Initial commit.
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / CTest / cmCTestScriptHandler.cxx
blob01bc2ef28ac55656760b842d7d65bcd97c7eb161
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCTestScriptHandler.cxx,v $
5 Language: C++
6 Date: $Date: 2008/01/23 15:28:01 $
7 Version: $Revision: 1.43 $
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 if(result == cmsysProcess_State_Exited)
279 retVal = cmsysProcess_GetExitValue(cp);
281 else
283 abort();
285 return retVal;
288 void cmCTestScriptHandler::CreateCMake()
290 // create a cmake instance to read the configuration script
291 if (this->CMake)
293 delete this->CMake;
294 delete this->GlobalGenerator;
295 delete this->LocalGenerator;
297 this->CMake = new cmake;
298 this->CMake->AddCMakePaths();
299 this->GlobalGenerator = new cmGlobalGenerator;
300 this->GlobalGenerator->SetCMakeInstance(this->CMake);
302 this->LocalGenerator = this->GlobalGenerator->CreateLocalGenerator();
303 this->LocalGenerator->SetGlobalGenerator(this->GlobalGenerator);
304 this->Makefile = this->LocalGenerator->GetMakefile();
306 // remove all cmake commands which are not scriptable, since they can't be
307 // used in ctest scripts
308 this->CMake->RemoveUnscriptableCommands();
310 // add any ctest specific commands, probably should have common superclass
311 // for ctest commands to clean this up. If a couple more commands are
312 // created with the same format lets do that - ken
313 this->AddCTestCommand(new cmCTestBuildCommand);
314 this->AddCTestCommand(new cmCTestConfigureCommand);
315 this->AddCTestCommand(new cmCTestCoverageCommand);
316 this->AddCTestCommand(new cmCTestEmptyBinaryDirectoryCommand);
317 this->AddCTestCommand(new cmCTestMemCheckCommand);
318 this->AddCTestCommand(new cmCTestReadCustomFilesCommand);
319 this->AddCTestCommand(new cmCTestRunScriptCommand);
320 this->AddCTestCommand(new cmCTestSleepCommand);
321 this->AddCTestCommand(new cmCTestStartCommand);
322 this->AddCTestCommand(new cmCTestSubmitCommand);
323 this->AddCTestCommand(new cmCTestTestCommand);
324 this->AddCTestCommand(new cmCTestUpdateCommand);
327 void cmCTestScriptHandler::GetCommandDocumentation(
328 std::vector<cmDocumentationEntry>& v) const
330 this->CMake->GetCommandDocumentation(v);
333 //----------------------------------------------------------------------
334 // this sets up some variables for the script to use, creates the required
335 // cmake instance and generators, and then reads in the script
336 int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
338 // if the argument has a , in it then it needs to be broken into the fist
339 // argument (which is the script) and the second argument which will be
340 // passed into the scripts as S_ARG
341 std::string script = total_script_arg;
342 std::string script_arg;
343 if (total_script_arg.find(",") != std::string::npos)
345 script = total_script_arg.substr(0,total_script_arg.find(","));
346 script_arg = total_script_arg.substr(total_script_arg.find(",")+1);
349 // make sure the file exists
350 if (!cmSystemTools::FileExists(script.c_str()))
352 cmSystemTools::Error("Cannot find file: ", script.c_str());
353 return 1;
356 // read in the list file to fill the cache
357 // create a cmake instance to read the configuration script
358 this->CreateCMake();
360 // set a variable with the path to the current script
361 this->Makefile->AddDefinition("CTEST_SCRIPT_DIRECTORY",
362 cmSystemTools::GetFilenamePath(script).c_str());
363 this->Makefile->AddDefinition("CTEST_SCRIPT_NAME",
364 cmSystemTools::GetFilenameName(script).c_str());
365 this->Makefile->AddDefinition("CTEST_EXECUTABLE_NAME",
366 this->CTest->GetCTestExecutable());
367 this->Makefile->AddDefinition("CMAKE_EXECUTABLE_NAME",
368 this->CTest->GetCMakeExecutable());
369 this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", true);
370 this->UpdateElapsedTime();
372 // add the script arg if defined
373 if (script_arg.size())
375 this->Makefile->AddDefinition("CTEST_SCRIPT_ARG", script_arg.c_str());
378 // always add a function blocker to update the elapsed time
379 cmCTestScriptFunctionBlocker *f = new cmCTestScriptFunctionBlocker();
380 f->CTestScriptHandler = this;
381 this->Makefile->AddFunctionBlocker(f);
383 // finally read in the script
384 if (!this->Makefile->ReadListFile(0, script.c_str()) ||
385 cmSystemTools::GetErrorOccuredFlag())
387 return 2;
390 return 0;
394 //----------------------------------------------------------------------
395 // extract variabels from the script to set ivars
396 int cmCTestScriptHandler::ExtractVariables()
398 // Temporary variables
399 const char* minInterval;
400 const char* contDuration;
402 this->SourceDir
403 = this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
404 this->BinaryDir
405 = this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY");
407 // add in translations for src and bin
408 cmSystemTools::AddKeepPath(this->SourceDir.c_str());
409 cmSystemTools::AddKeepPath(this->BinaryDir.c_str());
411 this->CTestCmd
412 = this->Makefile->GetSafeDefinition("CTEST_COMMAND");
413 this->CVSCheckOut
414 = this->Makefile->GetSafeDefinition("CTEST_CVS_CHECKOUT");
415 this->CTestRoot
416 = this->Makefile->GetSafeDefinition("CTEST_DASHBOARD_ROOT");
417 this->UpdateCmd
418 = this->Makefile->GetSafeDefinition("CTEST_UPDATE_COMMAND");
419 if ( this->UpdateCmd.empty() )
421 this->UpdateCmd
422 = this->Makefile->GetSafeDefinition("CTEST_CVS_COMMAND");
424 this->CTestEnv
425 = this->Makefile->GetSafeDefinition("CTEST_ENVIRONMENT");
426 this->InitCache
427 = this->Makefile->GetSafeDefinition("CTEST_INITIAL_CACHE");
428 this->CMakeCmd
429 = this->Makefile->GetSafeDefinition("CTEST_CMAKE_COMMAND");
430 this->CMOutFile
431 = this->Makefile->GetSafeDefinition("CTEST_CMAKE_OUTPUT_FILE_NAME");
433 this->Backup
434 = this->Makefile->IsOn("CTEST_BACKUP_AND_RESTORE");
435 this->EmptyBinDir
436 = this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY");
437 this->EmptyBinDirOnce
438 = this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY_ONCE");
440 minInterval
441 = this->Makefile->GetDefinition("CTEST_CONTINUOUS_MINIMUM_INTERVAL");
442 contDuration
443 = this->Makefile->GetDefinition("CTEST_CONTINUOUS_DURATION");
445 char updateVar[40];
446 int i;
447 for (i = 1; i < 10; ++i)
449 sprintf(updateVar,"CTEST_EXTRA_UPDATES_%i",i);
450 const char *updateVal = this->Makefile->GetDefinition(updateVar);
451 if ( updateVal )
453 if ( this->UpdateCmd.empty() )
455 cmSystemTools::Error(updateVar,
456 " specified without specifying CTEST_CVS_COMMAND.");
457 return 12;
459 this->ExtraUpdates.push_back(updateVal);
463 // in order to backup and restore we also must have the cvs root
464 if (this->Backup && this->CVSCheckOut.empty())
466 cmSystemTools::Error(
467 "Backup was requested without specifying CTEST_CVS_CHECKOUT.");
468 return 3;
471 // make sure the required info is here
472 if (this->SourceDir.empty() ||
473 this->BinaryDir.empty() ||
474 this->CTestCmd.empty())
476 std::string msg = "CTEST_SOURCE_DIRECTORY = ";
477 msg += (!this->SourceDir.empty()) ? this->SourceDir.c_str() : "(Null)";
478 msg += "\nCTEST_BINARY_DIRECTORY = ";
479 msg += (!this->BinaryDir.empty()) ? this->BinaryDir.c_str() : "(Null)";
480 msg += "\nCTEST_COMMAND = ";
481 msg += (!this->CTestCmd.empty()) ? this->CTestCmd.c_str() : "(Null)";
482 cmSystemTools::Error(
483 "Some required settings in the configuration file were missing:\n",
484 msg.c_str());
485 return 4;
488 // if the dashboard root isn't specified then we can compute it from the
489 // this->SourceDir
490 if (this->CTestRoot.empty() )
492 this->CTestRoot = cmSystemTools::GetFilenamePath(this->SourceDir).c_str();
495 // the script may override the minimum continuous interval
496 if (minInterval)
498 this->MinimumInterval = 60 * atof(minInterval);
500 if (contDuration)
502 this->ContinuousDuration = 60.0 * atof(contDuration);
506 this->UpdateElapsedTime();
508 return 0;
511 //----------------------------------------------------------------------
512 void cmCTestScriptHandler::SleepInSeconds(unsigned int secondsToWait)
514 #if defined(_WIN32)
515 Sleep(1000*secondsToWait);
516 #else
517 sleep(secondsToWait);
518 #endif
521 //----------------------------------------------------------------------
522 // run a specific script
523 int cmCTestScriptHandler::RunConfigurationScript
524 (const std::string& total_script_arg, bool pscope)
526 int result;
528 this->ScriptStartTime =
529 cmSystemTools::GetTime();
531 // read in the script
532 if (pscope)
534 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
535 "Reading Script: " << total_script_arg << std::endl);
536 result = this->ReadInScript(total_script_arg);
538 else
540 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
541 "Executing Script: " << total_script_arg << std::endl);
542 result = this->ExecuteScript(total_script_arg);
544 if (result)
546 return result;
549 // only run the curent script if we should
550 if (this->Makefile && this->Makefile->IsOn("CTEST_RUN_CURRENT_SCRIPT"))
552 return this->RunCurrentScript();
554 return result;
557 //----------------------------------------------------------------------
558 int cmCTestScriptHandler::RunCurrentScript()
560 int result;
562 // do not run twice
563 this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", false);
565 // no popup widows
566 cmSystemTools::SetRunCommandHideConsole(true);
568 // extract the vars from the cache and store in ivars
569 result = this->ExtractVariables();
570 if (result)
572 return result;
575 // set any environment variables
576 if (!this->CTestEnv.empty())
578 std::vector<std::string> envArgs;
579 cmSystemTools::ExpandListArgument(this->CTestEnv.c_str(),envArgs);
580 // for each variable/argument do a putenv
581 for (unsigned i = 0; i < envArgs.size(); ++i)
583 cmSystemTools::PutEnv(envArgs[i].c_str());
587 // now that we have done most of the error checking finally run the
588 // dashboard, we may be asked to repeatedly run this dashboard, such as
589 // for a continuous, do we ned to run it more than once?
590 if ( this->ContinuousDuration >= 0 )
592 this->UpdateElapsedTime();
593 double ending_time = cmSystemTools::GetTime() + this->ContinuousDuration;
594 if (this->EmptyBinDirOnce)
596 this->EmptyBinDir = true;
600 double interval = cmSystemTools::GetTime();
601 result = this->RunConfigurationDashboard();
602 interval = cmSystemTools::GetTime() - interval;
603 if (interval < this->MinimumInterval)
605 this->SleepInSeconds(
606 static_cast<unsigned int>(this->MinimumInterval - interval));
608 if (this->EmptyBinDirOnce)
610 this->EmptyBinDir = false;
613 while (cmSystemTools::GetTime() < ending_time);
615 // otherwise just run it once
616 else
618 result = this->RunConfigurationDashboard();
621 return result;
624 //----------------------------------------------------------------------
625 int cmCTestScriptHandler::CheckOutSourceDir()
627 std::string command;
628 std::string output;
629 int retVal;
630 bool res;
632 if (!cmSystemTools::FileExists(this->SourceDir.c_str()) &&
633 !this->CVSCheckOut.empty())
635 // we must now checkout the src dir
636 output = "";
637 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
638 "Run cvs: " << this->CVSCheckOut << std::endl);
639 res = cmSystemTools::RunSingleCommand(this->CVSCheckOut.c_str(), &output,
640 &retVal, this->CTestRoot.c_str(), this->HandlerVerbose,
641 0 /*this->TimeOut*/);
642 if (!res || retVal != 0)
644 cmSystemTools::Error("Unable to perform cvs checkout:\n",
645 output.c_str());
646 return 6;
649 return 0;
652 //----------------------------------------------------------------------
653 int cmCTestScriptHandler::BackupDirectories()
655 int retVal;
657 // compute the backup names
658 this->BackupSourceDir = this->SourceDir;
659 this->BackupSourceDir += "_CMakeBackup";
660 this->BackupBinaryDir = this->BinaryDir;
661 this->BackupBinaryDir += "_CMakeBackup";
663 // backup the binary and src directories if requested
664 if (this->Backup)
666 // if for some reason those directories exist then first delete them
667 if (cmSystemTools::FileExists(this->BackupSourceDir.c_str()))
669 cmSystemTools::RemoveADirectory(this->BackupSourceDir.c_str());
671 if (cmSystemTools::FileExists(this->BackupBinaryDir.c_str()))
673 cmSystemTools::RemoveADirectory(this->BackupBinaryDir.c_str());
676 // first rename the src and binary directories
677 rename(this->SourceDir.c_str(), this->BackupSourceDir.c_str());
678 rename(this->BinaryDir.c_str(), this->BackupBinaryDir.c_str());
680 // we must now checkout the src dir
681 retVal = this->CheckOutSourceDir();
682 if (retVal)
684 this->RestoreBackupDirectories();
685 return retVal;
689 return 0;
693 //----------------------------------------------------------------------
694 int cmCTestScriptHandler::PerformExtraUpdates()
696 std::string command;
697 std::string output;
698 int retVal;
699 bool res;
701 // do an initial cvs update as required
702 command = this->UpdateCmd;
703 std::vector<cmStdString>::iterator it;
704 for (it = this->ExtraUpdates.begin();
705 it != this->ExtraUpdates.end();
706 ++ it )
708 std::vector<std::string> cvsArgs;
709 cmSystemTools::ExpandListArgument(it->c_str(),cvsArgs);
710 if (cvsArgs.size() == 2)
712 std::string fullCommand = command;
713 fullCommand += " update ";
714 fullCommand += cvsArgs[1];
715 output = "";
716 retVal = 0;
717 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run Update: "
718 << fullCommand.c_str() << std::endl);
719 res = cmSystemTools::RunSingleCommand(fullCommand.c_str(), &output,
720 &retVal, cvsArgs[0].c_str(),
721 this->HandlerVerbose, 0 /*this->TimeOut*/);
722 if (!res || retVal != 0)
724 cmSystemTools::Error("Unable to perform extra updates:\n",
725 it->c_str(), "\nWith output:\n",
726 output.c_str());
727 return 0;
731 return 0;
735 //----------------------------------------------------------------------
736 // run a single dashboard entry
737 int cmCTestScriptHandler::RunConfigurationDashboard()
739 // local variables
740 std::string command;
741 std::string output;
742 int retVal;
743 bool res;
745 // make sure the src directory is there, if it isn't then we might be able
746 // to check it out from cvs
747 retVal = this->CheckOutSourceDir();
748 if (retVal)
750 return retVal;
753 // backup the dirs if requested
754 retVal = this->BackupDirectories();
755 if (retVal)
757 return retVal;
760 // clear the binary directory?
761 if (this->EmptyBinDir)
763 if ( !cmCTestScriptHandler::EmptyBinaryDirectory(
764 this->BinaryDir.c_str()) )
766 cmCTestLog(this->CTest, ERROR_MESSAGE,
767 "Problem removing the binary directory" << std::endl);
771 // make sure the binary directory exists if it isn't the srcdir
772 if (!cmSystemTools::FileExists(this->BinaryDir.c_str()) &&
773 this->SourceDir != this->BinaryDir)
775 if (!cmSystemTools::MakeDirectory(this->BinaryDir.c_str()))
777 cmSystemTools::Error("Unable to create the binary directory:\n",
778 this->BinaryDir.c_str());
779 this->RestoreBackupDirectories();
780 return 7;
784 // if the binary directory and the source directory are the same,
785 // and we are starting with an empty binary directory, then that means
786 // we must check out the source tree
787 if (this->EmptyBinDir && this->SourceDir == this->BinaryDir)
789 // make sure we have the required info
790 if (this->CVSCheckOut.empty())
792 cmSystemTools::Error("You have specified the source and binary "
793 "directories to be the same (an in source build). You have also "
794 "specified that the binary directory is to be erased. This means "
795 "that the source will have to be checked out from CVS. But you have "
796 "not specified CTEST_CVS_CHECKOUT");
797 return 8;
800 // we must now checkout the src dir
801 retVal = this->CheckOutSourceDir();
802 if (retVal)
804 this->RestoreBackupDirectories();
805 return retVal;
809 // backup the dirs if requested
810 retVal = this->PerformExtraUpdates();
811 if (retVal)
813 return retVal;
816 // put the initial cache into the bin dir
817 if (!this->InitCache.empty())
819 std::string cacheFile = this->BinaryDir;
820 cacheFile += "/CMakeCache.txt";
821 cmGeneratedFileStream fout(cacheFile.c_str());
822 if(!fout)
824 this->RestoreBackupDirectories();
825 return 9;
828 fout.write(this->InitCache.c_str(), this->InitCache.size());
830 // Make sure the operating system has finished writing the file
831 // before closing it. This will ensure the file is finished before
832 // the check below.
833 fout.flush();
834 fout.close();
837 // do an initial cmake to setup the DartConfig file
838 int cmakeFailed = 0;
839 std::string cmakeFailedOuput;
840 if (!this->CMakeCmd.empty())
842 command = this->CMakeCmd;
843 command += " \"";
844 command += this->SourceDir;
845 output = "";
846 command += "\"";
847 retVal = 0;
848 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run cmake command: "
849 << command.c_str() << std::endl);
850 res = cmSystemTools::RunSingleCommand(command.c_str(), &output,
851 &retVal, this->BinaryDir.c_str(),
852 this->HandlerVerbose, 0 /*this->TimeOut*/);
854 if ( !this->CMOutFile.empty() )
856 std::string cmakeOutputFile = this->CMOutFile;
857 if ( !cmSystemTools::FileIsFullPath(cmakeOutputFile.c_str()) )
859 cmakeOutputFile = this->BinaryDir + "/" + cmakeOutputFile;
862 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
863 "Write CMake output to file: " << cmakeOutputFile.c_str()
864 << std::endl);
865 cmGeneratedFileStream fout(cmakeOutputFile.c_str());
866 if ( fout )
868 fout << output.c_str();
870 else
872 cmCTestLog(this->CTest, ERROR_MESSAGE,
873 "Cannot open CMake output file: "
874 << cmakeOutputFile.c_str() << " for writing" << std::endl);
877 if (!res || retVal != 0)
879 // even if this fails continue to the next step
880 cmakeFailed = 1;
881 cmakeFailedOuput = output;
885 // run ctest, it may be more than one command in here
886 std::vector<std::string> ctestCommands;
887 cmSystemTools::ExpandListArgument(this->CTestCmd,ctestCommands);
888 // for each variable/argument do a putenv
889 for (unsigned i = 0; i < ctestCommands.size(); ++i)
891 command = ctestCommands[i];
892 output = "";
893 retVal = 0;
894 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run ctest command: "
895 << command.c_str() << std::endl);
896 res = cmSystemTools::RunSingleCommand(command.c_str(), &output,
897 &retVal, this->BinaryDir.c_str(), this->HandlerVerbose,
898 0 /*this->TimeOut*/);
900 // did something critical fail in ctest
901 if (!res || cmakeFailed ||
902 retVal & cmCTest::BUILD_ERRORS)
904 this->RestoreBackupDirectories();
905 if (cmakeFailed)
907 cmCTestLog(this->CTest, ERROR_MESSAGE,
908 "Unable to run cmake:" << std::endl
909 << cmakeFailedOuput.c_str() << std::endl);
910 return 10;
912 cmCTestLog(this->CTest, ERROR_MESSAGE,
913 "Unable to run ctest:" << std::endl
914 << output.c_str() << std::endl);
915 if (!res)
917 return 11;
919 return retVal * 100;
923 // if all was succesful, delete the backup dirs to free up disk space
924 if (this->Backup)
926 cmSystemTools::RemoveADirectory(this->BackupSourceDir.c_str());
927 cmSystemTools::RemoveADirectory(this->BackupBinaryDir.c_str());
930 return 0;
934 //-------------------------------------------------------------------------
935 void cmCTestScriptHandler::RestoreBackupDirectories()
937 // if we backed up the dirs and the build failed, then restore
938 // the backed up dirs
939 if (this->Backup)
941 // if for some reason those directories exist then first delete them
942 if (cmSystemTools::FileExists(this->SourceDir.c_str()))
944 cmSystemTools::RemoveADirectory(this->SourceDir.c_str());
946 if (cmSystemTools::FileExists(this->BinaryDir.c_str()))
948 cmSystemTools::RemoveADirectory(this->BinaryDir.c_str());
950 // rename the src and binary directories
951 rename(this->BackupSourceDir.c_str(), this->SourceDir.c_str());
952 rename(this->BackupBinaryDir.c_str(), this->BinaryDir.c_str());
956 bool cmCTestScriptHandler::RunScript(cmCTest* ctest, const char *sname,
957 bool InProcess)
959 cmCTestScriptHandler* sh = new cmCTestScriptHandler();
960 sh->SetCTestInstance(ctest);
961 sh->AddConfigurationScript(sname,InProcess);
962 sh->ProcessHandler();
963 delete sh;
964 return true;
967 bool cmCTestScriptHandler::EmptyBinaryDirectory(const char *sname)
969 // try to avoid deleting root
970 if (!sname || strlen(sname) < 2)
972 return false;
975 // try to avoid deleting directories that we shouldn't
976 std::string check = sname;
977 check += "/CMakeCache.txt";
978 if(cmSystemTools::FileExists(check.c_str()) &&
979 !cmSystemTools::RemoveADirectory(sname))
981 return false;
983 return true;
986 //-------------------------------------------------------------------------
987 double cmCTestScriptHandler::GetRemainingTimeAllowed()
989 if (!this->Makefile)
991 return 1.0e7;
994 const char *timelimitS
995 = this->Makefile->GetDefinition("CTEST_TIME_LIMIT");
997 if (!timelimitS)
999 return 1.0e7;
1002 double timelimit = atof(timelimitS);
1004 return timelimit - cmSystemTools::GetTime() + this->ScriptStartTime;