cmCTestScriptHandler.cxx 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmCTestScriptHandler.h"
  14. #include "cmCTest.h"
  15. #include "cmake.h"
  16. #include "cmFunctionBlocker.h"
  17. #include "cmMakefile.h"
  18. #include "cmLocalGenerator.h"
  19. #include "cmGlobalGenerator.h"
  20. #include "cmGeneratedFileStream.h"
  21. //#include <cmsys/RegularExpression.hxx>
  22. #include <cmsys/Process.h>
  23. // used for sleep
  24. #ifdef _WIN32
  25. #include "windows.h"
  26. #endif
  27. #include <stdlib.h>
  28. #include <time.h>
  29. #include <math.h>
  30. #include <float.h>
  31. // needed for sleep
  32. #if !defined(_WIN32)
  33. # include <unistd.h>
  34. #endif
  35. #include "cmCTestBuildCommand.h"
  36. #include "cmCTestConfigureCommand.h"
  37. #include "cmCTestCoverageCommand.h"
  38. #include "cmCTestEmptyBinaryDirectoryCommand.h"
  39. #include "cmCTestMemCheckCommand.h"
  40. #include "cmCTestReadCustomFilesCommand.h"
  41. #include "cmCTestRunScriptCommand.h"
  42. #include "cmCTestSleepCommand.h"
  43. #include "cmCTestStartCommand.h"
  44. #include "cmCTestSubmitCommand.h"
  45. #include "cmCTestTestCommand.h"
  46. #include "cmCTestUpdateCommand.h"
  47. #define CTEST_INITIAL_CMAKE_OUTPUT_FILE_NAME "CTestInitialCMakeOutput.log"
  48. // used to keep elapsed time up to date
  49. class cmCTestScriptFunctionBlocker : public cmFunctionBlocker
  50. {
  51. public:
  52. cmCTestScriptFunctionBlocker() {}
  53. virtual ~cmCTestScriptFunctionBlocker() {}
  54. virtual bool IsFunctionBlocked(const cmListFileFunction& lff,
  55. cmMakefile &mf);
  56. //virtual bool ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf);
  57. //virtual void ScopeEnded(cmMakefile &mf);
  58. cmCTestScriptHandler* CTestScriptHandler;
  59. };
  60. // simply update the time and don't block anything
  61. bool cmCTestScriptFunctionBlocker::
  62. IsFunctionBlocked(const cmListFileFunction& , cmMakefile &)
  63. {
  64. this->CTestScriptHandler->UpdateElapsedTime();
  65. return false;
  66. }
  67. //----------------------------------------------------------------------
  68. cmCTestScriptHandler::cmCTestScriptHandler()
  69. {
  70. this->Backup = false;
  71. this->EmptyBinDir = false;
  72. this->EmptyBinDirOnce = false;
  73. this->Makefile = 0;
  74. this->LocalGenerator = 0;
  75. this->CMake = 0;
  76. this->GlobalGenerator = 0;
  77. this->ScriptStartTime = 0;
  78. // the *60 is becuase the settings are in minutes but GetTime is seconds
  79. this->MinimumInterval = 30*60;
  80. this->ContinuousDuration = -1;
  81. }
  82. //----------------------------------------------------------------------
  83. void cmCTestScriptHandler::Initialize()
  84. {
  85. this->Superclass::Initialize();
  86. this->Backup = false;
  87. this->EmptyBinDir = false;
  88. this->EmptyBinDirOnce = false;
  89. this->SourceDir = "";
  90. this->BinaryDir = "";
  91. this->BackupSourceDir = "";
  92. this->BackupBinaryDir = "";
  93. this->CTestRoot = "";
  94. this->CVSCheckOut = "";
  95. this->CTestCmd = "";
  96. this->UpdateCmd = "";
  97. this->CTestEnv = "";
  98. this->InitCache = "";
  99. this->CMakeCmd = "";
  100. this->CMOutFile = "";
  101. this->ExtraUpdates.clear();
  102. this->MinimumInterval = 20*60;
  103. this->ContinuousDuration = -1;
  104. // what time in seconds did this script start running
  105. this->ScriptStartTime = 0;
  106. this->Makefile = 0;
  107. if (this->LocalGenerator)
  108. {
  109. delete this->LocalGenerator;
  110. }
  111. this->LocalGenerator = 0;
  112. if (this->GlobalGenerator)
  113. {
  114. delete this->GlobalGenerator;
  115. }
  116. this->GlobalGenerator = 0;
  117. if (this->CMake)
  118. {
  119. delete this->CMake;
  120. }
  121. }
  122. //----------------------------------------------------------------------
  123. cmCTestScriptHandler::~cmCTestScriptHandler()
  124. {
  125. // local generator owns the makefile
  126. this->Makefile = 0;
  127. if (this->LocalGenerator)
  128. {
  129. delete this->LocalGenerator;
  130. }
  131. this->LocalGenerator = 0;
  132. if (this->GlobalGenerator)
  133. {
  134. delete this->GlobalGenerator;
  135. }
  136. this->GlobalGenerator = 0;
  137. if (this->CMake)
  138. {
  139. delete this->CMake;
  140. }
  141. }
  142. //----------------------------------------------------------------------
  143. // just adds an argument to the vector
  144. void cmCTestScriptHandler::AddConfigurationScript(const char *script,
  145. bool pscope)
  146. {
  147. this->ConfigurationScripts.push_back(script);
  148. this->ScriptProcessScope.push_back(pscope);
  149. }
  150. //----------------------------------------------------------------------
  151. // the generic entry point for handling scripts, this routine will run all
  152. // the scripts provides a -S arguments
  153. int cmCTestScriptHandler::ProcessHandler()
  154. {
  155. int res = 0;
  156. for (size_t i=0; i < this->ConfigurationScripts.size(); ++i)
  157. {
  158. // for each script run it
  159. res += this->RunConfigurationScript
  160. (cmSystemTools::CollapseFullPath(this->ConfigurationScripts[i].c_str()),
  161. this->ScriptProcessScope[i]);
  162. }
  163. if ( res )
  164. {
  165. return -1;
  166. }
  167. return 0;
  168. }
  169. void cmCTestScriptHandler::UpdateElapsedTime()
  170. {
  171. if (this->LocalGenerator)
  172. {
  173. // set the current elapsed time
  174. char timeString[20];
  175. int itime = static_cast<unsigned int>(cmSystemTools::GetTime()
  176. - this->ScriptStartTime);
  177. sprintf(timeString,"%i",itime);
  178. this->LocalGenerator->GetMakefile()->AddDefinition("CTEST_ELAPSED_TIME",
  179. timeString);
  180. }
  181. }
  182. //----------------------------------------------------------------------
  183. void cmCTestScriptHandler::AddCTestCommand(cmCTestCommand* command)
  184. {
  185. cmCTestCommand* newCom = command;
  186. newCom->CTest = this->CTest;
  187. newCom->CTestScriptHandler = this;
  188. this->CMake->AddCommand(newCom);
  189. }
  190. int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
  191. {
  192. // execute the script passing in the arguments to the script as well as the
  193. // arguments from this invocation of cmake
  194. std::vector<const char*> argv;
  195. argv.push_back(this->CTest->GetCTestExecutable());
  196. argv.push_back("-SR");
  197. argv.push_back(total_script_arg.c_str());
  198. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  199. "Executable for CTest is: " <<
  200. this->CTest->GetCTestExecutable() << "\n");
  201. // now pass through all the other arguments
  202. std::vector<cmStdString> &initArgs =
  203. this->CTest->GetInitialCommandLineArguments();
  204. for(size_t i=1; i < initArgs.size(); ++i)
  205. {
  206. argv.push_back(initArgs[i].c_str());
  207. }
  208. argv.push_back(0);
  209. // Now create process object
  210. cmsysProcess* cp = cmsysProcess_New();
  211. cmsysProcess_SetCommand(cp, &*argv.begin());
  212. //cmsysProcess_SetWorkingDirectory(cp, dir);
  213. cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
  214. //cmsysProcess_SetTimeout(cp, timeout);
  215. cmsysProcess_Execute(cp);
  216. std::vector<char> out;
  217. std::vector<char> err;
  218. std::string line;
  219. int pipe = cmSystemTools::WaitForLine(cp, line, 100.0, out, err);
  220. while(pipe != cmsysProcess_Pipe_None)
  221. {
  222. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Output: "
  223. << line << "\n");
  224. if(pipe == cmsysProcess_Pipe_STDERR)
  225. {
  226. cmCTestLog(this->CTest, ERROR_MESSAGE, line << "\n");
  227. }
  228. else if(pipe == cmsysProcess_Pipe_STDOUT)
  229. {
  230. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n");
  231. }
  232. pipe = cmSystemTools::WaitForLine(cp, line, 100, out, err);
  233. }
  234. // Properly handle output of the build command
  235. cmsysProcess_WaitForExit(cp, 0);
  236. int result = cmsysProcess_GetState(cp);
  237. int retVal = 0;
  238. if(result == cmsysProcess_State_Exited)
  239. {
  240. retVal = cmsysProcess_GetExitValue(cp);
  241. }
  242. else
  243. {
  244. abort();
  245. }
  246. return retVal;
  247. }
  248. //----------------------------------------------------------------------
  249. // this sets up some variables for the script to use, creates the required
  250. // cmake instance and generators, and then reads in the script
  251. int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
  252. {
  253. // if the argument has a , in it then it needs to be broken into the fist
  254. // argument (which is the script) and the second argument which will be
  255. // passed into the scripts as S_ARG
  256. std::string script = total_script_arg;
  257. std::string script_arg;
  258. if (total_script_arg.find(",") != std::string::npos)
  259. {
  260. script = total_script_arg.substr(0,total_script_arg.find(","));
  261. script_arg = total_script_arg.substr(total_script_arg.find(",")+1);
  262. }
  263. // make sure the file exists
  264. if (!cmSystemTools::FileExists(script.c_str()))
  265. {
  266. cmSystemTools::Error("Cannot find file: ", script.c_str());
  267. return 1;
  268. }
  269. // create a cmake instance to read the configuration script
  270. // read in the list file to fill the cache
  271. if (this->CMake)
  272. {
  273. delete this->CMake;
  274. delete this->GlobalGenerator;
  275. delete this->LocalGenerator;
  276. }
  277. this->CMake = new cmake;
  278. this->CMake->AddCMakePaths(this->CTest->GetCTestExecutable());
  279. this->GlobalGenerator = new cmGlobalGenerator;
  280. this->GlobalGenerator->SetCMakeInstance(this->CMake);
  281. this->LocalGenerator = this->GlobalGenerator->CreateLocalGenerator();
  282. this->LocalGenerator->SetGlobalGenerator(this->GlobalGenerator);
  283. this->Makefile = this->LocalGenerator->GetMakefile();
  284. // set a variable with the path to the current script
  285. this->Makefile->AddDefinition("CTEST_SCRIPT_DIRECTORY",
  286. cmSystemTools::GetFilenamePath(script).c_str());
  287. this->Makefile->AddDefinition("CTEST_SCRIPT_NAME",
  288. cmSystemTools::GetFilenameName(script).c_str());
  289. this->Makefile->AddDefinition("CTEST_EXECUTABLE_NAME",
  290. this->CTest->GetCTestExecutable());
  291. this->Makefile->AddDefinition("CMAKE_EXECUTABLE_NAME",
  292. this->CTest->GetCMakeExecutable());
  293. this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", true);
  294. this->UpdateElapsedTime();
  295. // add any ctest specific commands, probably should have common superclass
  296. // for ctest commands to clean this up. If a couple more commands are
  297. // created with the same format lets do that - ken
  298. this->AddCTestCommand(new cmCTestBuildCommand);
  299. this->AddCTestCommand(new cmCTestConfigureCommand);
  300. this->AddCTestCommand(new cmCTestCoverageCommand);
  301. this->AddCTestCommand(new cmCTestEmptyBinaryDirectoryCommand);
  302. this->AddCTestCommand(new cmCTestMemCheckCommand);
  303. this->AddCTestCommand(new cmCTestReadCustomFilesCommand);
  304. this->AddCTestCommand(new cmCTestRunScriptCommand);
  305. this->AddCTestCommand(new cmCTestSleepCommand);
  306. this->AddCTestCommand(new cmCTestStartCommand);
  307. this->AddCTestCommand(new cmCTestSubmitCommand);
  308. this->AddCTestCommand(new cmCTestTestCommand);
  309. this->AddCTestCommand(new cmCTestUpdateCommand);
  310. // add the script arg if defined
  311. if (script_arg.size())
  312. {
  313. this->Makefile->AddDefinition("CTEST_SCRIPT_ARG", script_arg.c_str());
  314. }
  315. // always add a function blocker to update the elapsed time
  316. cmCTestScriptFunctionBlocker *f = new cmCTestScriptFunctionBlocker();
  317. f->CTestScriptHandler = this;
  318. this->Makefile->AddFunctionBlocker(f);
  319. // finally read in the script
  320. if (!this->Makefile->ReadListFile(0, script.c_str()))
  321. {
  322. return 2;
  323. }
  324. return 0;
  325. }
  326. //----------------------------------------------------------------------
  327. // extract variabels from the script to set ivars
  328. int cmCTestScriptHandler::ExtractVariables()
  329. {
  330. // Temporary variables
  331. const char* minInterval;
  332. const char* contDuration;
  333. this->SourceDir
  334. = this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
  335. this->BinaryDir
  336. = this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY");
  337. this->CTestCmd
  338. = this->Makefile->GetSafeDefinition("CTEST_COMMAND");
  339. this->CVSCheckOut
  340. = this->Makefile->GetSafeDefinition("CTEST_CVS_CHECKOUT");
  341. this->CTestRoot
  342. = this->Makefile->GetSafeDefinition("CTEST_DASHBOARD_ROOT");
  343. this->UpdateCmd
  344. = this->Makefile->GetSafeDefinition("CTEST_UPDATE_COMMAND");
  345. if ( this->UpdateCmd.empty() )
  346. {
  347. this->UpdateCmd
  348. = this->Makefile->GetSafeDefinition("CTEST_CVS_COMMAND");
  349. }
  350. this->CTestEnv
  351. = this->Makefile->GetSafeDefinition("CTEST_ENVIRONMENT");
  352. this->InitCache
  353. = this->Makefile->GetSafeDefinition("CTEST_INITIAL_CACHE");
  354. this->CMakeCmd
  355. = this->Makefile->GetSafeDefinition("CTEST_CMAKE_COMMAND");
  356. this->CMOutFile
  357. = this->Makefile->GetSafeDefinition("CTEST_CMAKE_OUTPUT_FILE_NAME");
  358. this->Backup
  359. = this->Makefile->IsOn("CTEST_BACKUP_AND_RESTORE");
  360. this->EmptyBinDir
  361. = this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY");
  362. this->EmptyBinDirOnce
  363. = this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY_ONCE");
  364. minInterval
  365. = this->Makefile->GetDefinition("CTEST_CONTINUOUS_MINIMUM_INTERVAL");
  366. contDuration
  367. = this->Makefile->GetDefinition("CTEST_CONTINUOUS_DURATION");
  368. char updateVar[40];
  369. int i;
  370. for (i = 1; i < 10; ++i)
  371. {
  372. sprintf(updateVar,"CTEST_EXTRA_UPDATES_%i",i);
  373. const char *updateVal = this->Makefile->GetDefinition(updateVar);
  374. if ( updateVal )
  375. {
  376. if ( this->UpdateCmd.empty() )
  377. {
  378. cmSystemTools::Error(updateVar,
  379. " specified without specifying CTEST_CVS_COMMAND.");
  380. return 12;
  381. }
  382. this->ExtraUpdates.push_back(updateVal);
  383. }
  384. }
  385. // in order to backup and restore we also must have the cvs root
  386. if (this->Backup && this->CVSCheckOut.empty())
  387. {
  388. cmSystemTools::Error(
  389. "Backup was requested without specifying CTEST_CVS_CHECKOUT.");
  390. return 3;
  391. }
  392. // make sure the required info is here
  393. if (this->SourceDir.empty() ||
  394. this->BinaryDir.empty() ||
  395. this->CTestCmd.empty())
  396. {
  397. std::string msg = "CTEST_SOURCE_DIRECTORY = ";
  398. msg += (!this->SourceDir.empty()) ? this->SourceDir.c_str() : "(Null)";
  399. msg += "\nCTEST_BINARY_DIRECTORY = ";
  400. msg += (!this->BinaryDir.empty()) ? this->BinaryDir.c_str() : "(Null)";
  401. msg += "\nCTEST_COMMAND = ";
  402. msg += (!this->CTestCmd.empty()) ? this->CTestCmd.c_str() : "(Null)";
  403. cmSystemTools::Error(
  404. "Some required settings in the configuration file were missing:\n",
  405. msg.c_str());
  406. return 4;
  407. }
  408. // if the dashboard root isn't specified then we can compute it from the
  409. // this->SourceDir
  410. if (this->CTestRoot.empty() )
  411. {
  412. this->CTestRoot = cmSystemTools::GetFilenamePath(this->SourceDir).c_str();
  413. }
  414. // the script may override the minimum continuous interval
  415. if (minInterval)
  416. {
  417. this->MinimumInterval = 60 * atof(minInterval);
  418. }
  419. if (contDuration)
  420. {
  421. this->ContinuousDuration = 60.0 * atof(contDuration);
  422. }
  423. this->UpdateElapsedTime();
  424. return 0;
  425. }
  426. //----------------------------------------------------------------------
  427. void cmCTestScriptHandler::SleepInSeconds(unsigned int secondsToWait)
  428. {
  429. #if defined(_WIN32)
  430. Sleep(1000*secondsToWait);
  431. #else
  432. sleep(secondsToWait);
  433. #endif
  434. }
  435. //----------------------------------------------------------------------
  436. // run a specific script
  437. int cmCTestScriptHandler::RunConfigurationScript
  438. (const std::string& total_script_arg, bool pscope)
  439. {
  440. int result;
  441. this->ScriptStartTime =
  442. cmSystemTools::GetTime();
  443. // read in the script
  444. if (pscope)
  445. {
  446. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  447. "Reading Script: " << total_script_arg << std::endl);
  448. result = this->ReadInScript(total_script_arg);
  449. }
  450. else
  451. {
  452. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  453. "Executing Script: " << total_script_arg << std::endl);
  454. result = this->ExecuteScript(total_script_arg);
  455. }
  456. if (result)
  457. {
  458. return result;
  459. }
  460. // only run the curent script if we should
  461. if (this->Makefile && this->Makefile->IsOn("CTEST_RUN_CURRENT_SCRIPT"))
  462. {
  463. return this->RunCurrentScript();
  464. }
  465. return result;
  466. }
  467. //----------------------------------------------------------------------
  468. int cmCTestScriptHandler::RunCurrentScript()
  469. {
  470. int result;
  471. // do not run twice
  472. this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", false);
  473. // no popup widows
  474. cmSystemTools::SetRunCommandHideConsole(true);
  475. // extract the vars from the cache and store in ivars
  476. result = this->ExtractVariables();
  477. if (result)
  478. {
  479. return result;
  480. }
  481. // set any environment variables
  482. if (!this->CTestEnv.empty())
  483. {
  484. std::vector<std::string> envArgs;
  485. cmSystemTools::ExpandListArgument(this->CTestEnv.c_str(),envArgs);
  486. // for each variable/argument do a putenv
  487. for (unsigned i = 0; i < envArgs.size(); ++i)
  488. {
  489. cmSystemTools::PutEnv(envArgs[i].c_str());
  490. }
  491. }
  492. // now that we have done most of the error checking finally run the
  493. // dashboard, we may be asked to repeatedly run this dashboard, such as
  494. // for a continuous, do we ned to run it more than once?
  495. if ( this->ContinuousDuration >= 0 )
  496. {
  497. this->UpdateElapsedTime();
  498. double ending_time = cmSystemTools::GetTime() + this->ContinuousDuration;
  499. if (this->EmptyBinDirOnce)
  500. {
  501. this->EmptyBinDir = true;
  502. }
  503. do
  504. {
  505. double interval = cmSystemTools::GetTime();
  506. result = this->RunConfigurationDashboard();
  507. interval = cmSystemTools::GetTime() - interval;
  508. if (interval < this->MinimumInterval)
  509. {
  510. this->SleepInSeconds(
  511. static_cast<unsigned int>(this->MinimumInterval - interval));
  512. }
  513. if (this->EmptyBinDirOnce)
  514. {
  515. this->EmptyBinDir = false;
  516. }
  517. }
  518. while (cmSystemTools::GetTime() < ending_time);
  519. }
  520. // otherwise just run it once
  521. else
  522. {
  523. result = this->RunConfigurationDashboard();
  524. }
  525. return result;
  526. }
  527. //----------------------------------------------------------------------
  528. int cmCTestScriptHandler::CheckOutSourceDir()
  529. {
  530. std::string command;
  531. std::string output;
  532. int retVal;
  533. bool res;
  534. if (!cmSystemTools::FileExists(this->SourceDir.c_str()) &&
  535. !this->CVSCheckOut.empty())
  536. {
  537. // we must now checkout the src dir
  538. output = "";
  539. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  540. "Run cvs: " << this->CVSCheckOut << std::endl);
  541. res = cmSystemTools::RunSingleCommand(this->CVSCheckOut.c_str(), &output,
  542. &retVal, this->CTestRoot.c_str(), this->HandlerVerbose,
  543. 0 /*this->TimeOut*/);
  544. if (!res || retVal != 0)
  545. {
  546. cmSystemTools::Error("Unable to perform cvs checkout:\n",
  547. output.c_str());
  548. return 6;
  549. }
  550. }
  551. return 0;
  552. }
  553. //----------------------------------------------------------------------
  554. int cmCTestScriptHandler::BackupDirectories()
  555. {
  556. int retVal;
  557. // compute the backup names
  558. this->BackupSourceDir = this->SourceDir;
  559. this->BackupSourceDir += "_CMakeBackup";
  560. this->BackupBinaryDir = this->BinaryDir;
  561. this->BackupBinaryDir += "_CMakeBackup";
  562. // backup the binary and src directories if requested
  563. if (this->Backup)
  564. {
  565. // if for some reason those directories exist then first delete them
  566. if (cmSystemTools::FileExists(this->BackupSourceDir.c_str()))
  567. {
  568. cmSystemTools::RemoveADirectory(this->BackupSourceDir.c_str());
  569. }
  570. if (cmSystemTools::FileExists(this->BackupBinaryDir.c_str()))
  571. {
  572. cmSystemTools::RemoveADirectory(this->BackupBinaryDir.c_str());
  573. }
  574. // first rename the src and binary directories
  575. rename(this->SourceDir.c_str(), this->BackupSourceDir.c_str());
  576. rename(this->BinaryDir.c_str(), this->BackupBinaryDir.c_str());
  577. // we must now checkout the src dir
  578. retVal = this->CheckOutSourceDir();
  579. if (retVal)
  580. {
  581. this->RestoreBackupDirectories();
  582. return retVal;
  583. }
  584. }
  585. return 0;
  586. }
  587. //----------------------------------------------------------------------
  588. int cmCTestScriptHandler::PerformExtraUpdates()
  589. {
  590. std::string command;
  591. std::string output;
  592. int retVal;
  593. bool res;
  594. // do an initial cvs update as required
  595. command = this->UpdateCmd;
  596. std::vector<cmStdString>::iterator it;
  597. for (it = this->ExtraUpdates.begin();
  598. it != this->ExtraUpdates.end();
  599. ++ it )
  600. {
  601. std::vector<std::string> cvsArgs;
  602. cmSystemTools::ExpandListArgument(it->c_str(),cvsArgs);
  603. if (cvsArgs.size() == 2)
  604. {
  605. std::string fullCommand = command;
  606. fullCommand += " update ";
  607. fullCommand += cvsArgs[1];
  608. output = "";
  609. retVal = 0;
  610. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run Update: "
  611. << fullCommand.c_str() << std::endl);
  612. res = cmSystemTools::RunSingleCommand(fullCommand.c_str(), &output,
  613. &retVal, cvsArgs[0].c_str(),
  614. this->HandlerVerbose, 0 /*this->TimeOut*/);
  615. if (!res || retVal != 0)
  616. {
  617. cmSystemTools::Error("Unable to perform extra updates:\n",
  618. output.c_str());
  619. return 0;
  620. }
  621. }
  622. }
  623. return 0;
  624. }
  625. //----------------------------------------------------------------------
  626. // run a single dashboard entry
  627. int cmCTestScriptHandler::RunConfigurationDashboard()
  628. {
  629. // local variables
  630. std::string command;
  631. std::string output;
  632. int retVal;
  633. bool res;
  634. // make sure the src directory is there, if it isn't then we might be able
  635. // to check it out from cvs
  636. retVal = this->CheckOutSourceDir();
  637. if (retVal)
  638. {
  639. return retVal;
  640. }
  641. // backup the dirs if requested
  642. retVal = this->BackupDirectories();
  643. if (retVal)
  644. {
  645. return retVal;
  646. }
  647. // clear the binary directory?
  648. if (this->EmptyBinDir)
  649. {
  650. if ( !cmCTestScriptHandler::EmptyBinaryDirectory(
  651. this->BinaryDir.c_str()) )
  652. {
  653. cmCTestLog(this->CTest, ERROR_MESSAGE,
  654. "Problem removing the binary directory" << std::endl);
  655. }
  656. }
  657. // make sure the binary directory exists if it isn't the srcdir
  658. if (!cmSystemTools::FileExists(this->BinaryDir.c_str()) &&
  659. this->SourceDir != this->BinaryDir)
  660. {
  661. if (!cmSystemTools::MakeDirectory(this->BinaryDir.c_str()))
  662. {
  663. cmSystemTools::Error("Unable to create the binary directory:\n",
  664. this->BinaryDir.c_str());
  665. this->RestoreBackupDirectories();
  666. return 7;
  667. }
  668. }
  669. // if the binary directory and the source directory are the same,
  670. // and we are starting with an empty binary directory, then that means
  671. // we must check out the source tree
  672. if (this->EmptyBinDir && this->SourceDir == this->BinaryDir)
  673. {
  674. // make sure we have the required info
  675. if (this->CVSCheckOut.empty())
  676. {
  677. cmSystemTools::Error("You have specified the source and binary "
  678. "directories to be the same (an in source build). You have also "
  679. "specified that the binary directory is to be erased. This means "
  680. "that the source will have to be checked out from CVS. But you have "
  681. "not specified CTEST_CVS_CHECKOUT");
  682. return 8;
  683. }
  684. // we must now checkout the src dir
  685. retVal = this->CheckOutSourceDir();
  686. if (retVal)
  687. {
  688. this->RestoreBackupDirectories();
  689. return retVal;
  690. }
  691. }
  692. // backup the dirs if requested
  693. retVal = this->PerformExtraUpdates();
  694. if (retVal)
  695. {
  696. return retVal;
  697. }
  698. // put the initial cache into the bin dir
  699. if (!this->InitCache.empty())
  700. {
  701. std::string cacheFile = this->BinaryDir;
  702. cacheFile += "/CMakeCache.txt";
  703. cmGeneratedFileStream fout(cacheFile.c_str());
  704. if(!fout)
  705. {
  706. this->RestoreBackupDirectories();
  707. return 9;
  708. }
  709. fout.write(this->InitCache.c_str(), this->InitCache.size());
  710. // Make sure the operating system has finished writing the file
  711. // before closing it. This will ensure the file is finished before
  712. // the check below.
  713. fout.flush();
  714. fout.close();
  715. }
  716. // do an initial cmake to setup the DartConfig file
  717. int cmakeFailed = 0;
  718. std::string cmakeFailedOuput;
  719. if (!this->CMakeCmd.empty())
  720. {
  721. command = this->CMakeCmd;
  722. command += " \"";
  723. command += this->SourceDir;
  724. output = "";
  725. command += "\"";
  726. retVal = 0;
  727. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run cmake command: "
  728. << command.c_str() << std::endl);
  729. res = cmSystemTools::RunSingleCommand(command.c_str(), &output,
  730. &retVal, this->BinaryDir.c_str(),
  731. this->HandlerVerbose, 0 /*this->TimeOut*/);
  732. if ( !this->CMOutFile.empty() )
  733. {
  734. std::string cmakeOutputFile = this->CMOutFile;
  735. if ( !cmSystemTools::FileIsFullPath(cmakeOutputFile.c_str()) )
  736. {
  737. cmakeOutputFile = this->BinaryDir + "/" + cmakeOutputFile;
  738. }
  739. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  740. "Write CMake output to file: " << cmakeOutputFile.c_str()
  741. << std::endl);
  742. cmGeneratedFileStream fout(cmakeOutputFile.c_str());
  743. if ( fout )
  744. {
  745. fout << output.c_str();
  746. }
  747. else
  748. {
  749. cmCTestLog(this->CTest, ERROR_MESSAGE,
  750. "Cannot open CMake output file: "
  751. << cmakeOutputFile.c_str() << " for writing" << std::endl);
  752. }
  753. }
  754. if (!res || retVal != 0)
  755. {
  756. // even if this fails continue to the next step
  757. cmakeFailed = 1;
  758. cmakeFailedOuput = output;
  759. }
  760. }
  761. // run ctest, it may be more than one command in here
  762. std::vector<std::string> ctestCommands;
  763. cmSystemTools::ExpandListArgument(this->CTestCmd,ctestCommands);
  764. // for each variable/argument do a putenv
  765. for (unsigned i = 0; i < ctestCommands.size(); ++i)
  766. {
  767. command = ctestCommands[i];
  768. output = "";
  769. retVal = 0;
  770. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run ctest command: "
  771. << command.c_str() << std::endl);
  772. res = cmSystemTools::RunSingleCommand(command.c_str(), &output,
  773. &retVal, this->BinaryDir.c_str(), this->HandlerVerbose,
  774. 0 /*this->TimeOut*/);
  775. // did something critical fail in ctest
  776. if (!res || cmakeFailed ||
  777. retVal & cmCTest::BUILD_ERRORS)
  778. {
  779. this->RestoreBackupDirectories();
  780. if (cmakeFailed)
  781. {
  782. cmCTestLog(this->CTest, ERROR_MESSAGE,
  783. "Unable to run cmake:" << std::endl
  784. << cmakeFailedOuput.c_str() << std::endl);
  785. return 10;
  786. }
  787. cmCTestLog(this->CTest, ERROR_MESSAGE,
  788. "Unable to run ctest:" << std::endl
  789. << output.c_str() << std::endl);
  790. if (!res)
  791. {
  792. return 11;
  793. }
  794. return retVal * 100;
  795. }
  796. }
  797. // if all was succesful, delete the backup dirs to free up disk space
  798. if (this->Backup)
  799. {
  800. cmSystemTools::RemoveADirectory(this->BackupSourceDir.c_str());
  801. cmSystemTools::RemoveADirectory(this->BackupBinaryDir.c_str());
  802. }
  803. return 0;
  804. }
  805. //-------------------------------------------------------------------------
  806. void cmCTestScriptHandler::RestoreBackupDirectories()
  807. {
  808. // if we backed up the dirs and the build failed, then restore
  809. // the backed up dirs
  810. if (this->Backup)
  811. {
  812. // if for some reason those directories exist then first delete them
  813. if (cmSystemTools::FileExists(this->SourceDir.c_str()))
  814. {
  815. cmSystemTools::RemoveADirectory(this->SourceDir.c_str());
  816. }
  817. if (cmSystemTools::FileExists(this->BinaryDir.c_str()))
  818. {
  819. cmSystemTools::RemoveADirectory(this->BinaryDir.c_str());
  820. }
  821. // rename the src and binary directories
  822. rename(this->BackupSourceDir.c_str(), this->SourceDir.c_str());
  823. rename(this->BackupBinaryDir.c_str(), this->BinaryDir.c_str());
  824. }
  825. }
  826. bool cmCTestScriptHandler::RunScript(cmCTest* ctest, const char *sname,
  827. bool InProcess)
  828. {
  829. cmCTestScriptHandler* sh = new cmCTestScriptHandler();
  830. sh->SetCTestInstance(ctest);
  831. sh->AddConfigurationScript(sname,InProcess);
  832. sh->ProcessHandler();
  833. delete sh;
  834. return true;
  835. }
  836. bool cmCTestScriptHandler::EmptyBinaryDirectory(const char *sname)
  837. {
  838. // try to avoid deleting root
  839. if (!sname || strlen(sname) < 2)
  840. {
  841. return false;
  842. }
  843. // try to avoid deleting directories that we shouldn't
  844. std::string check = sname;
  845. check += "/CMakeCache.txt";
  846. if(cmSystemTools::FileExists(check.c_str()) &&
  847. !cmSystemTools::RemoveADirectory(sname))
  848. {
  849. return false;
  850. }
  851. return true;
  852. }