1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCTestScriptHandler.cxx,v $
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"
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>
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
65 cmCTestScriptFunctionBlocker() {}
66 virtual ~cmCTestScriptFunctionBlocker() {}
67 virtual bool IsFunctionBlocked(const cmListFileFunction
& lff
,
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
&,
81 this->CTestScriptHandler
->UpdateElapsedTime();
85 //----------------------------------------------------------------------
86 cmCTestScriptHandler::cmCTestScriptHandler()
89 this->EmptyBinDir
= false;
90 this->EmptyBinDirOnce
= false;
92 this->LocalGenerator
= 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
= "";
118 this->UpdateCmd
= "";
120 this->InitCache
= "";
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;
132 if (this->LocalGenerator
)
134 delete this->LocalGenerator
;
136 this->LocalGenerator
= 0;
137 if (this->GlobalGenerator
)
139 delete this->GlobalGenerator
;
141 this->GlobalGenerator
= 0;
148 //----------------------------------------------------------------------
149 cmCTestScriptHandler::~cmCTestScriptHandler()
151 // local generator owns the makefile
153 if (this->LocalGenerator
)
155 delete this->LocalGenerator
;
157 this->LocalGenerator
= 0;
158 if (this->GlobalGenerator
)
160 delete this->GlobalGenerator
;
162 this->GlobalGenerator
= 0;
170 //----------------------------------------------------------------------
171 // just adds an argument to the vector
172 void cmCTestScriptHandler::AddConfigurationScript(const char *script
,
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()
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
]);
200 void cmCTestScriptHandler::UpdateElapsedTime()
202 if (this->LocalGenerator
)
204 // set the current elapsed time
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",
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());
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
;
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: "
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
);
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
);
290 else if(result
== cmsysProcess_State_Expired
)
292 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "\tThere was a timeout"
296 else if(result
== cmsysProcess_State_Error
)
298 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "\tError executing ctest: "
299 << cmsysProcess_GetErrorString(cp
) << std::endl
);
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
)
312 message
<< *i
<< " ";
315 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
316 message
.str() << argv
[0] << std::endl
);
322 void cmCTestScriptHandler::CreateCMake()
324 // create a cmake instance to read the configuration script
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());
392 // read in the list file to fill the cache
393 // create a cmake instance to read the configuration script
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");
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");
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: "
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
;
467 = this->Makefile
->GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
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());
476 = this->Makefile
->GetSafeDefinition("CTEST_COMMAND");
478 = this->Makefile
->GetSafeDefinition("CTEST_CVS_CHECKOUT");
480 = this->Makefile
->GetSafeDefinition("CTEST_DASHBOARD_ROOT");
482 = this->Makefile
->GetSafeDefinition("CTEST_UPDATE_COMMAND");
483 if ( this->UpdateCmd
.empty() )
486 = this->Makefile
->GetSafeDefinition("CTEST_CVS_COMMAND");
489 = this->Makefile
->GetSafeDefinition("CTEST_ENVIRONMENT");
491 = this->Makefile
->GetSafeDefinition("CTEST_INITIAL_CACHE");
493 = this->Makefile
->GetSafeDefinition("CTEST_CMAKE_COMMAND");
495 = this->Makefile
->GetSafeDefinition("CTEST_CMAKE_OUTPUT_FILE_NAME");
498 = this->Makefile
->IsOn("CTEST_BACKUP_AND_RESTORE");
500 = this->Makefile
->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY");
501 this->EmptyBinDirOnce
502 = this->Makefile
->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY_ONCE");
505 = this->Makefile
->GetDefinition("CTEST_CONTINUOUS_MINIMUM_INTERVAL");
507 = this->Makefile
->GetDefinition("CTEST_CONTINUOUS_DURATION");
511 for (i
= 1; i
< 10; ++i
)
513 sprintf(updateVar
,"CTEST_EXTRA_UPDATES_%i",i
);
514 const char *updateVal
= this->Makefile
->GetDefinition(updateVar
);
517 if ( this->UpdateCmd
.empty() )
519 cmSystemTools::Error(updateVar
,
520 " specified without specifying CTEST_CVS_COMMAND.");
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.");
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",
552 // if the dashboard root isn't specified then we can compute it from the
554 if (this->CTestRoot
.empty() )
556 this->CTestRoot
= cmSystemTools::GetFilenamePath(this->SourceDir
).c_str();
559 // the script may override the minimum continuous interval
562 this->MinimumInterval
= 60 * atof(minInterval
);
566 this->ContinuousDuration
= 60.0 * atof(contDuration
);
570 this->UpdateElapsedTime();
575 //----------------------------------------------------------------------
576 void cmCTestScriptHandler::SleepInSeconds(unsigned int secondsToWait
)
579 Sleep(1000*secondsToWait
);
581 sleep(secondsToWait
);
585 //----------------------------------------------------------------------
586 // run a specific script
587 int cmCTestScriptHandler::RunConfigurationScript
588 (const std::string
& total_script_arg
, bool pscope
)
592 this->ScriptStartTime
=
593 cmSystemTools::GetTime();
595 // read in the script
598 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
599 "Reading Script: " << total_script_arg
<< std::endl
);
600 result
= this->ReadInScript(total_script_arg
);
604 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
605 "Executing Script: " << total_script_arg
<< std::endl
);
606 result
= this->ExecuteScript(total_script_arg
);
613 // only run the curent script if we should
614 if (this->Makefile
&& this->Makefile
->IsOn("CTEST_RUN_CURRENT_SCRIPT"))
616 return this->RunCurrentScript();
621 //----------------------------------------------------------------------
622 int cmCTestScriptHandler::RunCurrentScript()
627 this->Makefile
->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", false);
630 cmSystemTools::SetRunCommandHideConsole(true);
632 // extract the vars from the cache and store in ivars
633 result
= this->ExtractVariables();
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
682 result
= this->RunConfigurationDashboard();
688 //----------------------------------------------------------------------
689 int cmCTestScriptHandler::CheckOutSourceDir()
696 if (!cmSystemTools::FileExists(this->SourceDir
.c_str()) &&
697 !this->CVSCheckOut
.empty())
699 // we must now checkout the src dir
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",
716 //----------------------------------------------------------------------
717 int cmCTestScriptHandler::BackupDirectories()
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
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();
748 this->RestoreBackupDirectories();
757 //----------------------------------------------------------------------
758 int cmCTestScriptHandler::PerformExtraUpdates()
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();
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];
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",
799 //----------------------------------------------------------------------
800 // run a single dashboard entry
801 int cmCTestScriptHandler::RunConfigurationDashboard()
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();
817 // backup the dirs if requested
818 retVal
= this->BackupDirectories();
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();
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");
864 // we must now checkout the src dir
865 retVal
= this->CheckOutSourceDir();
868 this->RestoreBackupDirectories();
873 // backup the dirs if requested
874 retVal
= this->PerformExtraUpdates();
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());
888 this->RestoreBackupDirectories();
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
901 // do an initial cmake to setup the DartConfig file
903 std::string cmakeFailedOuput
;
904 if (!this->CMakeCmd
.empty())
906 command
= this->CMakeCmd
;
908 command
+= this->SourceDir
;
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()
929 cmGeneratedFileStream
fout(cmakeOutputFile
.c_str());
932 fout
<< output
.c_str();
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
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
];
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();
971 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
972 "Unable to run cmake:" << std::endl
973 << cmakeFailedOuput
.c_str() << std::endl
);
976 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
977 "Unable to run ctest:" << std::endl
978 << output
.c_str() << std::endl
);
987 // if all was succesful, delete the backup dirs to free up disk space
990 cmSystemTools::RemoveADirectory(this->BackupSourceDir
.c_str());
991 cmSystemTools::RemoveADirectory(this->BackupBinaryDir
.c_str());
998 //-------------------------------------------------------------------------
999 void cmCTestScriptHandler::RestoreBackupDirectories()
1001 // if we backed up the dirs and the build failed, then restore
1002 // the backed up dirs
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
,
1023 cmCTestScriptHandler
* sh
= new cmCTestScriptHandler();
1024 sh
->SetCTestInstance(ctest
);
1025 sh
->AddConfigurationScript(sname
,InProcess
);
1026 sh
->ProcessHandler();
1031 bool cmCTestScriptHandler::EmptyBinaryDirectory(const char *sname
)
1033 // try to avoid deleting root
1034 if (!sname
|| strlen(sname
) < 2)
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
))
1050 //-------------------------------------------------------------------------
1051 double cmCTestScriptHandler::GetRemainingTimeAllowed()
1053 if (!this->Makefile
)
1058 const char *timelimitS
1059 = this->Makefile
->GetDefinition("CTEST_TIME_LIMIT");
1066 double timelimit
= atof(timelimitS
);
1068 return timelimit
- cmSystemTools::GetTime() + this->ScriptStartTime
;