Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / CTest / cmCTestScriptHandler.cxx
blob51e4ac5945b8bf9efff74cb94fd8e4c75f3b5dd2
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCTestScriptHandler.cxx,v $
5 Language: C++
6 Date: $Date: 2009-03-04 16:24:57 $
7 Version: $Revision: 1.47 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
18 #include "cmCTestScriptHandler.h"
20 #include "cmCTest.h"
21 #include "cmake.h"
22 #include "cmFunctionBlocker.h"
23 #include "cmMakefile.h"
24 #include "cmLocalGenerator.h"
25 #include "cmGlobalGenerator.h"
26 #include "cmGeneratedFileStream.h"
28 //#include <cmsys/RegularExpression.hxx>
29 #include <cmsys/Process.h>
31 // used for sleep
32 #ifdef _WIN32
33 #include "windows.h"
34 #endif
36 #include <stdlib.h>
37 #include <time.h>
38 #include <math.h>
39 #include <float.h>
41 // needed for sleep
42 #if !defined(_WIN32)
43 # include <unistd.h>
44 #endif
46 #include "cmCTestBuildCommand.h"
47 #include "cmCTestConfigureCommand.h"
48 #include "cmCTestCoverageCommand.h"
49 #include "cmCTestEmptyBinaryDirectoryCommand.h"
50 #include "cmCTestMemCheckCommand.h"
51 #include "cmCTestReadCustomFilesCommand.h"
52 #include "cmCTestRunScriptCommand.h"
53 #include "cmCTestSleepCommand.h"
54 #include "cmCTestStartCommand.h"
55 #include "cmCTestSubmitCommand.h"
56 #include "cmCTestTestCommand.h"
57 #include "cmCTestUpdateCommand.h"
59 #define CTEST_INITIAL_CMAKE_OUTPUT_FILE_NAME "CTestInitialCMakeOutput.log"
61 // used to keep elapsed time up to date
62 class cmCTestScriptFunctionBlocker : public cmFunctionBlocker
64 public:
65 cmCTestScriptFunctionBlocker() {}
66 virtual ~cmCTestScriptFunctionBlocker() {}
67 virtual bool IsFunctionBlocked(const cmListFileFunction& lff,
68 cmMakefile &mf,
69 cmExecutionStatus &);
70 //virtual bool ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf);
71 //virtual void ScopeEnded(cmMakefile &mf);
73 cmCTestScriptHandler* CTestScriptHandler;
76 // simply update the time and don't block anything
77 bool cmCTestScriptFunctionBlocker::
78 IsFunctionBlocked(const cmListFileFunction& , cmMakefile &,
79 cmExecutionStatus &)
81 this->CTestScriptHandler->UpdateElapsedTime();
82 return false;
85 //----------------------------------------------------------------------
86 cmCTestScriptHandler::cmCTestScriptHandler()
88 this->Backup = false;
89 this->EmptyBinDir = false;
90 this->EmptyBinDirOnce = false;
91 this->Makefile = 0;
92 this->LocalGenerator = 0;
93 this->CMake = 0;
94 this->GlobalGenerator = 0;
96 this->ScriptStartTime = 0;
98 // the *60 is becuase the settings are in minutes but GetTime is seconds
99 this->MinimumInterval = 30*60;
100 this->ContinuousDuration = -1;
103 //----------------------------------------------------------------------
104 void cmCTestScriptHandler::Initialize()
106 this->Superclass::Initialize();
107 this->Backup = false;
108 this->EmptyBinDir = false;
109 this->EmptyBinDirOnce = false;
111 this->SourceDir = "";
112 this->BinaryDir = "";
113 this->BackupSourceDir = "";
114 this->BackupBinaryDir = "";
115 this->CTestRoot = "";
116 this->CVSCheckOut = "";
117 this->CTestCmd = "";
118 this->UpdateCmd = "";
119 this->CTestEnv = "";
120 this->InitCache = "";
121 this->CMakeCmd = "";
122 this->CMOutFile = "";
123 this->ExtraUpdates.clear();
125 this->MinimumInterval = 20*60;
126 this->ContinuousDuration = -1;
128 // what time in seconds did this script start running
129 this->ScriptStartTime = 0;
131 this->Makefile = 0;
132 if (this->LocalGenerator)
134 delete this->LocalGenerator;
136 this->LocalGenerator = 0;
137 if (this->GlobalGenerator)
139 delete this->GlobalGenerator;
141 this->GlobalGenerator = 0;
142 if (this->CMake)
144 delete this->CMake;
148 //----------------------------------------------------------------------
149 cmCTestScriptHandler::~cmCTestScriptHandler()
151 // local generator owns the makefile
152 this->Makefile = 0;
153 if (this->LocalGenerator)
155 delete this->LocalGenerator;
157 this->LocalGenerator = 0;
158 if (this->GlobalGenerator)
160 delete this->GlobalGenerator;
162 this->GlobalGenerator = 0;
163 if (this->CMake)
165 delete this->CMake;
170 //----------------------------------------------------------------------
171 // just adds an argument to the vector
172 void cmCTestScriptHandler::AddConfigurationScript(const char *script,
173 bool pscope)
175 this->ConfigurationScripts.push_back(script);
176 this->ScriptProcessScope.push_back(pscope);
180 //----------------------------------------------------------------------
181 // the generic entry point for handling scripts, this routine will run all
182 // the scripts provides a -S arguments
183 int cmCTestScriptHandler::ProcessHandler()
185 int res = 0;
186 for (size_t i=0; i < this->ConfigurationScripts.size(); ++i)
188 // for each script run it
189 res += this->RunConfigurationScript
190 (cmSystemTools::CollapseFullPath(this->ConfigurationScripts[i].c_str()),
191 this->ScriptProcessScope[i]);
193 if ( res )
195 return -1;
197 return 0;
200 void cmCTestScriptHandler::UpdateElapsedTime()
202 if (this->LocalGenerator)
204 // set the current elapsed time
205 char timeString[20];
206 int itime = static_cast<unsigned int>(cmSystemTools::GetTime()
207 - this->ScriptStartTime);
208 sprintf(timeString,"%i",itime);
209 this->LocalGenerator->GetMakefile()->AddDefinition("CTEST_ELAPSED_TIME",
210 timeString);
214 //----------------------------------------------------------------------
215 void cmCTestScriptHandler::AddCTestCommand(cmCTestCommand* command)
217 cmCTestCommand* newCom = command;
218 newCom->CTest = this->CTest;
219 newCom->CTestScriptHandler = this;
220 this->CMake->AddCommand(newCom);
223 int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
225 // execute the script passing in the arguments to the script as well as the
226 // arguments from this invocation of cmake
227 std::vector<const char*> argv;
228 argv.push_back(this->CTest->GetCTestExecutable());
229 argv.push_back("-SR");
230 argv.push_back(total_script_arg.c_str());
232 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
233 "Executable for CTest is: " <<
234 this->CTest->GetCTestExecutable() << "\n");
236 // now pass through all the other arguments
237 std::vector<cmStdString> &initArgs =
238 this->CTest->GetInitialCommandLineArguments();
239 for(size_t i=1; i < initArgs.size(); ++i)
241 argv.push_back(initArgs[i].c_str());
243 argv.push_back(0);
245 // Now create process object
246 cmsysProcess* cp = cmsysProcess_New();
247 cmsysProcess_SetCommand(cp, &*argv.begin());
248 //cmsysProcess_SetWorkingDirectory(cp, dir);
249 cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
250 //cmsysProcess_SetTimeout(cp, timeout);
251 cmsysProcess_Execute(cp);
253 std::vector<char> out;
254 std::vector<char> err;
255 std::string line;
256 int pipe = cmSystemTools::WaitForLine(cp, line, 100.0, out, err);
257 while(pipe != cmsysProcess_Pipe_None)
259 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Output: "
260 << line << "\n");
261 if(pipe == cmsysProcess_Pipe_STDERR)
263 cmCTestLog(this->CTest, ERROR_MESSAGE, line << "\n");
265 else if(pipe == cmsysProcess_Pipe_STDOUT)
267 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n");
269 pipe = cmSystemTools::WaitForLine(cp, line, 100, out, err);
272 // Properly handle output of the build command
273 cmsysProcess_WaitForExit(cp, 0);
274 int result = cmsysProcess_GetState(cp);
276 int retVal = 0;
277 bool failed = false;
278 if(result == cmsysProcess_State_Exited)
280 retVal = cmsysProcess_GetExitValue(cp);
282 else if(result == cmsysProcess_State_Exception)
284 retVal = cmsysProcess_GetExitException(cp);
285 cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was an exception: "
286 << cmsysProcess_GetExceptionString(cp) << " " <<
287 retVal << std::endl);
288 failed = true;
290 else if(result == cmsysProcess_State_Expired)
292 cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was a timeout"
293 << std::endl);
294 failed = true;
296 else if(result == cmsysProcess_State_Error)
298 cmCTestLog(this->CTest, ERROR_MESSAGE, "\tError executing ctest: "
299 << cmsysProcess_GetErrorString(cp) << std::endl);
300 failed = true;
302 if(failed)
304 cmOStringStream message;
305 message << "Error running command: [";
306 message << result << "] ";
307 for(std::vector<const char*>::iterator i = argv.begin();
308 i != argv.end(); ++i)
310 if(*i)
312 message << *i << " ";
315 cmCTestLog(this->CTest, ERROR_MESSAGE,
316 message.str() << argv[0] << std::endl);
317 return -1;
319 return retVal;
322 void cmCTestScriptHandler::CreateCMake()
324 // create a cmake instance to read the configuration script
325 if (this->CMake)
327 delete this->CMake;
328 delete this->GlobalGenerator;
329 delete this->LocalGenerator;
331 this->CMake = new cmake;
332 this->CMake->AddCMakePaths();
333 this->GlobalGenerator = new cmGlobalGenerator;
334 this->GlobalGenerator->SetCMakeInstance(this->CMake);
336 this->LocalGenerator = this->GlobalGenerator->CreateLocalGenerator();
337 this->LocalGenerator->SetGlobalGenerator(this->GlobalGenerator);
338 this->Makefile = this->LocalGenerator->GetMakefile();
340 // remove all cmake commands which are not scriptable, since they can't be
341 // used in ctest scripts
342 this->CMake->RemoveUnscriptableCommands();
344 // add any ctest specific commands, probably should have common superclass
345 // for ctest commands to clean this up. If a couple more commands are
346 // created with the same format lets do that - ken
347 this->AddCTestCommand(new cmCTestBuildCommand);
348 this->AddCTestCommand(new cmCTestConfigureCommand);
349 this->AddCTestCommand(new cmCTestCoverageCommand);
350 this->AddCTestCommand(new cmCTestEmptyBinaryDirectoryCommand);
351 this->AddCTestCommand(new cmCTestMemCheckCommand);
352 this->AddCTestCommand(new cmCTestReadCustomFilesCommand);
353 this->AddCTestCommand(new cmCTestRunScriptCommand);
354 this->AddCTestCommand(new cmCTestSleepCommand);
355 this->AddCTestCommand(new cmCTestStartCommand);
356 this->AddCTestCommand(new cmCTestSubmitCommand);
357 this->AddCTestCommand(new cmCTestTestCommand);
358 this->AddCTestCommand(new cmCTestUpdateCommand);
361 void cmCTestScriptHandler::GetCommandDocumentation(
362 std::vector<cmDocumentationEntry>& v) const
364 this->CMake->GetCommandDocumentation(v);
367 //----------------------------------------------------------------------
368 // this sets up some variables for the script to use, creates the required
369 // cmake instance and generators, and then reads in the script
370 int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
372 // Reset the error flag so that the script is read in no matter what
373 cmSystemTools::ResetErrorOccuredFlag();
375 // if the argument has a , in it then it needs to be broken into the fist
376 // argument (which is the script) and the second argument which will be
377 // passed into the scripts as S_ARG
378 std::string script = total_script_arg;
379 std::string script_arg;
380 if (total_script_arg.find(",") != std::string::npos)
382 script = total_script_arg.substr(0,total_script_arg.find(","));
383 script_arg = total_script_arg.substr(total_script_arg.find(",")+1);
385 // make sure the file exists
386 if (!cmSystemTools::FileExists(script.c_str()))
388 cmSystemTools::Error("Cannot find file: ", script.c_str());
389 return 1;
392 // read in the list file to fill the cache
393 // create a cmake instance to read the configuration script
394 this->CreateCMake();
396 // set a variable with the path to the current script
397 this->Makefile->AddDefinition("CTEST_SCRIPT_DIRECTORY",
398 cmSystemTools::GetFilenamePath(script).c_str());
399 this->Makefile->AddDefinition("CTEST_SCRIPT_NAME",
400 cmSystemTools::GetFilenameName(script).c_str());
401 this->Makefile->AddDefinition("CTEST_EXECUTABLE_NAME",
402 this->CTest->GetCTestExecutable());
403 this->Makefile->AddDefinition("CMAKE_EXECUTABLE_NAME",
404 this->CTest->GetCMakeExecutable());
405 this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", true);
406 this->UpdateElapsedTime();
408 // add the script arg if defined
409 if (script_arg.size())
411 this->Makefile->AddDefinition("CTEST_SCRIPT_ARG", script_arg.c_str());
414 // always add a function blocker to update the elapsed time
415 cmCTestScriptFunctionBlocker *f = new cmCTestScriptFunctionBlocker();
416 f->CTestScriptHandler = this;
417 this->Makefile->AddFunctionBlocker(f);
420 /* Execute CMakeDetermineSystem and CMakeSystemSpecificInformation, so
421 that variables like CMAKE_SYSTEM and also the search paths for libraries,
422 header and executables are set correctly and can be used. Makes new-style
423 ctest scripting easier. */
424 std::string systemFile =
425 this->Makefile->GetModulesFile("CMakeDetermineSystem.cmake");
426 if (!this->Makefile->ReadListFile(0, systemFile.c_str()) ||
427 cmSystemTools::GetErrorOccuredFlag())
429 cmCTestLog(this->CTest, ERROR_MESSAGE, "Error in read:"
430 << systemFile.c_str() << "\n");
431 return 2;
434 systemFile =
435 this->Makefile->GetModulesFile("CMakeSystemSpecificInformation.cmake");
436 if (!this->Makefile->ReadListFile(0, systemFile.c_str()) ||
437 cmSystemTools::GetErrorOccuredFlag())
439 cmCTestLog(this->CTest, ERROR_MESSAGE, "Error in read:"
440 << systemFile.c_str() << "\n");
441 return 2;
444 // finally read in the script
445 if (!this->Makefile->ReadListFile(0, script.c_str()) ||
446 cmSystemTools::GetErrorOccuredFlag())
448 cmCTestLog(this->CTest, ERROR_MESSAGE, "Error in read script: "
449 << script.c_str()
450 << std::endl);
451 return 2;
454 return 0;
458 //----------------------------------------------------------------------
459 // extract variabels from the script to set ivars
460 int cmCTestScriptHandler::ExtractVariables()
462 // Temporary variables
463 const char* minInterval;
464 const char* contDuration;
466 this->SourceDir
467 = this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
468 this->BinaryDir
469 = this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY");
471 // add in translations for src and bin
472 cmSystemTools::AddKeepPath(this->SourceDir.c_str());
473 cmSystemTools::AddKeepPath(this->BinaryDir.c_str());
475 this->CTestCmd
476 = this->Makefile->GetSafeDefinition("CTEST_COMMAND");
477 this->CVSCheckOut
478 = this->Makefile->GetSafeDefinition("CTEST_CVS_CHECKOUT");
479 this->CTestRoot
480 = this->Makefile->GetSafeDefinition("CTEST_DASHBOARD_ROOT");
481 this->UpdateCmd
482 = this->Makefile->GetSafeDefinition("CTEST_UPDATE_COMMAND");
483 if ( this->UpdateCmd.empty() )
485 this->UpdateCmd
486 = this->Makefile->GetSafeDefinition("CTEST_CVS_COMMAND");
488 this->CTestEnv
489 = this->Makefile->GetSafeDefinition("CTEST_ENVIRONMENT");
490 this->InitCache
491 = this->Makefile->GetSafeDefinition("CTEST_INITIAL_CACHE");
492 this->CMakeCmd
493 = this->Makefile->GetSafeDefinition("CTEST_CMAKE_COMMAND");
494 this->CMOutFile
495 = this->Makefile->GetSafeDefinition("CTEST_CMAKE_OUTPUT_FILE_NAME");
497 this->Backup
498 = this->Makefile->IsOn("CTEST_BACKUP_AND_RESTORE");
499 this->EmptyBinDir
500 = this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY");
501 this->EmptyBinDirOnce
502 = this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY_ONCE");
504 minInterval
505 = this->Makefile->GetDefinition("CTEST_CONTINUOUS_MINIMUM_INTERVAL");
506 contDuration
507 = this->Makefile->GetDefinition("CTEST_CONTINUOUS_DURATION");
509 char updateVar[40];
510 int i;
511 for (i = 1; i < 10; ++i)
513 sprintf(updateVar,"CTEST_EXTRA_UPDATES_%i",i);
514 const char *updateVal = this->Makefile->GetDefinition(updateVar);
515 if ( updateVal )
517 if ( this->UpdateCmd.empty() )
519 cmSystemTools::Error(updateVar,
520 " specified without specifying CTEST_CVS_COMMAND.");
521 return 12;
523 this->ExtraUpdates.push_back(updateVal);
527 // in order to backup and restore we also must have the cvs root
528 if (this->Backup && this->CVSCheckOut.empty())
530 cmSystemTools::Error(
531 "Backup was requested without specifying CTEST_CVS_CHECKOUT.");
532 return 3;
535 // make sure the required info is here
536 if (this->SourceDir.empty() ||
537 this->BinaryDir.empty() ||
538 this->CTestCmd.empty())
540 std::string msg = "CTEST_SOURCE_DIRECTORY = ";
541 msg += (!this->SourceDir.empty()) ? this->SourceDir.c_str() : "(Null)";
542 msg += "\nCTEST_BINARY_DIRECTORY = ";
543 msg += (!this->BinaryDir.empty()) ? this->BinaryDir.c_str() : "(Null)";
544 msg += "\nCTEST_COMMAND = ";
545 msg += (!this->CTestCmd.empty()) ? this->CTestCmd.c_str() : "(Null)";
546 cmSystemTools::Error(
547 "Some required settings in the configuration file were missing:\n",
548 msg.c_str());
549 return 4;
552 // if the dashboard root isn't specified then we can compute it from the
553 // this->SourceDir
554 if (this->CTestRoot.empty() )
556 this->CTestRoot = cmSystemTools::GetFilenamePath(this->SourceDir).c_str();
559 // the script may override the minimum continuous interval
560 if (minInterval)
562 this->MinimumInterval = 60 * atof(minInterval);
564 if (contDuration)
566 this->ContinuousDuration = 60.0 * atof(contDuration);
570 this->UpdateElapsedTime();
572 return 0;
575 //----------------------------------------------------------------------
576 void cmCTestScriptHandler::SleepInSeconds(unsigned int secondsToWait)
578 #if defined(_WIN32)
579 Sleep(1000*secondsToWait);
580 #else
581 sleep(secondsToWait);
582 #endif
585 //----------------------------------------------------------------------
586 // run a specific script
587 int cmCTestScriptHandler::RunConfigurationScript
588 (const std::string& total_script_arg, bool pscope)
590 int result;
592 this->ScriptStartTime =
593 cmSystemTools::GetTime();
595 // read in the script
596 if (pscope)
598 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
599 "Reading Script: " << total_script_arg << std::endl);
600 result = this->ReadInScript(total_script_arg);
602 else
604 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
605 "Executing Script: " << total_script_arg << std::endl);
606 result = this->ExecuteScript(total_script_arg);
608 if (result)
610 return result;
613 // only run the curent script if we should
614 if (this->Makefile && this->Makefile->IsOn("CTEST_RUN_CURRENT_SCRIPT"))
616 return this->RunCurrentScript();
618 return result;
621 //----------------------------------------------------------------------
622 int cmCTestScriptHandler::RunCurrentScript()
624 int result;
626 // do not run twice
627 this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", false);
629 // no popup widows
630 cmSystemTools::SetRunCommandHideConsole(true);
632 // extract the vars from the cache and store in ivars
633 result = this->ExtractVariables();
634 if (result)
636 return result;
639 // set any environment variables
640 if (!this->CTestEnv.empty())
642 std::vector<std::string> envArgs;
643 cmSystemTools::ExpandListArgument(this->CTestEnv.c_str(),envArgs);
644 // for each variable/argument do a putenv
645 for (unsigned i = 0; i < envArgs.size(); ++i)
647 cmSystemTools::PutEnv(envArgs[i].c_str());
651 // now that we have done most of the error checking finally run the
652 // dashboard, we may be asked to repeatedly run this dashboard, such as
653 // for a continuous, do we ned to run it more than once?
654 if ( this->ContinuousDuration >= 0 )
656 this->UpdateElapsedTime();
657 double ending_time = cmSystemTools::GetTime() + this->ContinuousDuration;
658 if (this->EmptyBinDirOnce)
660 this->EmptyBinDir = true;
664 double interval = cmSystemTools::GetTime();
665 result = this->RunConfigurationDashboard();
666 interval = cmSystemTools::GetTime() - interval;
667 if (interval < this->MinimumInterval)
669 this->SleepInSeconds(
670 static_cast<unsigned int>(this->MinimumInterval - interval));
672 if (this->EmptyBinDirOnce)
674 this->EmptyBinDir = false;
677 while (cmSystemTools::GetTime() < ending_time);
679 // otherwise just run it once
680 else
682 result = this->RunConfigurationDashboard();
685 return result;
688 //----------------------------------------------------------------------
689 int cmCTestScriptHandler::CheckOutSourceDir()
691 std::string command;
692 std::string output;
693 int retVal;
694 bool res;
696 if (!cmSystemTools::FileExists(this->SourceDir.c_str()) &&
697 !this->CVSCheckOut.empty())
699 // we must now checkout the src dir
700 output = "";
701 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
702 "Run cvs: " << this->CVSCheckOut << std::endl);
703 res = cmSystemTools::RunSingleCommand(this->CVSCheckOut.c_str(), &output,
704 &retVal, this->CTestRoot.c_str(), this->HandlerVerbose,
705 0 /*this->TimeOut*/);
706 if (!res || retVal != 0)
708 cmSystemTools::Error("Unable to perform cvs checkout:\n",
709 output.c_str());
710 return 6;
713 return 0;
716 //----------------------------------------------------------------------
717 int cmCTestScriptHandler::BackupDirectories()
719 int retVal;
721 // compute the backup names
722 this->BackupSourceDir = this->SourceDir;
723 this->BackupSourceDir += "_CMakeBackup";
724 this->BackupBinaryDir = this->BinaryDir;
725 this->BackupBinaryDir += "_CMakeBackup";
727 // backup the binary and src directories if requested
728 if (this->Backup)
730 // if for some reason those directories exist then first delete them
731 if (cmSystemTools::FileExists(this->BackupSourceDir.c_str()))
733 cmSystemTools::RemoveADirectory(this->BackupSourceDir.c_str());
735 if (cmSystemTools::FileExists(this->BackupBinaryDir.c_str()))
737 cmSystemTools::RemoveADirectory(this->BackupBinaryDir.c_str());
740 // first rename the src and binary directories
741 rename(this->SourceDir.c_str(), this->BackupSourceDir.c_str());
742 rename(this->BinaryDir.c_str(), this->BackupBinaryDir.c_str());
744 // we must now checkout the src dir
745 retVal = this->CheckOutSourceDir();
746 if (retVal)
748 this->RestoreBackupDirectories();
749 return retVal;
753 return 0;
757 //----------------------------------------------------------------------
758 int cmCTestScriptHandler::PerformExtraUpdates()
760 std::string command;
761 std::string output;
762 int retVal;
763 bool res;
765 // do an initial cvs update as required
766 command = this->UpdateCmd;
767 std::vector<cmStdString>::iterator it;
768 for (it = this->ExtraUpdates.begin();
769 it != this->ExtraUpdates.end();
770 ++ it )
772 std::vector<std::string> cvsArgs;
773 cmSystemTools::ExpandListArgument(it->c_str(),cvsArgs);
774 if (cvsArgs.size() == 2)
776 std::string fullCommand = command;
777 fullCommand += " update ";
778 fullCommand += cvsArgs[1];
779 output = "";
780 retVal = 0;
781 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run Update: "
782 << fullCommand.c_str() << std::endl);
783 res = cmSystemTools::RunSingleCommand(fullCommand.c_str(), &output,
784 &retVal, cvsArgs[0].c_str(),
785 this->HandlerVerbose, 0 /*this->TimeOut*/);
786 if (!res || retVal != 0)
788 cmSystemTools::Error("Unable to perform extra updates:\n",
789 it->c_str(), "\nWith output:\n",
790 output.c_str());
791 return 0;
795 return 0;
799 //----------------------------------------------------------------------
800 // run a single dashboard entry
801 int cmCTestScriptHandler::RunConfigurationDashboard()
803 // local variables
804 std::string command;
805 std::string output;
806 int retVal;
807 bool res;
809 // make sure the src directory is there, if it isn't then we might be able
810 // to check it out from cvs
811 retVal = this->CheckOutSourceDir();
812 if (retVal)
814 return retVal;
817 // backup the dirs if requested
818 retVal = this->BackupDirectories();
819 if (retVal)
821 return retVal;
824 // clear the binary directory?
825 if (this->EmptyBinDir)
827 if ( !cmCTestScriptHandler::EmptyBinaryDirectory(
828 this->BinaryDir.c_str()) )
830 cmCTestLog(this->CTest, ERROR_MESSAGE,
831 "Problem removing the binary directory" << std::endl);
835 // make sure the binary directory exists if it isn't the srcdir
836 if (!cmSystemTools::FileExists(this->BinaryDir.c_str()) &&
837 this->SourceDir != this->BinaryDir)
839 if (!cmSystemTools::MakeDirectory(this->BinaryDir.c_str()))
841 cmSystemTools::Error("Unable to create the binary directory:\n",
842 this->BinaryDir.c_str());
843 this->RestoreBackupDirectories();
844 return 7;
848 // if the binary directory and the source directory are the same,
849 // and we are starting with an empty binary directory, then that means
850 // we must check out the source tree
851 if (this->EmptyBinDir && this->SourceDir == this->BinaryDir)
853 // make sure we have the required info
854 if (this->CVSCheckOut.empty())
856 cmSystemTools::Error("You have specified the source and binary "
857 "directories to be the same (an in source build). You have also "
858 "specified that the binary directory is to be erased. This means "
859 "that the source will have to be checked out from CVS. But you have "
860 "not specified CTEST_CVS_CHECKOUT");
861 return 8;
864 // we must now checkout the src dir
865 retVal = this->CheckOutSourceDir();
866 if (retVal)
868 this->RestoreBackupDirectories();
869 return retVal;
873 // backup the dirs if requested
874 retVal = this->PerformExtraUpdates();
875 if (retVal)
877 return retVal;
880 // put the initial cache into the bin dir
881 if (!this->InitCache.empty())
883 std::string cacheFile = this->BinaryDir;
884 cacheFile += "/CMakeCache.txt";
885 cmGeneratedFileStream fout(cacheFile.c_str());
886 if(!fout)
888 this->RestoreBackupDirectories();
889 return 9;
892 fout.write(this->InitCache.c_str(), this->InitCache.size());
894 // Make sure the operating system has finished writing the file
895 // before closing it. This will ensure the file is finished before
896 // the check below.
897 fout.flush();
898 fout.close();
901 // do an initial cmake to setup the DartConfig file
902 int cmakeFailed = 0;
903 std::string cmakeFailedOuput;
904 if (!this->CMakeCmd.empty())
906 command = this->CMakeCmd;
907 command += " \"";
908 command += this->SourceDir;
909 output = "";
910 command += "\"";
911 retVal = 0;
912 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run cmake command: "
913 << command.c_str() << std::endl);
914 res = cmSystemTools::RunSingleCommand(command.c_str(), &output,
915 &retVal, this->BinaryDir.c_str(),
916 this->HandlerVerbose, 0 /*this->TimeOut*/);
918 if ( !this->CMOutFile.empty() )
920 std::string cmakeOutputFile = this->CMOutFile;
921 if ( !cmSystemTools::FileIsFullPath(cmakeOutputFile.c_str()) )
923 cmakeOutputFile = this->BinaryDir + "/" + cmakeOutputFile;
926 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
927 "Write CMake output to file: " << cmakeOutputFile.c_str()
928 << std::endl);
929 cmGeneratedFileStream fout(cmakeOutputFile.c_str());
930 if ( fout )
932 fout << output.c_str();
934 else
936 cmCTestLog(this->CTest, ERROR_MESSAGE,
937 "Cannot open CMake output file: "
938 << cmakeOutputFile.c_str() << " for writing" << std::endl);
941 if (!res || retVal != 0)
943 // even if this fails continue to the next step
944 cmakeFailed = 1;
945 cmakeFailedOuput = output;
949 // run ctest, it may be more than one command in here
950 std::vector<std::string> ctestCommands;
951 cmSystemTools::ExpandListArgument(this->CTestCmd,ctestCommands);
952 // for each variable/argument do a putenv
953 for (unsigned i = 0; i < ctestCommands.size(); ++i)
955 command = ctestCommands[i];
956 output = "";
957 retVal = 0;
958 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run ctest command: "
959 << command.c_str() << std::endl);
960 res = cmSystemTools::RunSingleCommand(command.c_str(), &output,
961 &retVal, this->BinaryDir.c_str(), this->HandlerVerbose,
962 0 /*this->TimeOut*/);
964 // did something critical fail in ctest
965 if (!res || cmakeFailed ||
966 retVal & cmCTest::BUILD_ERRORS)
968 this->RestoreBackupDirectories();
969 if (cmakeFailed)
971 cmCTestLog(this->CTest, ERROR_MESSAGE,
972 "Unable to run cmake:" << std::endl
973 << cmakeFailedOuput.c_str() << std::endl);
974 return 10;
976 cmCTestLog(this->CTest, ERROR_MESSAGE,
977 "Unable to run ctest:" << std::endl
978 << output.c_str() << std::endl);
979 if (!res)
981 return 11;
983 return retVal * 100;
987 // if all was succesful, delete the backup dirs to free up disk space
988 if (this->Backup)
990 cmSystemTools::RemoveADirectory(this->BackupSourceDir.c_str());
991 cmSystemTools::RemoveADirectory(this->BackupBinaryDir.c_str());
994 return 0;
998 //-------------------------------------------------------------------------
999 void cmCTestScriptHandler::RestoreBackupDirectories()
1001 // if we backed up the dirs and the build failed, then restore
1002 // the backed up dirs
1003 if (this->Backup)
1005 // if for some reason those directories exist then first delete them
1006 if (cmSystemTools::FileExists(this->SourceDir.c_str()))
1008 cmSystemTools::RemoveADirectory(this->SourceDir.c_str());
1010 if (cmSystemTools::FileExists(this->BinaryDir.c_str()))
1012 cmSystemTools::RemoveADirectory(this->BinaryDir.c_str());
1014 // rename the src and binary directories
1015 rename(this->BackupSourceDir.c_str(), this->SourceDir.c_str());
1016 rename(this->BackupBinaryDir.c_str(), this->BinaryDir.c_str());
1020 bool cmCTestScriptHandler::RunScript(cmCTest* ctest, const char *sname,
1021 bool InProcess)
1023 cmCTestScriptHandler* sh = new cmCTestScriptHandler();
1024 sh->SetCTestInstance(ctest);
1025 sh->AddConfigurationScript(sname,InProcess);
1026 sh->ProcessHandler();
1027 delete sh;
1028 return true;
1031 bool cmCTestScriptHandler::EmptyBinaryDirectory(const char *sname)
1033 // try to avoid deleting root
1034 if (!sname || strlen(sname) < 2)
1036 return false;
1039 // try to avoid deleting directories that we shouldn't
1040 std::string check = sname;
1041 check += "/CMakeCache.txt";
1042 if(cmSystemTools::FileExists(check.c_str()) &&
1043 !cmSystemTools::RemoveADirectory(sname))
1045 return false;
1047 return true;
1050 //-------------------------------------------------------------------------
1051 double cmCTestScriptHandler::GetRemainingTimeAllowed()
1053 if (!this->Makefile)
1055 return 1.0e7;
1058 const char *timelimitS
1059 = this->Makefile->GetDefinition("CTEST_TIME_LIMIT");
1061 if (!timelimitS)
1063 return 1.0e7;
1066 double timelimit = atof(timelimitS);
1068 return timelimit - cmSystemTools::GetTime() + this->ScriptStartTime;