1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
16 #include "cmMakefile.h"
17 #include "cmLocalGenerator.h"
18 #include "cmGlobalGenerator.h"
19 #include <cmsys/Base64.h>
20 #include <cmsys/Directory.hxx>
21 #include <cmsys/SystemInformation.hxx>
22 #include "cmDynamicLoader.h"
23 #include "cmGeneratedFileStream.h"
24 #include "cmXMLSafe.h"
25 #include "cmVersionMacros.h"
26 #include "cmCTestCommand.h"
27 #include "cmCTestStartCommand.h"
29 #include "cmCTestBuildHandler.h"
30 #include "cmCTestBuildAndTestHandler.h"
31 #include "cmCTestConfigureHandler.h"
32 #include "cmCTestCoverageHandler.h"
33 #include "cmCTestMemCheckHandler.h"
34 #include "cmCTestScriptHandler.h"
35 #include "cmCTestSubmitHandler.h"
36 #include "cmCTestTestHandler.h"
37 #include "cmCTestUpdateHandler.h"
38 #include "cmCTestUploadHandler.h"
40 #include "cmVersion.h"
42 #include <cmsys/RegularExpression.hxx>
43 #include <cmsys/Process.h>
44 #include <cmsys/Glob.hxx>
51 #include <cmsys/auto_ptr.hxx>
54 #include <cmsys/Base64.h>
57 #include <be/kernel/OS.h> /* disable_debugger() API. */
60 #if defined(__HAIKU__)
61 #include <os/kernel/OS.h> /* disable_debugger() API. */
65 #define DEBUGOUT std::cout << __LINE__ << " "; std::cout
66 #define DEBUGERR std::cerr << __LINE__ << " "; std::cerr
68 //----------------------------------------------------------------------
69 struct tm* cmCTest::GetNightlyTime(std::string str,
73 time_t tctime = time(0);
74 lctime = gmtime(&tctime);
76 // add todays year day and month to the time in str because
77 // curl_getdate no longer assumes the day is today
78 sprintf(buf, "%d%02d%02d %s",
83 cmCTestLog(this, OUTPUT, "Determine Nightly Start Time" << std::endl
84 << " Specified time: " << str.c_str() << std::endl);
85 //Convert the nightly start time to seconds. Since we are
86 //providing only a time and a timezone, the current date of
87 //the local machine is assumed. Consequently, nightlySeconds
88 //is the time at which the nightly dashboard was opened or
89 //will be opened on the date of the current client machine.
90 //As such, this time may be in the past or in the future.
91 time_t ntime = curl_getdate(buf, &tctime);
92 cmCTestLog(this, DEBUG, " Get curl time: " << ntime << std::endl);
94 cmCTestLog(this, DEBUG, " Get the current time: " << tctime << std::endl);
96 const int dayLength = 24 * 60 * 60;
97 cmCTestLog(this, DEBUG, "Seconds: " << tctime << std::endl);
98 while ( ntime > tctime )
100 // If nightlySeconds is in the past, this is the current
101 // open dashboard, then return nightlySeconds. If
102 // nightlySeconds is in the future, this is the next
103 // dashboard to be opened, so subtract 24 hours to get the
104 // time of the current open dashboard
106 cmCTestLog(this, DEBUG, "Pick yesterday" << std::endl);
107 cmCTestLog(this, DEBUG, " Future time, subtract day: " << ntime
110 while ( tctime > (ntime + dayLength) )
113 cmCTestLog(this, DEBUG, " Past time, add day: " << ntime << std::endl);
115 cmCTestLog(this, DEBUG, "nightlySeconds: " << ntime << std::endl);
116 cmCTestLog(this, DEBUG, " Current time: " << tctime
117 << " Nightly time: " << ntime << std::endl);
120 cmCTestLog(this, OUTPUT, " Use future tag, Add a day" << std::endl);
123 lctime = gmtime(&ntime);
127 //----------------------------------------------------------------------
128 std::string cmCTest::CleanString(const std::string& str)
130 std::string::size_type spos = str.find_first_not_of(" \n\t\r\f\v");
131 std::string::size_type epos = str.find_last_not_of(" \n\t\r\f\v");
132 if ( spos == str.npos )
134 return std::string();
136 if ( epos != str.npos )
138 epos = epos - spos + 1;
140 return str.substr(spos, epos);
143 //----------------------------------------------------------------------
144 std::string cmCTest::CurrentTime()
146 time_t currenttime = time(0);
147 struct tm* t = localtime(¤ttime);
148 //return ::CleanString(ctime(¤ttime));
149 char current_time[1024];
150 if ( this->ShortDateFormat )
152 strftime(current_time, 1000, "%b %d %H:%M %Z", t);
156 strftime(current_time, 1000, "%a %b %d %H:%M:%S %Z %Y", t);
158 cmCTestLog(this, DEBUG, " Current_Time: " << current_time << std::endl);
159 return cmXMLSafe(cmCTest::CleanString(current_time)).str();
162 //----------------------------------------------------------------------
163 std::string cmCTest::GetCostDataFile()
165 std::string fname = this->GetCTestConfiguration("CostDataFile");
168 fname= this->GetBinaryDir() + "/Testing/Temporary/CTestCostData.txt";
173 #ifdef CMAKE_BUILD_WITH_CMAKE
174 //----------------------------------------------------------------------------
176 HTTPResponseCallback(void *ptr, size_t size, size_t nmemb, void *data)
178 register int realsize = (int)(size * nmemb);
180 std::string *response
181 = static_cast<std::string*>(data);
182 const char* chPtr = static_cast<char*>(ptr);
188 //----------------------------------------------------------------------------
189 int cmCTest::HTTPRequest(std::string url, HTTPMethod method,
190 std::string& response,
192 std::string putFile, int timeout)
196 ::curl_global_init(CURL_GLOBAL_ALL);
197 curl = ::curl_easy_init();
199 //set request options based on method
202 case cmCTest::HTTP_POST:
203 ::curl_easy_setopt(curl, CURLOPT_POST, 1);
204 ::curl_easy_setopt(curl, CURLOPT_POSTFIELDS, fields.c_str());
206 case cmCTest::HTTP_PUT:
207 if(!cmSystemTools::FileExists(putFile.c_str()))
209 response = "Error: File ";
210 response += putFile + " does not exist.\n";
213 ::curl_easy_setopt(curl, CURLOPT_PUT, 1);
214 file = ::fopen(putFile.c_str(), "rb");
215 ::curl_easy_setopt(curl, CURLOPT_INFILE, file);
216 //fall through to append GET fields
217 case cmCTest::HTTP_GET:
227 ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
228 ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
229 ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
231 //set response options
232 ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HTTPResponseCallback);
233 ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&response);
234 ::curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
236 CURLcode res = ::curl_easy_perform(curl);
238 ::curl_easy_cleanup(curl);
239 ::curl_global_cleanup();
241 return static_cast<int>(res);
245 //----------------------------------------------------------------------
246 std::string cmCTest::MakeURLSafe(const std::string& str)
250 for ( std::string::size_type pos = 0; pos < str.size(); pos ++ )
252 unsigned char ch = str[pos];
253 if ( ( ch > 126 || ch < 32 ||
261 sprintf(buffer, "%02x;", (unsigned int)ch);
272 //----------------------------------------------------------------------------
273 std::string cmCTest::DecodeURL(const std::string& in)
276 for(const char* c = in.c_str(); *c; ++c)
278 if(*c == '%' && isxdigit(*(c+1)) && isxdigit(*(c+2)))
280 char buf[3] = {*(c+1), *(c+2), 0};
281 out.append(1, char(strtoul(buf, 0, 16)));
292 //----------------------------------------------------------------------
295 this->LabelSummary = true;
296 this->ParallelLevel = 1;
297 this->SubmitIndex = 0;
298 this->Failover = false;
299 this->BatchJobs = false;
300 this->ForceNewCTestProcess = false;
301 this->TomorrowTag = false;
302 this->Verbose = false;
305 this->ShowLineNumbers = false;
307 this->ExtraVerbose = false;
308 this->ProduceXML = false;
309 this->ShowOnly = false;
310 this->RunConfigurationScript = false;
311 this->UseHTTP10 = false;
312 this->PrintLabels = false;
313 this->CompressTestOutput = true;
314 this->CompressMemCheckOutput = true;
315 this->TestModel = cmCTest::EXPERIMENTAL;
316 this->MaxTestNameWidth = 30;
317 this->InteractiveDebugMode = true;
319 this->GlobalTimeout = 0;
320 this->LastStopTimeout = 24 * 60 * 60;
321 this->CompressXMLFiles = false;
322 this->CTestConfigFile = "";
323 this->ScheduleType = "";
325 this->NextDayStopTime = false;
326 this->OutputLogFile = 0;
327 this->OutputLogFileLastTag = -1;
328 this->SuppressUpdatingCTestConfiguration = false;
329 this->DartVersion = 1;
330 this->DropSiteCDash = false;
331 this->OutputTestOutputOnTestFailure = false;
332 this->ComputedCompressTestOutput = false;
333 this->ComputedCompressMemCheckOutput = false;
334 if(cmSystemTools::GetEnv("CTEST_OUTPUT_ON_FAILURE"))
336 this->OutputTestOutputOnTestFailure = true;
340 this->Parts[PartStart].SetName("Start");
341 this->Parts[PartUpdate].SetName("Update");
342 this->Parts[PartConfigure].SetName("Configure");
343 this->Parts[PartBuild].SetName("Build");
344 this->Parts[PartTest].SetName("Test");
345 this->Parts[PartCoverage].SetName("Coverage");
346 this->Parts[PartMemCheck].SetName("MemCheck");
347 this->Parts[PartSubmit].SetName("Submit");
348 this->Parts[PartNotes].SetName("Notes");
349 this->Parts[PartExtraFiles].SetName("ExtraFiles");
350 this->Parts[PartUpload].SetName("Upload");
352 // Fill the part name-to-id map.
353 for(Part p = PartStart; p != PartCount; p = Part(p+1))
355 this->PartMap[cmSystemTools::LowerCase(this->Parts[p].GetName())] = p;
358 this->ShortDateFormat = true;
360 this->TestingHandlers["build"] = new cmCTestBuildHandler;
361 this->TestingHandlers["buildtest"] = new cmCTestBuildAndTestHandler;
362 this->TestingHandlers["coverage"] = new cmCTestCoverageHandler;
363 this->TestingHandlers["script"] = new cmCTestScriptHandler;
364 this->TestingHandlers["test"] = new cmCTestTestHandler;
365 this->TestingHandlers["update"] = new cmCTestUpdateHandler;
366 this->TestingHandlers["configure"] = new cmCTestConfigureHandler;
367 this->TestingHandlers["memcheck"] = new cmCTestMemCheckHandler;
368 this->TestingHandlers["submit"] = new cmCTestSubmitHandler;
369 this->TestingHandlers["upload"] = new cmCTestUploadHandler;
371 cmCTest::t_TestingHandlers::iterator it;
372 for ( it = this->TestingHandlers.begin();
373 it != this->TestingHandlers.end(); ++ it )
375 it->second->SetCTestInstance(this);
378 // Make sure we can capture the build tool output.
379 cmSystemTools::EnableVSConsoleOutput();
382 //----------------------------------------------------------------------
385 cmCTest::t_TestingHandlers::iterator it;
386 for ( it = this->TestingHandlers.begin();
387 it != this->TestingHandlers.end(); ++ it )
392 this->SetOutputLogFileName(0);
395 void cmCTest::SetParallelLevel(int level)
397 this->ParallelLevel = level < 1 ? 1 : level;
400 //----------------------------------------------------------------------------
401 bool cmCTest::ShouldCompressTestOutput()
403 if(!this->ComputedCompressTestOutput)
405 std::string cdashVersion = this->GetCDashVersion();
407 bool cdashSupportsGzip = cmSystemTools::VersionCompare(
408 cmSystemTools::OP_GREATER, cdashVersion.c_str(), "1.6") ||
409 cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
410 cdashVersion.c_str(), "1.6");
411 this->CompressTestOutput &= cdashSupportsGzip;
412 this->ComputedCompressTestOutput = true;
414 return this->CompressTestOutput;
417 //----------------------------------------------------------------------------
418 bool cmCTest::ShouldCompressMemCheckOutput()
420 if(!this->ComputedCompressMemCheckOutput)
422 std::string cdashVersion = this->GetCDashVersion();
424 bool compressionSupported = cmSystemTools::VersionCompare(
425 cmSystemTools::OP_GREATER, cdashVersion.c_str(), "1.9.0");
426 this->CompressMemCheckOutput &= compressionSupported;
427 this->ComputedCompressMemCheckOutput = true;
429 return this->CompressMemCheckOutput;
432 //----------------------------------------------------------------------------
433 std::string cmCTest::GetCDashVersion()
435 #ifdef CMAKE_BUILD_WITH_CMAKE
436 //First query the server. If that fails, fall back to the local setting
437 std::string response;
438 std::string url = "http://";
439 url += this->GetCTestConfiguration("DropSite");
441 std::string cdashUri = this->GetCTestConfiguration("DropLocation");
442 cdashUri = cdashUri.substr(0, cdashUri.find("/submit.php"));
445 if ( ! cdashUri.empty() )
447 url += cdashUri + "/api/getversion.php";
448 res = cmCTest::HTTPRequest(url, cmCTest::HTTP_GET, response, "", "", 3);
451 return res ? this->GetCTestConfiguration("CDashVersion") : response;
453 return this->GetCTestConfiguration("CDashVersion");
457 //----------------------------------------------------------------------------
458 cmCTest::Part cmCTest::GetPartFromName(const char* name)
460 // Look up by lower-case to make names case-insensitive.
461 std::string lower_name = cmSystemTools::LowerCase(name);
462 PartMapType::const_iterator i = this->PartMap.find(lower_name);
463 if(i != this->PartMap.end())
468 // The string does not name a valid part.
472 //----------------------------------------------------------------------
473 int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
475 cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
476 if(!this->InteractiveDebugMode)
478 this->BlockTestErrorDiagnostics();
482 cmSystemTools::PutEnv("CTEST_INTERACTIVE_DEBUG_MODE=1");
485 this->BinaryDir = binary_dir;
486 cmSystemTools::ConvertToUnixSlashes(this->BinaryDir);
488 this->UpdateCTestConfiguration();
490 cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
491 if ( this->ProduceXML )
493 cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
494 cmCTestLog(this, OUTPUT,
495 " Site: " << this->GetCTestConfiguration("Site") << std::endl
496 << " Build name: " << this->GetCTestConfiguration("BuildName")
498 cmCTestLog(this, DEBUG, "Produce XML is on" << std::endl);
499 if ( this->TestModel == cmCTest::NIGHTLY &&
500 this->GetCTestConfiguration("NightlyStartTime").empty() )
502 cmCTestLog(this, WARNING,
503 "WARNING: No nightly start time found please set in"
504 " CTestConfig.cmake or DartConfig.cmake" << std::endl);
505 cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
511 cmGlobalGenerator gg;
512 gg.SetCMakeInstance(&cm);
513 cmsys::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator());
514 cmMakefile *mf = lg->GetMakefile();
515 if ( !this->ReadCustomConfigurationFileTree(this->BinaryDir.c_str(), mf) )
517 cmCTestLog(this, DEBUG, "Cannot find custom configuration file tree"
522 if ( this->ProduceXML )
524 // Verify "Testing" directory exists:
526 std::string testingDir = this->BinaryDir + "/Testing";
527 if ( cmSystemTools::FileExists(testingDir.c_str()) )
529 if ( !cmSystemTools::FileIsDirectory(testingDir.c_str()) )
531 cmCTestLog(this, ERROR_MESSAGE, "File " << testingDir
532 << " is in the place of the testing directory" << std::endl);
538 if ( !cmSystemTools::MakeDirectory(testingDir.c_str()) )
540 cmCTestLog(this, ERROR_MESSAGE, "Cannot create directory "
541 << testingDir << std::endl);
546 // Create new "TAG" file or read existing one:
548 bool createNewTag = true;
551 createNewTag = command->ShouldCreateNewTag();
554 std::string tagfile = testingDir + "/TAG";
555 std::ifstream tfin(tagfile.c_str());
560 time_t tctime = time(0);
561 if ( this->TomorrowTag )
563 tctime += ( 24 * 60 * 60 );
565 struct tm *lctime = gmtime(&tctime);
566 if ( tfin && cmSystemTools::GetLineFromStream(tfin, tag) )
573 sscanf(tag.c_str(), "%04d%02d%02d-%02d%02d",
574 &year, &mon, &day, &hour, &min);
575 if ( year != lctime->tm_year + 1900 ||
576 mon != lctime->tm_mon+1 ||
577 day != lctime->tm_mday )
582 if ( cmSystemTools::GetLineFromStream(tfin, tagmode) )
584 if (tagmode.size() > 4 && !this->Parts[PartStart])
586 this->TestModel = cmCTest::GetTestModelFromString(tagmode.c_str());
591 if (tag.size() == 0 || (0 != command) || this->Parts[PartStart])
593 cmCTestLog(this, DEBUG, "TestModel: " << this->GetTestModelString()
595 cmCTestLog(this, DEBUG, "TestModel: " << this->TestModel << std::endl);
596 if ( this->TestModel == cmCTest::NIGHTLY )
598 lctime = this->GetNightlyTime(
599 this->GetCTestConfiguration("NightlyStartTime"),
602 char datestring[100];
603 sprintf(datestring, "%04d%02d%02d-%02d%02d",
604 lctime->tm_year + 1900,
610 std::ofstream ofs(tagfile.c_str());
613 ofs << tag << std::endl;
614 ofs << this->GetTestModelString() << std::endl;
619 cmCTestLog(this, OUTPUT, "Create new tag: " << tag << " - "
620 << this->GetTestModelString() << std::endl);
628 cmSystemTools::GetLineFromStream(tfin, tag);
634 cmCTestLog(this, ERROR_MESSAGE,
635 "Cannot read existing TAG file in " << testingDir
640 cmCTestLog(this, OUTPUT, " Use existing tag: " << tag << " - "
641 << this->GetTestModelString() << std::endl);
644 this->CurrentTag = tag;
650 //----------------------------------------------------------------------
651 bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command)
654 = this->GetCTestConfiguration("SourceDirectory").c_str();
655 std::string bld_dir = this->GetCTestConfiguration("BuildDirectory").c_str();
656 this->DartVersion = 1;
657 this->DropSiteCDash = false;
658 for(Part p = PartStart; p != PartCount; p = Part(p+1))
660 this->Parts[p].SubmitFiles.clear();
663 cmMakefile* mf = command->GetMakefile();
666 std::string src_dir_fname = src_dir;
667 src_dir_fname += "/CTestConfig.cmake";
668 cmSystemTools::ConvertToUnixSlashes(src_dir_fname);
670 std::string bld_dir_fname = bld_dir;
671 bld_dir_fname += "/CTestConfig.cmake";
672 cmSystemTools::ConvertToUnixSlashes(bld_dir_fname);
674 if ( cmSystemTools::FileExists(bld_dir_fname.c_str()) )
676 fname = bld_dir_fname;
678 else if ( cmSystemTools::FileExists(src_dir_fname.c_str()) )
680 fname = src_dir_fname;
683 if ( !fname.empty() )
685 cmCTestLog(this, OUTPUT, " Reading ctest configuration file: "
686 << fname.c_str() << std::endl);
687 bool readit = mf->ReadListFile(mf->GetCurrentListFile(),
691 std::string m = "Could not find include file: ";
693 command->SetError(m.c_str());
699 cmCTestLog(this, WARNING,
700 "Cannot locate CTest configuration: in BuildDirectory: "
701 << bld_dir_fname.c_str() << std::endl);
702 cmCTestLog(this, WARNING,
703 "Cannot locate CTest configuration: in SourceDirectory: "
704 << src_dir_fname.c_str() << std::endl);
707 this->SetCTestConfigurationFromCMakeVariable(mf, "NightlyStartTime",
708 "CTEST_NIGHTLY_START_TIME");
709 this->SetCTestConfigurationFromCMakeVariable(mf, "Site", "CTEST_SITE");
710 this->SetCTestConfigurationFromCMakeVariable(mf, "BuildName",
712 const char* dartVersion = mf->GetDefinition("CTEST_DART_SERVER_VERSION");
715 this->DartVersion = atoi(dartVersion);
716 if ( this->DartVersion < 0 )
718 cmCTestLog(this, ERROR_MESSAGE, "Invalid Dart server version: "
719 << dartVersion << ". Please specify the version number."
724 this->DropSiteCDash = mf->IsOn("CTEST_DROP_SITE_CDASH");
726 if ( !this->Initialize(bld_dir.c_str(), command) )
730 cmCTestLog(this, OUTPUT, " Use " << this->GetTestModelString()
731 << " tag: " << this->GetCurrentTag() << std::endl);
736 //----------------------------------------------------------------------
737 bool cmCTest::UpdateCTestConfiguration()
739 if ( this->SuppressUpdatingCTestConfiguration )
743 std::string fileName = this->CTestConfigFile;
744 if ( fileName.empty() )
746 fileName = this->BinaryDir + "/CTestConfiguration.ini";
747 if ( !cmSystemTools::FileExists(fileName.c_str()) )
749 fileName = this->BinaryDir + "/DartConfiguration.tcl";
752 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "UpdateCTestConfiguration from :"
753 << fileName.c_str() << "\n");
754 if ( !cmSystemTools::FileExists(fileName.c_str()) )
756 // No need to exit if we are not producing XML
757 if ( this->ProduceXML )
759 cmCTestLog(this, ERROR_MESSAGE, "Cannot find file: " << fileName.c_str()
766 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Parse Config file:"
767 << fileName.c_str() << "\n");
768 // parse the dart test file
769 std::ifstream fin(fileName.c_str());
780 fin.getline(buffer, 1023);
782 std::string line = cmCTest::CleanString(buffer);
787 while ( fin && (line[line.size()-1] == '\\') )
789 line = line.substr(0, line.size()-1);
791 fin.getline(buffer, 1023);
793 line += cmCTest::CleanString(buffer);
795 if ( line[0] == '#' )
799 std::string::size_type cpos = line.find_first_of(":");
800 if ( cpos == line.npos )
804 std::string key = line.substr(0, cpos);
806 = cmCTest::CleanString(line.substr(cpos+1, line.npos));
807 this->CTestConfiguration[key] = value;
811 if ( !this->GetCTestConfiguration("BuildDirectory").empty() )
813 this->BinaryDir = this->GetCTestConfiguration("BuildDirectory");
814 cmSystemTools::ChangeDirectory(this->BinaryDir.c_str());
816 this->TimeOut = atoi(this->GetCTestConfiguration("TimeOut").c_str());
817 if ( this->ProduceXML )
819 this->CompressXMLFiles = cmSystemTools::IsOn(
820 this->GetCTestConfiguration("CompressSubmission").c_str());
825 //----------------------------------------------------------------------
826 void cmCTest::BlockTestErrorDiagnostics()
828 cmSystemTools::PutEnv("DART_TEST_FROM_DART=1");
829 cmSystemTools::PutEnv("DASHBOARD_TEST_FROM_CTEST=" CMake_VERSION);
831 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
832 #elif defined(__BEOS__) || defined(__HAIKU__)
837 //----------------------------------------------------------------------
838 void cmCTest::SetTestModel(int mode)
840 this->InteractiveDebugMode = false;
841 this->TestModel = mode;
844 //----------------------------------------------------------------------
845 bool cmCTest::SetTest(const char* ttype, bool report)
847 if ( cmSystemTools::LowerCase(ttype) == "all" )
849 for(Part p = PartStart; p != PartCount; p = Part(p+1))
851 this->Parts[p].Enable();
855 Part p = this->GetPartFromName(ttype);
858 this->Parts[p].Enable();
865 cmCTestLog(this, ERROR_MESSAGE, "Don't know about test \"" << ttype
866 << "\" yet..." << std::endl);
872 //----------------------------------------------------------------------
873 void cmCTest::Finalize()
877 //----------------------------------------------------------------------
878 bool cmCTest::OpenOutputFile(const std::string& path,
879 const std::string& name, cmGeneratedFileStream& stream,
882 std::string testingDir = this->BinaryDir + "/Testing";
883 if ( path.size() > 0 )
885 testingDir += "/" + path;
887 if ( cmSystemTools::FileExists(testingDir.c_str()) )
889 if ( !cmSystemTools::FileIsDirectory(testingDir.c_str()) )
891 cmCTestLog(this, ERROR_MESSAGE, "File " << testingDir
892 << " is in the place of the testing directory"
899 if ( !cmSystemTools::MakeDirectory(testingDir.c_str()) )
901 cmCTestLog(this, ERROR_MESSAGE, "Cannot create directory " << testingDir
906 std::string filename = testingDir + "/" + name;
907 stream.Open(filename.c_str());
910 cmCTestLog(this, ERROR_MESSAGE, "Problem opening file: " << filename
916 if ( this->CompressXMLFiles )
918 stream.SetCompression(true);
924 //----------------------------------------------------------------------
925 bool cmCTest::AddIfExists(Part part, const char* file)
927 if ( this->CTestFileExists(file) )
929 this->AddSubmitFile(part, file);
933 std::string name = file;
935 if ( this->CTestFileExists(name.c_str()) )
937 this->AddSubmitFile(part, file);
947 //----------------------------------------------------------------------
948 bool cmCTest::CTestFileExists(const std::string& filename)
950 std::string testingDir = this->BinaryDir + "/Testing/" +
951 this->CurrentTag + "/" + filename;
952 return cmSystemTools::FileExists(testingDir.c_str());
955 //----------------------------------------------------------------------
956 cmCTestGenericHandler* cmCTest::GetInitializedHandler(const char* handler)
958 cmCTest::t_TestingHandlers::iterator it =
959 this->TestingHandlers.find(handler);
960 if ( it == this->TestingHandlers.end() )
964 it->second->Initialize();
968 //----------------------------------------------------------------------
969 cmCTestGenericHandler* cmCTest::GetHandler(const char* handler)
971 cmCTest::t_TestingHandlers::iterator it =
972 this->TestingHandlers.find(handler);
973 if ( it == this->TestingHandlers.end() )
980 //----------------------------------------------------------------------
981 int cmCTest::ExecuteHandler(const char* shandler)
983 cmCTestGenericHandler* handler = this->GetHandler(shandler);
988 handler->Initialize();
989 return handler->ProcessHandler();
992 //----------------------------------------------------------------------
993 int cmCTest::ProcessTests()
997 int update_count = 0;
999 for(Part p = PartStart; notest && p != PartCount; p = Part(p+1))
1001 notest = !this->Parts[p];
1003 if (this->Parts[PartUpdate] &&
1004 (this->GetRemainingTimeAllowed() - 120 > 0))
1006 cmCTestGenericHandler* uphandler = this->GetHandler("update");
1007 uphandler->SetPersistentOption("SourceDirectory",
1008 this->GetCTestConfiguration("SourceDirectory").c_str());
1009 update_count = uphandler->ProcessHandler();
1010 if ( update_count < 0 )
1012 res |= cmCTest::UPDATE_ERRORS;
1015 if ( this->TestModel == cmCTest::CONTINUOUS && !update_count )
1019 if (this->Parts[PartConfigure] &&
1020 (this->GetRemainingTimeAllowed() - 120 > 0))
1022 if (this->GetHandler("configure")->ProcessHandler() < 0)
1024 res |= cmCTest::CONFIGURE_ERRORS;
1027 if (this->Parts[PartBuild] &&
1028 (this->GetRemainingTimeAllowed() - 120 > 0))
1030 this->UpdateCTestConfiguration();
1031 if (this->GetHandler("build")->ProcessHandler() < 0)
1033 res |= cmCTest::BUILD_ERRORS;
1036 if ((this->Parts[PartTest] || notest) &&
1037 (this->GetRemainingTimeAllowed() - 120 > 0))
1039 this->UpdateCTestConfiguration();
1040 if (this->GetHandler("test")->ProcessHandler() < 0)
1042 res |= cmCTest::TEST_ERRORS;
1045 if (this->Parts[PartCoverage] &&
1046 (this->GetRemainingTimeAllowed() - 120 > 0))
1048 this->UpdateCTestConfiguration();
1049 if (this->GetHandler("coverage")->ProcessHandler() < 0)
1051 res |= cmCTest::COVERAGE_ERRORS;
1054 if (this->Parts[PartMemCheck] &&
1055 (this->GetRemainingTimeAllowed() - 120 > 0))
1057 this->UpdateCTestConfiguration();
1058 if (this->GetHandler("memcheck")->ProcessHandler() < 0)
1060 res |= cmCTest::MEMORY_ERRORS;
1065 std::string notes_dir = this->BinaryDir + "/Testing/Notes";
1066 if ( cmSystemTools::FileIsDirectory(notes_dir.c_str()) )
1069 d.Load(notes_dir.c_str());
1071 for ( kk = 0; kk < d.GetNumberOfFiles(); kk ++ )
1073 const char* file = d.GetFile(kk);
1074 std::string fullname = notes_dir + "/" + file;
1075 if ( cmSystemTools::FileExists(fullname.c_str()) &&
1076 !cmSystemTools::FileIsDirectory(fullname.c_str()) )
1078 if ( this->NotesFiles.size() > 0 )
1080 this->NotesFiles += ";";
1082 this->NotesFiles += fullname;
1083 this->Parts[PartNotes].Enable();
1088 if (this->Parts[PartNotes])
1090 this->UpdateCTestConfiguration();
1091 if ( this->NotesFiles.size() )
1093 this->GenerateNotesFile(this->NotesFiles.c_str());
1096 if (this->Parts[PartSubmit])
1098 this->UpdateCTestConfiguration();
1099 if (this->GetHandler("submit")->ProcessHandler() < 0)
1101 res |= cmCTest::SUBMIT_ERRORS;
1106 cmCTestLog(this, ERROR_MESSAGE, "Errors while running CTest"
1112 //----------------------------------------------------------------------
1113 std::string cmCTest::GetTestModelString()
1115 if ( !this->SpecificTrack.empty() )
1117 return this->SpecificTrack;
1119 switch ( this->TestModel )
1121 case cmCTest::NIGHTLY:
1123 case cmCTest::CONTINUOUS:
1124 return "Continuous";
1126 return "Experimental";
1129 //----------------------------------------------------------------------
1130 int cmCTest::GetTestModelFromString(const char* str)
1134 return cmCTest::EXPERIMENTAL;
1136 std::string rstr = cmSystemTools::LowerCase(str);
1137 if ( strncmp(rstr.c_str(), "cont", 4) == 0 )
1139 return cmCTest::CONTINUOUS;
1141 if ( strncmp(rstr.c_str(), "nigh", 4) == 0 )
1143 return cmCTest::NIGHTLY;
1145 return cmCTest::EXPERIMENTAL;
1148 //######################################################################
1149 //######################################################################
1150 //######################################################################
1151 //######################################################################
1153 //----------------------------------------------------------------------
1154 int cmCTest::RunMakeCommand(const char* command, std::string* output,
1155 int* retVal, const char* dir, int timeout, std::ofstream& ofs)
1157 // First generate the command and arguments
1158 std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);
1165 std::vector<const char*> argv;
1166 for(std::vector<cmStdString>::const_iterator a = args.begin();
1167 a != args.end(); ++a)
1169 argv.push_back(a->c_str());
1178 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Run command:");
1179 std::vector<const char*>::iterator ait;
1180 for ( ait = argv.begin(); ait != argv.end() && *ait; ++ ait )
1182 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, " \"" << *ait << "\"");
1184 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, std::endl);
1186 // Now create process object
1187 cmsysProcess* cp = cmsysProcess_New();
1188 cmsysProcess_SetCommand(cp, &*argv.begin());
1189 cmsysProcess_SetWorkingDirectory(cp, dir);
1190 cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
1191 cmsysProcess_SetTimeout(cp, timeout);
1192 cmsysProcess_Execute(cp);
1194 // Initialize tick's
1195 std::string::size_type tick = 0;
1196 std::string::size_type tick_len = 1024;
1197 std::string::size_type tick_line_len = 50;
1201 cmCTestLog(this, HANDLER_OUTPUT,
1202 " Each . represents " << tick_len << " bytes of output" << std::endl
1203 << " " << std::flush);
1204 while(cmsysProcess_WaitForData(cp, &data, &length, 0))
1208 for(int cc =0; cc < length; ++cc)
1216 output->append(data, length);
1217 while ( output->size() > (tick * tick_len) )
1220 cmCTestLog(this, HANDLER_OUTPUT, "." << std::flush);
1221 if ( tick % tick_line_len == 0 && tick > 0 )
1223 cmCTestLog(this, HANDLER_OUTPUT, " Size: "
1224 << int((double(output->size()) / 1024.0) + 1) << "K" << std::endl
1225 << " " << std::flush);
1229 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, cmCTestLogWrite(data, length));
1232 ofs << cmCTestLogWrite(data, length);
1235 cmCTestLog(this, OUTPUT, " Size of output: "
1236 << int(double(output->size()) / 1024.0) << "K" << std::endl);
1238 cmsysProcess_WaitForExit(cp, 0);
1240 int result = cmsysProcess_GetState(cp);
1242 if(result == cmsysProcess_State_Exited)
1244 *retVal = cmsysProcess_GetExitValue(cp);
1245 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Command exited with the value: "
1246 << *retVal << std::endl);
1248 else if(result == cmsysProcess_State_Exception)
1250 *retVal = cmsysProcess_GetExitException(cp);
1251 cmCTestLog(this, WARNING, "There was an exception: " << *retVal
1254 else if(result == cmsysProcess_State_Expired)
1256 cmCTestLog(this, WARNING, "There was a timeout" << std::endl);
1258 else if(result == cmsysProcess_State_Error)
1260 *output += "\n*** ERROR executing: ";
1261 *output += cmsysProcess_GetErrorString(cp);
1262 *output += "\n***The build process failed.";
1263 cmCTestLog(this, ERROR_MESSAGE, "There was an error: "
1264 << cmsysProcess_GetErrorString(cp) << std::endl);
1267 cmsysProcess_Delete(cp);
1272 //######################################################################
1273 //######################################################################
1274 //######################################################################
1275 //######################################################################
1277 //----------------------------------------------------------------------
1278 int cmCTest::RunTest(std::vector<const char*> argv,
1279 std::string* output, int *retVal,
1280 std::ostream* log, double testTimeOut,
1281 std::vector<std::string>* environment)
1283 bool modifyEnv = (environment && environment->size()>0);
1285 // determine how much time we have
1286 double timeout = this->GetRemainingTimeAllowed() - 120;
1287 if (this->TimeOut > 0 && this->TimeOut < timeout)
1289 timeout = this->TimeOut;
1292 && testTimeOut < this->GetRemainingTimeAllowed())
1294 timeout = testTimeOut;
1297 // always have at least 1 second if we got to here
1302 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
1303 "Test timeout computed to be: " << timeout << "\n");
1304 if(cmSystemTools::SameFile(argv[0], this->CTestSelf.c_str()) &&
1305 !this->ForceNewCTestProcess)
1308 inst.ConfigType = this->ConfigType;
1309 inst.TimeOut = timeout;
1311 // Capture output of the child ctest.
1312 cmOStringStream oss;
1313 inst.SetStreams(&oss, &oss);
1315 std::vector<std::string> args;
1316 for(unsigned int i =0; i < argv.size(); ++i)
1320 // make sure we pass the timeout in for any build and test
1321 // invocations. Since --build-generator is required this is a
1322 // good place to check for it, and to add the arguments in
1323 if (strcmp(argv[i],"--build-generator") == 0 && timeout > 0)
1325 args.push_back("--test-timeout");
1326 cmOStringStream msg;
1328 args.push_back(msg.str());
1330 args.push_back(argv[i]);
1335 *log << "* Run internal CTest" << std::endl;
1337 std::string oldpath = cmSystemTools::GetCurrentWorkingDirectory();
1339 cmsys::auto_ptr<cmSystemTools::SaveRestoreEnvironment> saveEnv;
1342 saveEnv.reset(new cmSystemTools::SaveRestoreEnvironment);
1343 cmSystemTools::AppendEnv(*environment);
1346 *retVal = inst.Run(args, output);
1347 *output += oss.str();
1350 *log << output->c_str();
1352 cmSystemTools::ChangeDirectory(oldpath.c_str());
1354 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
1355 "Internal cmCTest object used to run test." << std::endl
1356 << *output << std::endl);
1358 return cmsysProcess_State_Exited;
1360 std::vector<char> tempOutput;
1366 cmsys::auto_ptr<cmSystemTools::SaveRestoreEnvironment> saveEnv;
1369 saveEnv.reset(new cmSystemTools::SaveRestoreEnvironment);
1370 cmSystemTools::AppendEnv(*environment);
1373 cmsysProcess* cp = cmsysProcess_New();
1374 cmsysProcess_SetCommand(cp, &*argv.begin());
1375 cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
1376 if(cmSystemTools::GetRunCommandHideConsole())
1378 cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
1381 cmsysProcess_SetTimeout(cp, timeout);
1382 cmsysProcess_Execute(cp);
1386 while(cmsysProcess_WaitForData(cp, &data, &length, 0))
1390 tempOutput.insert(tempOutput.end(), data, data+length);
1392 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, cmCTestLogWrite(data, length));
1395 log->write(data, length);
1399 cmsysProcess_WaitForExit(cp, 0);
1400 if(output && tempOutput.begin() != tempOutput.end())
1402 output->append(&*tempOutput.begin(), tempOutput.size());
1404 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "-- Process completed"
1407 int result = cmsysProcess_GetState(cp);
1409 if(result == cmsysProcess_State_Exited)
1411 *retVal = cmsysProcess_GetExitValue(cp);
1412 if(*retVal != 0 && this->OutputTestOutputOnTestFailure)
1414 OutputTestErrors(tempOutput);
1417 else if(result == cmsysProcess_State_Exception)
1419 if(this->OutputTestOutputOnTestFailure)
1421 OutputTestErrors(tempOutput);
1423 *retVal = cmsysProcess_GetExitException(cp);
1424 std::string outerr = "\n*** Exception executing: ";
1425 outerr += cmsysProcess_GetExceptionString(cp);
1427 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr.c_str() << std::endl
1430 else if(result == cmsysProcess_State_Error)
1432 std::string outerr = "\n*** ERROR executing: ";
1433 outerr += cmsysProcess_GetErrorString(cp);
1435 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr.c_str() << std::endl
1438 cmsysProcess_Delete(cp);
1443 //----------------------------------------------------------------------
1444 std::string cmCTest::SafeBuildIdField(const std::string& value)
1446 std::string safevalue(value);
1448 if (safevalue != "")
1450 // Disallow non-filename and non-space whitespace characters.
1451 // If they occur, replace them with ""
1453 const char *disallowed = "\\/:*?\"<>|\n\r\t\f\v";
1455 if (safevalue.find_first_of(disallowed) != value.npos)
1457 std::string::size_type i = 0;
1458 std::string::size_type n = strlen(disallowed);
1462 for (i= 0; i<n; ++i)
1464 replace[0] = disallowed[i];
1465 cmSystemTools::ReplaceString(safevalue, replace, "");
1469 safevalue = cmXMLSafe(safevalue).str();
1472 if (safevalue == "")
1474 safevalue = "(empty)";
1480 //----------------------------------------------------------------------
1481 void cmCTest::StartXML(std::ostream& ostr, bool append)
1483 if(this->CurrentTag.empty())
1485 cmCTestLog(this, ERROR_MESSAGE,
1486 "Current Tag empty, this may mean"
1487 " NightlStartTime was not set correctly." << std::endl);
1488 cmSystemTools::SetFatalErrorOccured();
1491 // find out about the system
1492 cmsys::SystemInformation info;
1495 info.RunMemoryCheck();
1497 std::string buildname = cmCTest::SafeBuildIdField(
1498 this->GetCTestConfiguration("BuildName"));
1499 std::string stamp = cmCTest::SafeBuildIdField(
1500 this->CurrentTag + "-" + this->GetTestModelString());
1501 std::string site = cmCTest::SafeBuildIdField(
1502 this->GetCTestConfiguration("Site"));
1504 ostr << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1505 << "<Site BuildName=\"" << buildname << "\"\n"
1506 << "\tBuildStamp=\"" << stamp << "\"\n"
1507 << "\tName=\"" << site << "\"\n"
1508 << "\tGenerator=\"ctest-" << cmVersion::GetCMakeVersion() << "\"\n"
1509 << (append? "\tAppend=\"true\"\n":"")
1510 << "\tCompilerName=\"" << this->GetCTestConfiguration("Compiler")
1512 #ifdef _COMPILER_VERSION
1513 << "\tCompilerVersion=\"_COMPILER_VERSION\"\n"
1515 << "\tOSName=\"" << info.GetOSName() << "\"\n"
1516 << "\tHostname=\"" << info.GetHostname() << "\"\n"
1517 << "\tOSRelease=\"" << info.GetOSRelease() << "\"\n"
1518 << "\tOSVersion=\"" << info.GetOSVersion() << "\"\n"
1519 << "\tOSPlatform=\"" << info.GetOSPlatform() << "\"\n"
1520 << "\tIs64Bits=\"" << info.Is64Bits() << "\"\n"
1521 << "\tVendorString=\"" << info.GetVendorString() << "\"\n"
1522 << "\tVendorID=\"" << info.GetVendorID() << "\"\n"
1523 << "\tFamilyID=\"" << info.GetFamilyID() << "\"\n"
1524 << "\tModelID=\"" << info.GetModelID() << "\"\n"
1525 << "\tProcessorCacheSize=\"" << info.GetProcessorCacheSize() << "\"\n"
1526 << "\tNumberOfLogicalCPU=\"" << info.GetNumberOfLogicalCPU() << "\"\n"
1527 << "\tNumberOfPhysicalCPU=\""<< info.GetNumberOfPhysicalCPU() << "\"\n"
1528 << "\tTotalVirtualMemory=\"" << info.GetTotalVirtualMemory() << "\"\n"
1529 << "\tTotalPhysicalMemory=\""<< info.GetTotalPhysicalMemory() << "\"\n"
1530 << "\tLogicalProcessorsPerPhysical=\""
1531 << info.GetLogicalProcessorsPerPhysical() << "\"\n"
1532 << "\tProcessorClockFrequency=\""
1533 << info.GetProcessorClockFrequency() << "\"\n"
1534 << ">" << std::endl;
1535 this->AddSiteProperties(ostr);
1538 //----------------------------------------------------------------------
1539 void cmCTest::AddSiteProperties(std::ostream& ostr)
1541 cmCTestScriptHandler* ch =
1542 static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
1543 cmake* cm = ch->GetCMake();
1544 // if no CMake then this is the old style script and props like
1545 // this will not work anyway.
1550 // This code should go when cdash is changed to use labels only
1551 const char* subproject = cm->GetProperty("SubProject", cmProperty::GLOBAL);
1554 ostr << "<Subproject name=\"" << subproject << "\">\n";
1555 const char* labels =
1556 ch->GetCMake()->GetProperty("SubProjectLabels", cmProperty::GLOBAL);
1559 ostr << " <Labels>\n";
1560 std::string l = labels;
1561 std::vector<std::string> args;
1562 cmSystemTools::ExpandListArgument(l, args);
1563 for(std::vector<std::string>::iterator i = args.begin();
1564 i != args.end(); ++i)
1566 ostr << " <Label>" << i->c_str() << "</Label>\n";
1568 ostr << " </Labels>\n";
1570 ostr << "</Subproject>\n";
1573 // This code should stay when cdash only does label based sub-projects
1574 const char* label = cm->GetProperty("Label", cmProperty::GLOBAL);
1577 ostr << "<Labels>\n";
1578 ostr << " <Label>" << label << "</Label>\n";
1579 ostr << "</Labels>\n";
1584 //----------------------------------------------------------------------
1585 void cmCTest::EndXML(std::ostream& ostr)
1587 ostr << "</Site>" << std::endl;
1590 //----------------------------------------------------------------------
1591 int cmCTest::GenerateCTestNotesOutput(std::ostream& os,
1592 const cmCTest::VectorOfStrings& files)
1594 cmCTest::VectorOfStrings::const_iterator it;
1595 os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1596 << "<?xml-stylesheet type=\"text/xsl\" "
1597 "href=\"Dart/Source/Server/XSL/Build.xsl "
1598 "<file:///Dart/Source/Server/XSL/Build.xsl> \"?>\n"
1599 << "<Site BuildName=\"" << this->GetCTestConfiguration("BuildName")
1600 << "\" BuildStamp=\""
1601 << this->CurrentTag << "-" << this->GetTestModelString() << "\" Name=\""
1602 << this->GetCTestConfiguration("Site") << "\" Generator=\"ctest"
1603 << cmVersion::GetCMakeVersion()
1605 this->AddSiteProperties(os);
1606 os << "<Notes>" << std::endl;
1608 for ( it = files.begin(); it != files.end(); it ++ )
1610 cmCTestLog(this, OUTPUT, "\tAdd file: " << it->c_str() << std::endl);
1611 std::string note_time = this->CurrentTime();
1612 os << "<Note Name=\"" << cmXMLSafe(*it) << "\">\n"
1613 << "<Time>" << cmSystemTools::GetTime() << "</Time>\n"
1614 << "<DateTime>" << note_time << "</DateTime>\n"
1615 << "<Text>" << std::endl;
1616 std::ifstream ifs(it->c_str());
1620 while ( cmSystemTools::GetLineFromStream(ifs, line) )
1622 os << cmXMLSafe(line) << std::endl;
1628 os << "Problem reading file: " << it->c_str() << std::endl;
1629 cmCTestLog(this, ERROR_MESSAGE, "Problem reading file: " << it->c_str()
1630 << " while creating notes" << std::endl);
1633 << "</Note>" << std::endl;
1636 << "</Site>" << std::endl;
1640 //----------------------------------------------------------------------
1641 int cmCTest::GenerateNotesFile(const std::vector<cmStdString> &files)
1643 cmGeneratedFileStream ofs;
1644 if ( !this->OpenOutputFile(this->CurrentTag, "Notes.xml", ofs) )
1646 cmCTestLog(this, ERROR_MESSAGE, "Cannot open notes file" << std::endl);
1650 this->GenerateCTestNotesOutput(ofs, files);
1654 //----------------------------------------------------------------------
1655 int cmCTest::GenerateNotesFile(const char* cfiles)
1662 std::vector<cmStdString> files;
1664 cmCTestLog(this, OUTPUT, "Create notes file" << std::endl);
1666 files = cmSystemTools::SplitString(cfiles, ';');
1667 if ( files.size() == 0 )
1672 return this->GenerateNotesFile(files);
1675 //----------------------------------------------------------------------
1676 std::string cmCTest::Base64GzipEncodeFile(std::string file)
1678 std::string tarFile = file + "_temp.tar.gz";
1679 std::vector<cmStdString> files;
1680 files.push_back(file);
1682 if(!cmSystemTools::CreateTar(tarFile.c_str(), files, true, false, false))
1684 cmCTestLog(this, ERROR_MESSAGE, "Error creating tar while "
1685 "encoding file: " << file << std::endl);
1688 std::string base64 = this->Base64EncodeFile(tarFile);
1689 cmSystemTools::RemoveFile(tarFile.c_str());
1693 //----------------------------------------------------------------------
1694 std::string cmCTest::Base64EncodeFile(std::string file)
1696 long len = cmSystemTools::FileLength(file.c_str());
1697 std::ifstream ifs(file.c_str(), std::ios::in
1702 unsigned char *file_buffer = new unsigned char [ len + 1 ];
1703 ifs.read(reinterpret_cast<char*>(file_buffer), len);
1706 unsigned char *encoded_buffer
1707 = new unsigned char [ static_cast<int>(
1708 static_cast<double>(len) * 1.5 + 5.0) ];
1711 = cmsysBase64_Encode(file_buffer, len, encoded_buffer, 1);
1713 std::string base64 = "";
1714 for(unsigned long i = 0; i < rlen; i++)
1716 base64 += encoded_buffer[i];
1718 delete [] file_buffer;
1719 delete [] encoded_buffer;
1725 //----------------------------------------------------------------------
1726 bool cmCTest::SubmitExtraFiles(const std::vector<cmStdString> &files)
1728 std::vector<cmStdString>::const_iterator it;
1729 for ( it = files.begin();
1733 if ( !cmSystemTools::FileExists(it->c_str()) )
1735 cmCTestLog(this, ERROR_MESSAGE, "Cannot find extra file: "
1736 << it->c_str() << " to submit."
1740 this->AddSubmitFile(PartExtraFiles, it->c_str());
1745 //----------------------------------------------------------------------
1746 bool cmCTest::SubmitExtraFiles(const char* cfiles)
1753 std::vector<cmStdString> files;
1755 cmCTestLog(this, OUTPUT, "Submit extra files" << std::endl);
1757 files = cmSystemTools::SplitString(cfiles, ';');
1758 if ( files.size() == 0 )
1763 return this->SubmitExtraFiles(files);
1767 //-------------------------------------------------------
1768 // for a -D argument convert the next argument into
1769 // the proper list of dashboard steps via SetTest
1770 bool cmCTest::AddTestsForDashboardType(std::string &targ)
1772 if ( targ == "Experimental" )
1774 this->SetTestModel(cmCTest::EXPERIMENTAL);
1775 this->SetTest("Start");
1776 this->SetTest("Configure");
1777 this->SetTest("Build");
1778 this->SetTest("Test");
1779 this->SetTest("Coverage");
1780 this->SetTest("Submit");
1782 else if ( targ == "ExperimentalStart" )
1784 this->SetTestModel(cmCTest::EXPERIMENTAL);
1785 this->SetTest("Start");
1787 else if ( targ == "ExperimentalUpdate" )
1789 this->SetTestModel(cmCTest::EXPERIMENTAL);
1790 this->SetTest("Update");
1792 else if ( targ == "ExperimentalConfigure" )
1794 this->SetTestModel(cmCTest::EXPERIMENTAL);
1795 this->SetTest("Configure");
1797 else if ( targ == "ExperimentalBuild" )
1799 this->SetTestModel(cmCTest::EXPERIMENTAL);
1800 this->SetTest("Build");
1802 else if ( targ == "ExperimentalTest" )
1804 this->SetTestModel(cmCTest::EXPERIMENTAL);
1805 this->SetTest("Test");
1807 else if ( targ == "ExperimentalMemCheck"
1808 || targ == "ExperimentalPurify" )
1810 this->SetTestModel(cmCTest::EXPERIMENTAL);
1811 this->SetTest("MemCheck");
1813 else if ( targ == "ExperimentalCoverage" )
1815 this->SetTestModel(cmCTest::EXPERIMENTAL);
1816 this->SetTest("Coverage");
1818 else if ( targ == "ExperimentalSubmit" )
1820 this->SetTestModel(cmCTest::EXPERIMENTAL);
1821 this->SetTest("Submit");
1823 else if ( targ == "Continuous" )
1825 this->SetTestModel(cmCTest::CONTINUOUS);
1826 this->SetTest("Start");
1827 this->SetTest("Update");
1828 this->SetTest("Configure");
1829 this->SetTest("Build");
1830 this->SetTest("Test");
1831 this->SetTest("Coverage");
1832 this->SetTest("Submit");
1834 else if ( targ == "ContinuousStart" )
1836 this->SetTestModel(cmCTest::CONTINUOUS);
1837 this->SetTest("Start");
1839 else if ( targ == "ContinuousUpdate" )
1841 this->SetTestModel(cmCTest::CONTINUOUS);
1842 this->SetTest("Update");
1844 else if ( targ == "ContinuousConfigure" )
1846 this->SetTestModel(cmCTest::CONTINUOUS);
1847 this->SetTest("Configure");
1849 else if ( targ == "ContinuousBuild" )
1851 this->SetTestModel(cmCTest::CONTINUOUS);
1852 this->SetTest("Build");
1854 else if ( targ == "ContinuousTest" )
1856 this->SetTestModel(cmCTest::CONTINUOUS);
1857 this->SetTest("Test");
1859 else if ( targ == "ContinuousMemCheck"
1860 || targ == "ContinuousPurify" )
1862 this->SetTestModel(cmCTest::CONTINUOUS);
1863 this->SetTest("MemCheck");
1865 else if ( targ == "ContinuousCoverage" )
1867 this->SetTestModel(cmCTest::CONTINUOUS);
1868 this->SetTest("Coverage");
1870 else if ( targ == "ContinuousSubmit" )
1872 this->SetTestModel(cmCTest::CONTINUOUS);
1873 this->SetTest("Submit");
1875 else if ( targ == "Nightly" )
1877 this->SetTestModel(cmCTest::NIGHTLY);
1878 this->SetTest("Start");
1879 this->SetTest("Update");
1880 this->SetTest("Configure");
1881 this->SetTest("Build");
1882 this->SetTest("Test");
1883 this->SetTest("Coverage");
1884 this->SetTest("Submit");
1886 else if ( targ == "NightlyStart" )
1888 this->SetTestModel(cmCTest::NIGHTLY);
1889 this->SetTest("Start");
1891 else if ( targ == "NightlyUpdate" )
1893 this->SetTestModel(cmCTest::NIGHTLY);
1894 this->SetTest("Update");
1896 else if ( targ == "NightlyConfigure" )
1898 this->SetTestModel(cmCTest::NIGHTLY);
1899 this->SetTest("Configure");
1901 else if ( targ == "NightlyBuild" )
1903 this->SetTestModel(cmCTest::NIGHTLY);
1904 this->SetTest("Build");
1906 else if ( targ == "NightlyTest" )
1908 this->SetTestModel(cmCTest::NIGHTLY);
1909 this->SetTest("Test");
1911 else if ( targ == "NightlyMemCheck"
1912 || targ == "NightlyPurify" )
1914 this->SetTestModel(cmCTest::NIGHTLY);
1915 this->SetTest("MemCheck");
1917 else if ( targ == "NightlyCoverage" )
1919 this->SetTestModel(cmCTest::NIGHTLY);
1920 this->SetTest("Coverage");
1922 else if ( targ == "NightlySubmit" )
1924 this->SetTestModel(cmCTest::NIGHTLY);
1925 this->SetTest("Submit");
1927 else if ( targ == "MemoryCheck" )
1929 this->SetTestModel(cmCTest::EXPERIMENTAL);
1930 this->SetTest("Start");
1931 this->SetTest("Configure");
1932 this->SetTest("Build");
1933 this->SetTest("MemCheck");
1934 this->SetTest("Coverage");
1935 this->SetTest("Submit");
1937 else if ( targ == "NightlyMemoryCheck" )
1939 this->SetTestModel(cmCTest::NIGHTLY);
1940 this->SetTest("Start");
1941 this->SetTest("Update");
1942 this->SetTest("Configure");
1943 this->SetTest("Build");
1944 this->SetTest("MemCheck");
1945 this->SetTest("Coverage");
1946 this->SetTest("Submit");
1956 //----------------------------------------------------------------------
1957 void cmCTest::ErrorMessageUnknownDashDValue(std::string &val)
1959 cmCTestLog(this, ERROR_MESSAGE,
1960 "CTest -D called with incorrect option: " << val << std::endl);
1962 cmCTestLog(this, ERROR_MESSAGE,
1963 "Available options are:" << std::endl
1964 << " ctest -D Continuous" << std::endl
1965 << " ctest -D Continuous(Start|Update|Configure|Build)" << std::endl
1966 << " ctest -D Continuous(Test|Coverage|MemCheck|Submit)" << std::endl
1967 << " ctest -D Experimental" << std::endl
1968 << " ctest -D Experimental(Start|Update|Configure|Build)" << std::endl
1969 << " ctest -D Experimental(Test|Coverage|MemCheck|Submit)" << std::endl
1970 << " ctest -D Nightly" << std::endl
1971 << " ctest -D Nightly(Start|Update|Configure|Build)" << std::endl
1972 << " ctest -D Nightly(Test|Coverage|MemCheck|Submit)" << std::endl
1973 << " ctest -D NightlyMemoryCheck" << std::endl);
1977 //----------------------------------------------------------------------
1978 bool cmCTest::CheckArgument(const std::string& arg, const char* varg1,
1981 return (varg1 && arg == varg1) || (varg2 && arg == varg2);
1985 //----------------------------------------------------------------------
1986 // Processes one command line argument (and its arguments if any)
1987 // for many simple options and then returns
1988 void cmCTest::HandleCommandLineArguments(size_t &i,
1989 std::vector<std::string> &args)
1991 std::string arg = args[i];
1993 if(this->CheckArgument(arg, "-F"))
1995 this->Failover = true;
1997 if(this->CheckArgument(arg, "-j", "--parallel") && i < args.size() - 1)
2000 int plevel = atoi(args[i].c_str());
2001 this->SetParallelLevel(plevel);
2003 else if(arg.find("-j") == 0)
2005 int plevel = atoi(arg.substr(2).c_str());
2006 this->SetParallelLevel(plevel);
2009 if(this->CheckArgument(arg, "--no-compress-output"))
2011 this->CompressTestOutput = false;
2012 this->CompressMemCheckOutput = false;
2015 if(this->CheckArgument(arg, "--print-labels"))
2017 this->PrintLabels = true;
2020 if(this->CheckArgument(arg, "--http1.0"))
2022 this->UseHTTP10 = true;
2025 if(this->CheckArgument(arg, "--timeout") && i < args.size() - 1)
2028 double timeout = (double)atof(args[i].c_str());
2029 this->GlobalTimeout = timeout;
2032 if(this->CheckArgument(arg, "--stop-time") && i < args.size() - 1)
2035 this->SetStopTime(args[i]);
2038 if(this->CheckArgument(arg, "-C", "--build-config") &&
2039 i < args.size() - 1)
2042 this->SetConfigType(args[i].c_str());
2045 if(this->CheckArgument(arg, "--debug"))
2048 this->ShowLineNumbers = true;
2050 if(this->CheckArgument(arg, "--track") && i < args.size() - 1)
2053 this->SpecificTrack = args[i];
2055 if(this->CheckArgument(arg, "--show-line-numbers"))
2057 this->ShowLineNumbers = true;
2059 if(this->CheckArgument(arg, "--no-label-summary"))
2061 this->LabelSummary = false;
2063 if(this->CheckArgument(arg, "-Q", "--quiet"))
2067 if(this->CheckArgument(arg, "-V", "--verbose"))
2069 this->Verbose = true;
2071 if(this->CheckArgument(arg, "-B"))
2073 this->BatchJobs = true;
2075 if(this->CheckArgument(arg, "-VV", "--extra-verbose"))
2077 this->ExtraVerbose = true;
2078 this->Verbose = true;
2080 if(this->CheckArgument(arg, "--output-on-failure"))
2082 this->OutputTestOutputOnTestFailure = true;
2085 if(this->CheckArgument(arg, "-N", "--show-only"))
2087 this->ShowOnly = true;
2090 if(this->CheckArgument(arg, "-O", "--output-log") && i < args.size() - 1 )
2093 this->SetOutputLogFileName(args[i].c_str());
2096 if(this->CheckArgument(arg, "--tomorrow-tag"))
2098 this->TomorrowTag = true;
2100 if(this->CheckArgument(arg, "--force-new-ctest-process"))
2102 this->ForceNewCTestProcess = true;
2104 if(this->CheckArgument(arg, "-W", "--max-width") && i < args.size() - 1)
2107 this->MaxTestNameWidth = atoi(args[i].c_str());
2109 if(this->CheckArgument(arg, "--interactive-debug-mode") &&
2110 i < args.size() - 1 )
2113 this->InteractiveDebugMode = cmSystemTools::IsOn(args[i].c_str());
2115 if(this->CheckArgument(arg, "--submit-index") && i < args.size() - 1 )
2118 this->SubmitIndex = atoi(args[i].c_str());
2119 if ( this->SubmitIndex < 0 )
2121 this->SubmitIndex = 0;
2125 if(this->CheckArgument(arg, "--overwrite") && i < args.size() - 1)
2128 this->AddCTestConfigurationOverwrite(args[i].c_str());
2130 if(this->CheckArgument(arg, "-A", "--add-notes") && i < args.size() - 1)
2132 this->ProduceXML = true;
2133 this->SetTest("Notes");
2135 this->SetNotesFiles(args[i].c_str());
2138 // options that control what tests are run
2139 if(this->CheckArgument(arg, "-I", "--tests-information") &&
2140 i < args.size() - 1)
2143 this->GetHandler("test")->SetPersistentOption("TestsToRunInformation",
2145 this->GetHandler("memcheck")->
2146 SetPersistentOption("TestsToRunInformation",args[i].c_str());
2148 if(this->CheckArgument(arg, "-U", "--union"))
2150 this->GetHandler("test")->SetPersistentOption("UseUnion", "true");
2151 this->GetHandler("memcheck")->SetPersistentOption("UseUnion", "true");
2153 if(this->CheckArgument(arg, "-R", "--tests-regex") && i < args.size() - 1)
2156 this->GetHandler("test")->
2157 SetPersistentOption("IncludeRegularExpression", args[i].c_str());
2158 this->GetHandler("memcheck")->
2159 SetPersistentOption("IncludeRegularExpression", args[i].c_str());
2161 if(this->CheckArgument(arg, "-L", "--label-regex") && i < args.size() - 1)
2164 this->GetHandler("test")->
2165 SetPersistentOption("LabelRegularExpression", args[i].c_str());
2166 this->GetHandler("memcheck")->
2167 SetPersistentOption("LabelRegularExpression", args[i].c_str());
2169 if(this->CheckArgument(arg, "-LE", "--label-exclude") && i < args.size() - 1)
2172 this->GetHandler("test")->
2173 SetPersistentOption("ExcludeLabelRegularExpression", args[i].c_str());
2174 this->GetHandler("memcheck")->
2175 SetPersistentOption("ExcludeLabelRegularExpression", args[i].c_str());
2178 if(this->CheckArgument(arg, "-E", "--exclude-regex") &&
2179 i < args.size() - 1)
2182 this->GetHandler("test")->
2183 SetPersistentOption("ExcludeRegularExpression", args[i].c_str());
2184 this->GetHandler("memcheck")->
2185 SetPersistentOption("ExcludeRegularExpression", args[i].c_str());
2189 //----------------------------------------------------------------------
2190 // handle the -S -SR and -SP arguments
2191 void cmCTest::HandleScriptArguments(size_t &i,
2192 std::vector<std::string> &args,
2193 bool &SRArgumentSpecified)
2195 std::string arg = args[i];
2196 if(this->CheckArgument(arg, "-SP", "--script-new-process") &&
2197 i < args.size() - 1 )
2199 this->RunConfigurationScript = true;
2201 cmCTestScriptHandler* ch
2202 = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
2203 // -SR is an internal argument, -SP should be ignored when it is passed
2204 if (!SRArgumentSpecified)
2206 ch->AddConfigurationScript(args[i].c_str(),false);
2210 if(this->CheckArgument(arg, "-SR", "--script-run") &&
2211 i < args.size() - 1 )
2213 SRArgumentSpecified = true;
2214 this->RunConfigurationScript = true;
2216 cmCTestScriptHandler* ch
2217 = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
2218 ch->AddConfigurationScript(args[i].c_str(),true);
2221 if(this->CheckArgument(arg, "-S", "--script") && i < args.size() - 1 )
2223 this->RunConfigurationScript = true;
2225 cmCTestScriptHandler* ch
2226 = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
2227 // -SR is an internal argument, -S should be ignored when it is passed
2228 if (!SRArgumentSpecified)
2230 ch->AddConfigurationScript(args[i].c_str(),true);
2235 //----------------------------------------------------------------------
2236 bool cmCTest::AddVariableDefinition(const std::string &arg)
2240 cmCacheManager::CacheEntryType type = cmCacheManager::UNINITIALIZED;
2242 if (cmCacheManager::ParseEntry(arg.c_str(), name, value, type))
2244 this->Definitions[name] = value;
2251 //----------------------------------------------------------------------
2252 // the main entry point of ctest, called from main
2253 int cmCTest::Run(std::vector<std::string> &args, std::string* output)
2255 this->FindRunningCMake();
2256 const char* ctestExec = "ctest";
2257 bool cmakeAndTest = false;
2258 bool executeTests = true;
2259 bool SRArgumentSpecified = false;
2261 // copy the command line
2262 for(size_t i=0; i < args.size(); ++i)
2264 this->InitialCommandLineArguments.push_back(args[i]);
2267 // process the command line arguments
2268 for(size_t i=1; i < args.size(); ++i)
2270 // handle the simple commandline arguments
2271 this->HandleCommandLineArguments(i,args);
2273 // handle the script arguments -S -SR -SP
2274 this->HandleScriptArguments(i,args,SRArgumentSpecified);
2276 // handle a request for a dashboard
2277 std::string arg = args[i];
2278 if(this->CheckArgument(arg, "-D", "--dashboard") && i < args.size() - 1 )
2280 this->ProduceXML = true;
2282 std::string targ = args[i];
2283 // AddTestsForDashboard parses the dashboard type and converts it
2284 // into the separate stages
2285 if (!this->AddTestsForDashboardType(targ))
2287 if (!this->AddVariableDefinition(targ))
2289 this->ErrorMessageUnknownDashDValue(targ);
2290 executeTests = false;
2295 // If it's not exactly -D, but it starts with -D, then try to parse out
2296 // a variable definition from it, same as CMake does. Unsuccessful
2297 // attempts are simply ignored since previous ctest versions ignore
2298 // this too. (As well as many other unknown command line args.)
2300 if(arg != "-D" && cmSystemTools::StringStartsWith(arg.c_str(), "-D"))
2302 std::string input = arg.substr(2);
2303 this->AddVariableDefinition(input);
2306 if(this->CheckArgument(arg, "-T", "--test-action") &&
2307 (i < args.size() -1) )
2309 this->ProduceXML = true;
2311 if ( !this->SetTest(args[i].c_str(), false) )
2313 executeTests = false;
2314 cmCTestLog(this, ERROR_MESSAGE,
2315 "CTest -T called with incorrect option: "
2316 << args[i].c_str() << std::endl);
2317 cmCTestLog(this, ERROR_MESSAGE, "Available options are:" << std::endl
2318 << " " << ctestExec << " -T all" << std::endl
2319 << " " << ctestExec << " -T start" << std::endl
2320 << " " << ctestExec << " -T update" << std::endl
2321 << " " << ctestExec << " -T configure" << std::endl
2322 << " " << ctestExec << " -T build" << std::endl
2323 << " " << ctestExec << " -T test" << std::endl
2324 << " " << ctestExec << " -T coverage" << std::endl
2325 << " " << ctestExec << " -T memcheck" << std::endl
2326 << " " << ctestExec << " -T notes" << std::endl
2327 << " " << ctestExec << " -T submit" << std::endl);
2331 // what type of test model
2332 if(this->CheckArgument(arg, "-M", "--test-model") &&
2333 (i < args.size() -1) )
2336 std::string const& str = args[i];
2337 if ( cmSystemTools::LowerCase(str) == "nightly" )
2339 this->SetTestModel(cmCTest::NIGHTLY);
2341 else if ( cmSystemTools::LowerCase(str) == "continuous" )
2343 this->SetTestModel(cmCTest::CONTINUOUS);
2345 else if ( cmSystemTools::LowerCase(str) == "experimental" )
2347 this->SetTestModel(cmCTest::EXPERIMENTAL);
2351 executeTests = false;
2352 cmCTestLog(this, ERROR_MESSAGE,
2353 "CTest -M called with incorrect option: " << str.c_str()
2355 cmCTestLog(this, ERROR_MESSAGE, "Available options are:" << std::endl
2356 << " " << ctestExec << " -M Continuous" << std::endl
2357 << " " << ctestExec << " -M Experimental" << std::endl
2358 << " " << ctestExec << " -M Nightly" << std::endl);
2362 if(this->CheckArgument(arg, "--extra-submit") && i < args.size() - 1)
2364 this->ProduceXML = true;
2365 this->SetTest("Submit");
2367 if ( !this->SubmitExtraFiles(args[i].c_str()) )
2373 // --build-and-test options
2374 if(this->CheckArgument(arg, "--build-and-test") && i < args.size() - 1)
2376 cmakeAndTest = true;
2379 if(this->CheckArgument(arg, "--schedule-random"))
2381 this->ScheduleType = "Random";
2384 // pass the argument to all the handlers as well, but i may no longer be
2385 // set to what it was originally so I'm not sure this is working as
2387 cmCTest::t_TestingHandlers::iterator it;
2388 for ( it = this->TestingHandlers.begin();
2389 it != this->TestingHandlers.end();
2392 if ( !it->second->ProcessCommandLineArguments(arg, i, args) )
2394 cmCTestLog(this, ERROR_MESSAGE,
2395 "Problem parsing command line arguments within a handler");
2399 } // the close of the for argument loop
2402 // now what sould cmake do? if --build-and-test was specified then
2403 // we run the build and test handler and return
2406 this->Verbose = true;
2407 cmCTestBuildAndTestHandler* handler =
2408 static_cast<cmCTestBuildAndTestHandler*>(this->GetHandler("buildtest"));
2409 int retv = handler->ProcessHandler();
2410 *output = handler->GetOutput();
2411 #ifdef CMAKE_BUILD_WITH_CMAKE
2412 cmDynamicLoader::FlushCache();
2416 cmCTestLog(this, DEBUG, "build and test failing returing: " << retv
2425 // call process directory
2426 if (this->RunConfigurationScript)
2428 if ( this->ExtraVerbose )
2430 cmCTestLog(this, OUTPUT, "* Extra verbosity turned on" << std::endl);
2432 cmCTest::t_TestingHandlers::iterator it;
2433 for ( it = this->TestingHandlers.begin();
2434 it != this->TestingHandlers.end();
2437 it->second->SetVerbose(this->ExtraVerbose);
2438 it->second->SetSubmitIndex(this->SubmitIndex);
2440 this->GetHandler("script")->SetVerbose(this->Verbose);
2441 res = this->GetHandler("script")->ProcessHandler();
2444 cmCTestLog(this, DEBUG, "running script failing returning: " << res
2451 // What is this? -V seems to be the same as -VV,
2452 // and Verbose is always on in this case
2453 this->ExtraVerbose = this->Verbose;
2454 this->Verbose = true;
2455 cmCTest::t_TestingHandlers::iterator it;
2456 for ( it = this->TestingHandlers.begin();
2457 it != this->TestingHandlers.end();
2460 it->second->SetVerbose(this->Verbose);
2461 it->second->SetSubmitIndex(this->SubmitIndex);
2463 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
2464 if(!this->Initialize(cwd.c_str(), 0))
2467 cmCTestLog(this, ERROR_MESSAGE, "Problem initializing the dashboard."
2472 res = this->ProcessTests();
2478 cmCTestLog(this, DEBUG, "Running a test(s) failed returning : " << res
2487 //----------------------------------------------------------------------
2488 void cmCTest::FindRunningCMake()
2490 // Find our own executable.
2491 this->CTestSelf = cmSystemTools::GetExecutableDirectory();
2492 this->CTestSelf += "/ctest";
2493 this->CTestSelf += cmSystemTools::GetExecutableExtension();
2494 if(!cmSystemTools::FileExists(this->CTestSelf.c_str()))
2496 cmSystemTools::Error("CTest executable cannot be found at ",
2497 this->CTestSelf.c_str());
2500 this->CMakeSelf = cmSystemTools::GetExecutableDirectory();
2501 this->CMakeSelf += "/cmake";
2502 this->CMakeSelf += cmSystemTools::GetExecutableExtension();
2503 if(!cmSystemTools::FileExists(this->CMakeSelf.c_str()))
2505 cmSystemTools::Error("CMake executable cannot be found at ",
2506 this->CMakeSelf.c_str());
2510 //----------------------------------------------------------------------
2511 void cmCTest::SetNotesFiles(const char* notes)
2517 this->NotesFiles = notes;
2520 //----------------------------------------------------------------------
2521 void cmCTest::SetStopTime(std::string time)
2523 this->StopTime = time;
2524 this->DetermineNextDayStop();
2527 //----------------------------------------------------------------------
2528 int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf)
2531 VectorOfStrings dirs;
2532 VectorOfStrings ndirs;
2533 cmCTestLog(this, DEBUG, "* Read custom CTest configuration directory: "
2534 << dir << std::endl);
2536 std::string fname = dir;
2537 fname += "/CTestCustom.cmake";
2538 cmCTestLog(this, DEBUG, "* Check for file: "
2539 << fname.c_str() << std::endl);
2540 if ( cmSystemTools::FileExists(fname.c_str()) )
2542 cmCTestLog(this, DEBUG, "* Read custom CTest configuration file: "
2543 << fname.c_str() << std::endl);
2544 bool erroroc = cmSystemTools::GetErrorOccuredFlag();
2545 cmSystemTools::ResetErrorOccuredFlag();
2547 if ( !mf->ReadListFile(0, fname.c_str()) ||
2548 cmSystemTools::GetErrorOccuredFlag() )
2550 cmCTestLog(this, ERROR_MESSAGE,
2551 "Problem reading custom configuration: "
2552 << fname.c_str() << std::endl);
2557 cmSystemTools::SetErrorOccured();
2561 std::string rexpr = dir;
2562 rexpr += "/CTestCustom.ctest";
2563 cmCTestLog(this, DEBUG, "* Check for file: "
2564 << rexpr.c_str() << std::endl);
2565 if ( !found && cmSystemTools::FileExists(rexpr.c_str()) )
2569 gl.FindFiles(rexpr);
2570 std::vector<std::string>& files = gl.GetFiles();
2571 std::vector<std::string>::iterator fileIt;
2572 for ( fileIt = files.begin(); fileIt != files.end();
2575 cmCTestLog(this, DEBUG, "* Read custom CTest configuration file: "
2576 << fileIt->c_str() << std::endl);
2577 if ( !mf->ReadListFile(0, fileIt->c_str()) ||
2578 cmSystemTools::GetErrorOccuredFlag() )
2580 cmCTestLog(this, ERROR_MESSAGE,
2581 "Problem reading custom configuration: "
2582 << fileIt->c_str() << std::endl);
2590 cmCTest::t_TestingHandlers::iterator it;
2591 for ( it = this->TestingHandlers.begin();
2592 it != this->TestingHandlers.end(); ++ it )
2594 cmCTestLog(this, DEBUG,
2595 "* Read custom CTest configuration vectors for handler: "
2596 << it->first.c_str() << " (" << it->second << ")" << std::endl);
2597 it->second->PopulateCustomVectors(mf);
2604 //----------------------------------------------------------------------
2605 void cmCTest::PopulateCustomVector(cmMakefile* mf, const char* def,
2606 VectorOfStrings& vec)
2612 const char* dval = mf->GetDefinition(def);
2617 cmCTestLog(this, DEBUG, "PopulateCustomVector: " << def << std::endl);
2618 std::vector<std::string> slist;
2619 cmSystemTools::ExpandListArgument(dval, slist);
2620 std::vector<std::string>::iterator it;
2624 for ( it = slist.begin(); it != slist.end(); ++it )
2626 cmCTestLog(this, DEBUG, " -- " << it->c_str() << std::endl);
2627 vec.push_back(it->c_str());
2631 //----------------------------------------------------------------------
2632 void cmCTest::PopulateCustomInteger(cmMakefile* mf, const char* def, int& val)
2638 const char* dval = mf->GetDefinition(def);
2646 //----------------------------------------------------------------------
2647 std::string cmCTest::GetShortPathToFile(const char* cfname)
2649 const std::string& sourceDir
2650 = cmSystemTools::CollapseFullPath(
2651 this->GetCTestConfiguration("SourceDirectory").c_str());
2652 const std::string& buildDir
2653 = cmSystemTools::CollapseFullPath(
2654 this->GetCTestConfiguration("BuildDirectory").c_str());
2655 std::string fname = cmSystemTools::CollapseFullPath(cfname);
2657 // Find relative paths to both directories
2658 std::string srcRelpath
2659 = cmSystemTools::RelativePath(sourceDir.c_str(), fname.c_str());
2660 std::string bldRelpath
2661 = cmSystemTools::RelativePath(buildDir.c_str(), fname.c_str());
2663 // If any contains "." it is not parent directory
2664 bool inSrc = srcRelpath.find("..") == srcRelpath.npos;
2665 bool inBld = bldRelpath.find("..") == bldRelpath.npos;
2666 // TODO: Handle files with .. in their name
2668 std::string* res = 0;
2670 if ( inSrc && inBld )
2672 // If both have relative path with no dots, pick the shorter one
2673 if ( srcRelpath.size() < bldRelpath.size() )
2699 cmSystemTools::ConvertToUnixSlashes(*res);
2702 if ( path[path.size()-1] == '/' )
2704 path = path.substr(0, path.size()-1);
2708 cmsys::SystemTools::ReplaceString(path, ":", "_");
2709 cmsys::SystemTools::ReplaceString(path, " ", "_");
2713 //----------------------------------------------------------------------
2714 std::string cmCTest::GetCTestConfiguration(const char *name)
2716 if ( this->CTestConfigurationOverwrites.find(name) !=
2717 this->CTestConfigurationOverwrites.end() )
2719 return this->CTestConfigurationOverwrites[name];
2721 return this->CTestConfiguration[name];
2724 //----------------------------------------------------------------------
2725 void cmCTest::EmptyCTestConfiguration()
2727 this->CTestConfiguration.clear();
2730 //----------------------------------------------------------------------
2731 void cmCTest::DetermineNextDayStop()
2734 time_t current_time = time(0);
2735 lctime = gmtime(¤t_time);
2736 int gm_hour = lctime->tm_hour;
2737 time_t gm_time = mktime(lctime);
2738 lctime = localtime(¤t_time);
2739 int local_hour = lctime->tm_hour;
2741 int tzone_offset = local_hour - gm_hour;
2742 if(gm_time > current_time && gm_hour < local_hour)
2744 // this means gm_time is on the next day
2747 else if(gm_time < current_time && gm_hour > local_hour)
2749 // this means gm_time is on the previous day
2753 tzone_offset *= 100;
2755 sprintf(buf, "%d%02d%02d %s %+05i",
2756 lctime->tm_year + 1900,
2759 this->StopTime.c_str(),
2762 time_t stop_time = curl_getdate(buf, ¤t_time);
2764 if(stop_time < current_time)
2766 this->NextDayStopTime = true;
2770 //----------------------------------------------------------------------
2771 void cmCTest::SetCTestConfiguration(const char *name, const char* value)
2773 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "SetCTestConfiguration:"
2774 << name << ":" << (value ? value : "(null)") << "\n");
2782 this->CTestConfiguration.erase(name);
2785 this->CTestConfiguration[name] = value;
2789 //----------------------------------------------------------------------
2790 std::string cmCTest::GetCurrentTag()
2792 return this->CurrentTag;
2795 //----------------------------------------------------------------------
2796 std::string cmCTest::GetBinaryDir()
2798 return this->BinaryDir;
2801 //----------------------------------------------------------------------
2802 std::string const& cmCTest::GetConfigType()
2804 return this->ConfigType;
2807 //----------------------------------------------------------------------
2808 bool cmCTest::GetShowOnly()
2810 return this->ShowOnly;
2813 //----------------------------------------------------------------------
2814 int cmCTest::GetMaxTestNameWidth() const
2816 return this->MaxTestNameWidth;
2819 //----------------------------------------------------------------------
2820 void cmCTest::SetProduceXML(bool v)
2822 this->ProduceXML = v;
2825 //----------------------------------------------------------------------
2826 bool cmCTest::GetProduceXML()
2828 return this->ProduceXML;
2831 //----------------------------------------------------------------------
2832 const char* cmCTest::GetSpecificTrack()
2834 if ( this->SpecificTrack.empty() )
2838 return this->SpecificTrack.c_str();
2841 //----------------------------------------------------------------------
2842 void cmCTest::SetSpecificTrack(const char* track)
2846 this->SpecificTrack = "";
2849 this->SpecificTrack = track;
2852 //----------------------------------------------------------------------
2853 void cmCTest::AddSubmitFile(Part part, const char* name)
2855 this->Parts[part].SubmitFiles.push_back(name);
2858 //----------------------------------------------------------------------
2859 void cmCTest::AddCTestConfigurationOverwrite(const char* encstr)
2861 std::string overStr = encstr;
2862 size_t epos = overStr.find("=");
2863 if ( epos == overStr.npos )
2865 cmCTestLog(this, ERROR_MESSAGE,
2866 "CTest configuration overwrite specified in the wrong format."
2868 << "Valid format is: --overwrite key=value" << std::endl
2869 << "The specified was: --overwrite " << overStr.c_str() << std::endl);
2872 std::string key = overStr.substr(0, epos);
2873 std::string value = overStr.substr(epos+1, overStr.npos);
2874 this->CTestConfigurationOverwrites[key] = value;
2877 //----------------------------------------------------------------------
2878 void cmCTest::SetConfigType(const char* ct)
2880 this->ConfigType = ct?ct:"";
2881 cmSystemTools::ReplaceString(this->ConfigType, ".\\", "");
2882 std::string confTypeEnv
2883 = "CMAKE_CONFIG_TYPE=" + this->ConfigType;
2884 cmSystemTools::PutEnv(confTypeEnv.c_str());
2887 //----------------------------------------------------------------------
2888 bool cmCTest::SetCTestConfigurationFromCMakeVariable(cmMakefile* mf,
2889 const char* dconfig, const char* cmake_var)
2892 ctvar = mf->GetDefinition(cmake_var);
2897 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
2898 "SetCTestConfigurationFromCMakeVariable:"
2899 << dconfig << ":" << cmake_var << std::endl);
2900 this->SetCTestConfiguration(dconfig, ctvar);
2904 bool cmCTest::RunCommand(
2905 const char* command,
2906 std::string* stdOut,
2907 std::string* stdErr,
2912 std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);
2919 std::vector<const char*> argv;
2920 for(std::vector<cmStdString>::const_iterator a = args.begin();
2921 a != args.end(); ++a)
2923 argv.push_back(a->c_str());
2930 cmsysProcess* cp = cmsysProcess_New();
2931 cmsysProcess_SetCommand(cp, &*argv.begin());
2932 cmsysProcess_SetWorkingDirectory(cp, dir);
2933 if(cmSystemTools::GetRunCommandHideConsole())
2935 cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
2937 cmsysProcess_SetTimeout(cp, timeout);
2938 cmsysProcess_Execute(cp);
2940 std::vector<char> tempOutput;
2941 std::vector<char> tempError;
2948 res = cmsysProcess_WaitForData(cp, &data, &length, 0);
2951 case cmsysProcess_Pipe_STDOUT:
2952 tempOutput.insert(tempOutput.end(), data, data+length);
2954 case cmsysProcess_Pipe_STDERR:
2955 tempError.insert(tempError.end(), data, data+length);
2960 if ( (res == cmsysProcess_Pipe_STDOUT ||
2961 res == cmsysProcess_Pipe_STDERR) && this->ExtraVerbose )
2963 cmSystemTools::Stdout(data, length);
2967 cmsysProcess_WaitForExit(cp, 0);
2968 if ( tempOutput.size() > 0 )
2970 stdOut->append(&*tempOutput.begin(), tempOutput.size());
2972 if ( tempError.size() > 0 )
2974 stdErr->append(&*tempError.begin(), tempError.size());
2978 if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exited)
2982 *retVal = cmsysProcess_GetExitValue(cp);
2986 if ( cmsysProcess_GetExitValue(cp) != 0 )
2992 else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exception)
2994 const char* exception_str = cmsysProcess_GetExceptionString(cp);
2995 cmCTestLog(this, ERROR_MESSAGE, exception_str << std::endl);
2996 stdErr->append(exception_str, strlen(exception_str));
2999 else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Error)
3001 const char* error_str = cmsysProcess_GetErrorString(cp);
3002 cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
3003 stdErr->append(error_str, strlen(error_str));
3006 else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Expired)
3008 const char* error_str = "Process terminated due to timeout\n";
3009 cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
3010 stdErr->append(error_str, strlen(error_str));
3014 cmsysProcess_Delete(cp);
3018 //----------------------------------------------------------------------
3019 void cmCTest::SetOutputLogFileName(const char* name)
3021 if ( this->OutputLogFile)
3023 delete this->OutputLogFile;
3024 this->OutputLogFile= 0;
3028 this->OutputLogFile = new cmGeneratedFileStream(name);
3032 //----------------------------------------------------------------------
3033 static const char* cmCTestStringLogType[] =
3038 "HANDLER_VERBOSE_OUTPUT",
3044 //----------------------------------------------------------------------
3052 #define cmCTestLogOutputFileLine(stream) \
3053 if ( this->ShowLineNumbers ) \
3055 (stream) << std::endl << file << ":" << line << " "; \
3058 void cmCTest::InitStreams()
3060 // By default we write output to the process output streams.
3061 this->StreamOut = &std::cout;
3062 this->StreamErr = &std::cerr;
3065 void cmCTest::Log(int logType, const char* file, int line, const char* msg)
3067 if ( !msg || !*msg )
3071 if ( this->OutputLogFile )
3073 bool display = true;
3074 if ( logType == cmCTest::DEBUG && !this->Debug ) { display = false; }
3075 if ( logType == cmCTest::HANDLER_VERBOSE_OUTPUT && !this->Debug &&
3076 !this->ExtraVerbose ) { display = false; }
3079 cmCTestLogOutputFileLine(*this->OutputLogFile);
3080 if ( logType != this->OutputLogFileLastTag )
3082 *this->OutputLogFile << "[";
3083 if ( logType >= OTHER || logType < 0 )
3085 *this->OutputLogFile << "OTHER";
3089 *this->OutputLogFile << cmCTestStringLogType[logType];
3091 *this->OutputLogFile << "] " << std::endl << std::flush;
3093 *this->OutputLogFile << msg << std::flush;
3094 if ( logType != this->OutputLogFileLastTag )
3096 *this->OutputLogFile << std::endl << std::flush;
3097 this->OutputLogFileLastTag = logType;
3103 std::ostream& out = *this->StreamOut;
3104 std::ostream& err = *this->StreamErr;
3110 cmCTestLogOutputFileLine(out);
3115 case OUTPUT: case HANDLER_OUTPUT:
3116 if ( this->Debug || this->Verbose )
3118 cmCTestLogOutputFileLine(out);
3123 case HANDLER_VERBOSE_OUTPUT:
3124 if ( this->Debug || this->ExtraVerbose )
3126 cmCTestLogOutputFileLine(out);
3132 cmCTestLogOutputFileLine(err);
3137 cmCTestLogOutputFileLine(err);
3140 cmSystemTools::SetErrorOccured();
3143 cmCTestLogOutputFileLine(out);
3150 //-------------------------------------------------------------------------
3151 double cmCTest::GetRemainingTimeAllowed()
3153 if (!this->GetHandler("script"))
3158 cmCTestScriptHandler* ch
3159 = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
3161 return ch->GetRemainingTimeAllowed();
3164 //----------------------------------------------------------------------
3165 void cmCTest::OutputTestErrors(std::vector<char> const &process_output)
3167 std::string test_outputs("\n*** Test Failed:\n");
3168 if(process_output.size())
3170 test_outputs.append(&*process_output.begin(), process_output.size());
3172 cmCTestLog(this, HANDLER_OUTPUT, test_outputs << std::endl << std::flush);
3175 //----------------------------------------------------------------------
3176 bool cmCTest::CompressString(std::string& str)
3181 unsigned char* in = reinterpret_cast<unsigned char*>(
3182 const_cast<char*>(str.c_str()));
3183 //zlib makes the guarantee that this is the maximum output size
3184 int outSize = static_cast<int>(
3185 static_cast<double>(str.size()) * 1.001 + 13.0);
3186 unsigned char* out = new unsigned char[outSize];
3188 strm.zalloc = Z_NULL;
3189 strm.zfree = Z_NULL;
3190 strm.opaque = Z_NULL;
3191 ret = deflateInit(&strm, -1); //default compression level
3198 strm.avail_in = static_cast<uInt>(str.size());
3200 strm.avail_out = outSize;
3201 strm.next_out = out;
3202 ret = deflate(&strm, Z_FINISH);
3204 if(ret == Z_STREAM_ERROR || ret != Z_STREAM_END)
3206 cmCTestLog(this, ERROR_MESSAGE, "Error during gzip compression."
3212 (void)deflateEnd(&strm);
3214 // Now base64 encode the resulting binary string
3215 unsigned char* base64EncodedBuffer
3216 = new unsigned char[static_cast<int>(outSize * 1.5)];
3219 = cmsysBase64_Encode(out, strm.total_out, base64EncodedBuffer, 1);
3222 str.append(reinterpret_cast<char*>(base64EncodedBuffer), rlen);
3224 delete [] base64EncodedBuffer;