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 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->ParallelLevelSetInCli = false;
298 this->SubmitIndex = 0;
299 this->Failover = false;
300 this->BatchJobs = false;
301 this->ForceNewCTestProcess = false;
302 this->TomorrowTag = false;
303 this->Verbose = false;
306 this->ShowLineNumbers = false;
308 this->ExtraVerbose = false;
309 this->ProduceXML = false;
310 this->ShowOnly = false;
311 this->RunConfigurationScript = false;
312 this->UseHTTP10 = false;
313 this->PrintLabels = false;
314 this->CompressTestOutput = true;
315 this->CompressMemCheckOutput = true;
316 this->TestModel = cmCTest::EXPERIMENTAL;
317 this->MaxTestNameWidth = 30;
318 this->InteractiveDebugMode = true;
320 this->GlobalTimeout = 0;
321 this->LastStopTimeout = 24 * 60 * 60;
322 this->CompressXMLFiles = false;
323 this->CTestConfigFile = "";
324 this->ScheduleType = "";
326 this->NextDayStopTime = false;
327 this->OutputLogFile = 0;
328 this->OutputLogFileLastTag = -1;
329 this->SuppressUpdatingCTestConfiguration = false;
330 this->DartVersion = 1;
331 this->DropSiteCDash = false;
332 this->OutputTestOutputOnTestFailure = false;
333 this->ComputedCompressTestOutput = false;
334 this->ComputedCompressMemCheckOutput = false;
335 if(cmSystemTools::GetEnv("CTEST_OUTPUT_ON_FAILURE"))
337 this->OutputTestOutputOnTestFailure = true;
341 this->Parts[PartStart].SetName("Start");
342 this->Parts[PartUpdate].SetName("Update");
343 this->Parts[PartConfigure].SetName("Configure");
344 this->Parts[PartBuild].SetName("Build");
345 this->Parts[PartTest].SetName("Test");
346 this->Parts[PartCoverage].SetName("Coverage");
347 this->Parts[PartMemCheck].SetName("MemCheck");
348 this->Parts[PartSubmit].SetName("Submit");
349 this->Parts[PartNotes].SetName("Notes");
350 this->Parts[PartExtraFiles].SetName("ExtraFiles");
351 this->Parts[PartUpload].SetName("Upload");
353 // Fill the part name-to-id map.
354 for(Part p = PartStart; p != PartCount; p = Part(p+1))
356 this->PartMap[cmSystemTools::LowerCase(this->Parts[p].GetName())] = p;
359 this->ShortDateFormat = true;
361 this->TestingHandlers["build"] = new cmCTestBuildHandler;
362 this->TestingHandlers["buildtest"] = new cmCTestBuildAndTestHandler;
363 this->TestingHandlers["coverage"] = new cmCTestCoverageHandler;
364 this->TestingHandlers["script"] = new cmCTestScriptHandler;
365 this->TestingHandlers["test"] = new cmCTestTestHandler;
366 this->TestingHandlers["update"] = new cmCTestUpdateHandler;
367 this->TestingHandlers["configure"] = new cmCTestConfigureHandler;
368 this->TestingHandlers["memcheck"] = new cmCTestMemCheckHandler;
369 this->TestingHandlers["submit"] = new cmCTestSubmitHandler;
370 this->TestingHandlers["upload"] = new cmCTestUploadHandler;
372 cmCTest::t_TestingHandlers::iterator it;
373 for ( it = this->TestingHandlers.begin();
374 it != this->TestingHandlers.end(); ++ it )
376 it->second->SetCTestInstance(this);
379 // Make sure we can capture the build tool output.
380 cmSystemTools::EnableVSConsoleOutput();
383 //----------------------------------------------------------------------
386 cmCTest::t_TestingHandlers::iterator it;
387 for ( it = this->TestingHandlers.begin();
388 it != this->TestingHandlers.end(); ++ it )
393 this->SetOutputLogFileName(0);
396 void cmCTest::SetParallelLevel(int level)
398 this->ParallelLevel = level < 1 ? 1 : level;
401 //----------------------------------------------------------------------------
402 bool cmCTest::ShouldCompressTestOutput()
404 if(!this->ComputedCompressTestOutput)
406 std::string cdashVersion = this->GetCDashVersion();
408 bool cdashSupportsGzip = cmSystemTools::VersionCompare(
409 cmSystemTools::OP_GREATER, cdashVersion.c_str(), "1.6") ||
410 cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
411 cdashVersion.c_str(), "1.6");
412 this->CompressTestOutput &= cdashSupportsGzip;
413 this->ComputedCompressTestOutput = true;
415 return this->CompressTestOutput;
418 //----------------------------------------------------------------------------
419 bool cmCTest::ShouldCompressMemCheckOutput()
421 if(!this->ComputedCompressMemCheckOutput)
423 std::string cdashVersion = this->GetCDashVersion();
425 bool compressionSupported = cmSystemTools::VersionCompare(
426 cmSystemTools::OP_GREATER, cdashVersion.c_str(), "1.9.0");
427 this->CompressMemCheckOutput &= compressionSupported;
428 this->ComputedCompressMemCheckOutput = true;
430 return this->CompressMemCheckOutput;
433 //----------------------------------------------------------------------------
434 std::string cmCTest::GetCDashVersion()
436 #ifdef CMAKE_BUILD_WITH_CMAKE
437 //First query the server. If that fails, fall back to the local setting
438 std::string response;
439 std::string url = "http://";
440 url += this->GetCTestConfiguration("DropSite");
442 std::string cdashUri = this->GetCTestConfiguration("DropLocation");
443 cdashUri = cdashUri.substr(0, cdashUri.find("/submit.php"));
446 if ( ! cdashUri.empty() )
448 url += cdashUri + "/api/getversion.php";
449 res = cmCTest::HTTPRequest(url, cmCTest::HTTP_GET, response, "", "", 3);
452 return res ? this->GetCTestConfiguration("CDashVersion") : response;
454 return this->GetCTestConfiguration("CDashVersion");
458 //----------------------------------------------------------------------------
459 cmCTest::Part cmCTest::GetPartFromName(const char* name)
461 // Look up by lower-case to make names case-insensitive.
462 std::string lower_name = cmSystemTools::LowerCase(name);
463 PartMapType::const_iterator i = this->PartMap.find(lower_name);
464 if(i != this->PartMap.end())
469 // The string does not name a valid part.
473 //----------------------------------------------------------------------
474 int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
476 cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
477 if(!this->InteractiveDebugMode)
479 this->BlockTestErrorDiagnostics();
483 cmSystemTools::PutEnv("CTEST_INTERACTIVE_DEBUG_MODE=1");
486 this->BinaryDir = binary_dir;
487 cmSystemTools::ConvertToUnixSlashes(this->BinaryDir);
489 this->UpdateCTestConfiguration();
491 cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
492 if ( this->ProduceXML )
494 cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
495 cmCTestLog(this, OUTPUT,
496 " Site: " << this->GetCTestConfiguration("Site") << std::endl
497 << " Build name: " << this->GetCTestConfiguration("BuildName")
499 cmCTestLog(this, DEBUG, "Produce XML is on" << std::endl);
500 if ( this->TestModel == cmCTest::NIGHTLY &&
501 this->GetCTestConfiguration("NightlyStartTime").empty() )
503 cmCTestLog(this, WARNING,
504 "WARNING: No nightly start time found please set in"
505 " CTestConfig.cmake or DartConfig.cmake" << std::endl);
506 cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
512 cmGlobalGenerator gg;
513 gg.SetCMakeInstance(&cm);
514 cmsys::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator());
515 cmMakefile *mf = lg->GetMakefile();
516 if ( !this->ReadCustomConfigurationFileTree(this->BinaryDir.c_str(), mf) )
518 cmCTestLog(this, DEBUG, "Cannot find custom configuration file tree"
523 if ( this->ProduceXML )
525 // Verify "Testing" directory exists:
527 std::string testingDir = this->BinaryDir + "/Testing";
528 if ( cmSystemTools::FileExists(testingDir.c_str()) )
530 if ( !cmSystemTools::FileIsDirectory(testingDir.c_str()) )
532 cmCTestLog(this, ERROR_MESSAGE, "File " << testingDir
533 << " is in the place of the testing directory" << std::endl);
539 if ( !cmSystemTools::MakeDirectory(testingDir.c_str()) )
541 cmCTestLog(this, ERROR_MESSAGE, "Cannot create directory "
542 << testingDir << std::endl);
547 // Create new "TAG" file or read existing one:
549 bool createNewTag = true;
552 createNewTag = command->ShouldCreateNewTag();
555 std::string tagfile = testingDir + "/TAG";
556 std::ifstream tfin(tagfile.c_str());
561 time_t tctime = time(0);
562 if ( this->TomorrowTag )
564 tctime += ( 24 * 60 * 60 );
566 struct tm *lctime = gmtime(&tctime);
567 if ( tfin && cmSystemTools::GetLineFromStream(tfin, tag) )
574 sscanf(tag.c_str(), "%04d%02d%02d-%02d%02d",
575 &year, &mon, &day, &hour, &min);
576 if ( year != lctime->tm_year + 1900 ||
577 mon != lctime->tm_mon+1 ||
578 day != lctime->tm_mday )
583 if ( cmSystemTools::GetLineFromStream(tfin, tagmode) )
585 if (tagmode.size() > 4 && !this->Parts[PartStart])
587 this->TestModel = cmCTest::GetTestModelFromString(tagmode.c_str());
592 if (tag.size() == 0 || (0 != command) || this->Parts[PartStart])
594 cmCTestLog(this, DEBUG, "TestModel: " << this->GetTestModelString()
596 cmCTestLog(this, DEBUG, "TestModel: " << this->TestModel << std::endl);
597 if ( this->TestModel == cmCTest::NIGHTLY )
599 lctime = this->GetNightlyTime(
600 this->GetCTestConfiguration("NightlyStartTime"),
603 char datestring[100];
604 sprintf(datestring, "%04d%02d%02d-%02d%02d",
605 lctime->tm_year + 1900,
611 std::ofstream ofs(tagfile.c_str());
614 ofs << tag << std::endl;
615 ofs << this->GetTestModelString() << std::endl;
620 cmCTestLog(this, OUTPUT, "Create new tag: " << tag << " - "
621 << this->GetTestModelString() << std::endl);
629 cmSystemTools::GetLineFromStream(tfin, tag);
635 cmCTestLog(this, ERROR_MESSAGE,
636 "Cannot read existing TAG file in " << testingDir
641 cmCTestLog(this, OUTPUT, " Use existing tag: " << tag << " - "
642 << this->GetTestModelString() << std::endl);
645 this->CurrentTag = tag;
651 //----------------------------------------------------------------------
652 bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command)
655 = this->GetCTestConfiguration("SourceDirectory").c_str();
656 std::string bld_dir = this->GetCTestConfiguration("BuildDirectory").c_str();
657 this->DartVersion = 1;
658 this->DropSiteCDash = false;
659 for(Part p = PartStart; p != PartCount; p = Part(p+1))
661 this->Parts[p].SubmitFiles.clear();
664 cmMakefile* mf = command->GetMakefile();
667 std::string src_dir_fname = src_dir;
668 src_dir_fname += "/CTestConfig.cmake";
669 cmSystemTools::ConvertToUnixSlashes(src_dir_fname);
671 std::string bld_dir_fname = bld_dir;
672 bld_dir_fname += "/CTestConfig.cmake";
673 cmSystemTools::ConvertToUnixSlashes(bld_dir_fname);
675 if ( cmSystemTools::FileExists(bld_dir_fname.c_str()) )
677 fname = bld_dir_fname;
679 else if ( cmSystemTools::FileExists(src_dir_fname.c_str()) )
681 fname = src_dir_fname;
684 if ( !fname.empty() )
686 cmCTestLog(this, OUTPUT, " Reading ctest configuration file: "
687 << fname.c_str() << std::endl);
688 bool readit = mf->ReadListFile(mf->GetCurrentListFile(),
692 std::string m = "Could not find include file: ";
694 command->SetError(m.c_str());
700 cmCTestLog(this, WARNING,
701 "Cannot locate CTest configuration: in BuildDirectory: "
702 << bld_dir_fname.c_str() << std::endl);
703 cmCTestLog(this, WARNING,
704 "Cannot locate CTest configuration: in SourceDirectory: "
705 << src_dir_fname.c_str() << std::endl);
708 this->SetCTestConfigurationFromCMakeVariable(mf, "NightlyStartTime",
709 "CTEST_NIGHTLY_START_TIME");
710 this->SetCTestConfigurationFromCMakeVariable(mf, "Site", "CTEST_SITE");
711 this->SetCTestConfigurationFromCMakeVariable(mf, "BuildName",
713 const char* dartVersion = mf->GetDefinition("CTEST_DART_SERVER_VERSION");
716 this->DartVersion = atoi(dartVersion);
717 if ( this->DartVersion < 0 )
719 cmCTestLog(this, ERROR_MESSAGE, "Invalid Dart server version: "
720 << dartVersion << ". Please specify the version number."
725 this->DropSiteCDash = mf->IsOn("CTEST_DROP_SITE_CDASH");
727 if ( !this->Initialize(bld_dir.c_str(), command) )
731 cmCTestLog(this, OUTPUT, " Use " << this->GetTestModelString()
732 << " tag: " << this->GetCurrentTag() << std::endl);
737 //----------------------------------------------------------------------
738 bool cmCTest::UpdateCTestConfiguration()
740 if ( this->SuppressUpdatingCTestConfiguration )
744 std::string fileName = this->CTestConfigFile;
745 if ( fileName.empty() )
747 fileName = this->BinaryDir + "/CTestConfiguration.ini";
748 if ( !cmSystemTools::FileExists(fileName.c_str()) )
750 fileName = this->BinaryDir + "/DartConfiguration.tcl";
753 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "UpdateCTestConfiguration from :"
754 << fileName.c_str() << "\n");
755 if ( !cmSystemTools::FileExists(fileName.c_str()) )
757 // No need to exit if we are not producing XML
758 if ( this->ProduceXML )
760 cmCTestLog(this, ERROR_MESSAGE, "Cannot find file: " << fileName.c_str()
767 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Parse Config file:"
768 << fileName.c_str() << "\n");
769 // parse the dart test file
770 std::ifstream fin(fileName.c_str());
781 fin.getline(buffer, 1023);
783 std::string line = cmCTest::CleanString(buffer);
788 while ( fin && (line[line.size()-1] == '\\') )
790 line = line.substr(0, line.size()-1);
792 fin.getline(buffer, 1023);
794 line += cmCTest::CleanString(buffer);
796 if ( line[0] == '#' )
800 std::string::size_type cpos = line.find_first_of(":");
801 if ( cpos == line.npos )
805 std::string key = line.substr(0, cpos);
807 = cmCTest::CleanString(line.substr(cpos+1, line.npos));
808 this->CTestConfiguration[key] = value;
812 if ( !this->GetCTestConfiguration("BuildDirectory").empty() )
814 this->BinaryDir = this->GetCTestConfiguration("BuildDirectory");
815 cmSystemTools::ChangeDirectory(this->BinaryDir.c_str());
817 this->TimeOut = atoi(this->GetCTestConfiguration("TimeOut").c_str());
818 if ( this->ProduceXML )
820 this->CompressXMLFiles = cmSystemTools::IsOn(
821 this->GetCTestConfiguration("CompressSubmission").c_str());
826 //----------------------------------------------------------------------
827 void cmCTest::BlockTestErrorDiagnostics()
829 cmSystemTools::PutEnv("DART_TEST_FROM_DART=1");
830 cmSystemTools::PutEnv("DASHBOARD_TEST_FROM_CTEST=" CMake_VERSION);
832 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
833 #elif defined(__BEOS__) || defined(__HAIKU__)
838 //----------------------------------------------------------------------
839 void cmCTest::SetTestModel(int mode)
841 this->InteractiveDebugMode = false;
842 this->TestModel = mode;
845 //----------------------------------------------------------------------
846 bool cmCTest::SetTest(const char* ttype, bool report)
848 if ( cmSystemTools::LowerCase(ttype) == "all" )
850 for(Part p = PartStart; p != PartCount; p = Part(p+1))
852 this->Parts[p].Enable();
856 Part p = this->GetPartFromName(ttype);
859 this->Parts[p].Enable();
866 cmCTestLog(this, ERROR_MESSAGE, "Don't know about test \"" << ttype
867 << "\" yet..." << std::endl);
873 //----------------------------------------------------------------------
874 void cmCTest::Finalize()
878 //----------------------------------------------------------------------
879 bool cmCTest::OpenOutputFile(const std::string& path,
880 const std::string& name, cmGeneratedFileStream& stream,
883 std::string testingDir = this->BinaryDir + "/Testing";
884 if ( path.size() > 0 )
886 testingDir += "/" + path;
888 if ( cmSystemTools::FileExists(testingDir.c_str()) )
890 if ( !cmSystemTools::FileIsDirectory(testingDir.c_str()) )
892 cmCTestLog(this, ERROR_MESSAGE, "File " << testingDir
893 << " is in the place of the testing directory"
900 if ( !cmSystemTools::MakeDirectory(testingDir.c_str()) )
902 cmCTestLog(this, ERROR_MESSAGE, "Cannot create directory " << testingDir
907 std::string filename = testingDir + "/" + name;
908 stream.Open(filename.c_str());
911 cmCTestLog(this, ERROR_MESSAGE, "Problem opening file: " << filename
917 if ( this->CompressXMLFiles )
919 stream.SetCompression(true);
925 //----------------------------------------------------------------------
926 bool cmCTest::AddIfExists(Part part, const char* file)
928 if ( this->CTestFileExists(file) )
930 this->AddSubmitFile(part, file);
934 std::string name = file;
936 if ( this->CTestFileExists(name.c_str()) )
938 this->AddSubmitFile(part, file);
948 //----------------------------------------------------------------------
949 bool cmCTest::CTestFileExists(const std::string& filename)
951 std::string testingDir = this->BinaryDir + "/Testing/" +
952 this->CurrentTag + "/" + filename;
953 return cmSystemTools::FileExists(testingDir.c_str());
956 //----------------------------------------------------------------------
957 cmCTestGenericHandler* cmCTest::GetInitializedHandler(const char* handler)
959 cmCTest::t_TestingHandlers::iterator it =
960 this->TestingHandlers.find(handler);
961 if ( it == this->TestingHandlers.end() )
965 it->second->Initialize();
969 //----------------------------------------------------------------------
970 cmCTestGenericHandler* cmCTest::GetHandler(const char* handler)
972 cmCTest::t_TestingHandlers::iterator it =
973 this->TestingHandlers.find(handler);
974 if ( it == this->TestingHandlers.end() )
981 //----------------------------------------------------------------------
982 int cmCTest::ExecuteHandler(const char* shandler)
984 cmCTestGenericHandler* handler = this->GetHandler(shandler);
989 handler->Initialize();
990 return handler->ProcessHandler();
993 //----------------------------------------------------------------------
994 int cmCTest::ProcessTests()
998 int update_count = 0;
1000 for(Part p = PartStart; notest && p != PartCount; p = Part(p+1))
1002 notest = !this->Parts[p];
1004 if (this->Parts[PartUpdate] &&
1005 (this->GetRemainingTimeAllowed() - 120 > 0))
1007 cmCTestGenericHandler* uphandler = this->GetHandler("update");
1008 uphandler->SetPersistentOption("SourceDirectory",
1009 this->GetCTestConfiguration("SourceDirectory").c_str());
1010 update_count = uphandler->ProcessHandler();
1011 if ( update_count < 0 )
1013 res |= cmCTest::UPDATE_ERRORS;
1016 if ( this->TestModel == cmCTest::CONTINUOUS && !update_count )
1020 if (this->Parts[PartConfigure] &&
1021 (this->GetRemainingTimeAllowed() - 120 > 0))
1023 if (this->GetHandler("configure")->ProcessHandler() < 0)
1025 res |= cmCTest::CONFIGURE_ERRORS;
1028 if (this->Parts[PartBuild] &&
1029 (this->GetRemainingTimeAllowed() - 120 > 0))
1031 this->UpdateCTestConfiguration();
1032 if (this->GetHandler("build")->ProcessHandler() < 0)
1034 res |= cmCTest::BUILD_ERRORS;
1037 if ((this->Parts[PartTest] || notest) &&
1038 (this->GetRemainingTimeAllowed() - 120 > 0))
1040 this->UpdateCTestConfiguration();
1041 if (this->GetHandler("test")->ProcessHandler() < 0)
1043 res |= cmCTest::TEST_ERRORS;
1046 if (this->Parts[PartCoverage] &&
1047 (this->GetRemainingTimeAllowed() - 120 > 0))
1049 this->UpdateCTestConfiguration();
1050 if (this->GetHandler("coverage")->ProcessHandler() < 0)
1052 res |= cmCTest::COVERAGE_ERRORS;
1055 if (this->Parts[PartMemCheck] &&
1056 (this->GetRemainingTimeAllowed() - 120 > 0))
1058 this->UpdateCTestConfiguration();
1059 if (this->GetHandler("memcheck")->ProcessHandler() < 0)
1061 res |= cmCTest::MEMORY_ERRORS;
1066 std::string notes_dir = this->BinaryDir + "/Testing/Notes";
1067 if ( cmSystemTools::FileIsDirectory(notes_dir.c_str()) )
1070 d.Load(notes_dir.c_str());
1072 for ( kk = 0; kk < d.GetNumberOfFiles(); kk ++ )
1074 const char* file = d.GetFile(kk);
1075 std::string fullname = notes_dir + "/" + file;
1076 if ( cmSystemTools::FileExists(fullname.c_str()) &&
1077 !cmSystemTools::FileIsDirectory(fullname.c_str()) )
1079 if ( this->NotesFiles.size() > 0 )
1081 this->NotesFiles += ";";
1083 this->NotesFiles += fullname;
1084 this->Parts[PartNotes].Enable();
1089 if (this->Parts[PartNotes])
1091 this->UpdateCTestConfiguration();
1092 if ( this->NotesFiles.size() )
1094 this->GenerateNotesFile(this->NotesFiles.c_str());
1097 if (this->Parts[PartSubmit])
1099 this->UpdateCTestConfiguration();
1100 if (this->GetHandler("submit")->ProcessHandler() < 0)
1102 res |= cmCTest::SUBMIT_ERRORS;
1107 cmCTestLog(this, ERROR_MESSAGE, "Errors while running CTest"
1113 //----------------------------------------------------------------------
1114 std::string cmCTest::GetTestModelString()
1116 if ( !this->SpecificTrack.empty() )
1118 return this->SpecificTrack;
1120 switch ( this->TestModel )
1122 case cmCTest::NIGHTLY:
1124 case cmCTest::CONTINUOUS:
1125 return "Continuous";
1127 return "Experimental";
1130 //----------------------------------------------------------------------
1131 int cmCTest::GetTestModelFromString(const char* str)
1135 return cmCTest::EXPERIMENTAL;
1137 std::string rstr = cmSystemTools::LowerCase(str);
1138 if ( strncmp(rstr.c_str(), "cont", 4) == 0 )
1140 return cmCTest::CONTINUOUS;
1142 if ( strncmp(rstr.c_str(), "nigh", 4) == 0 )
1144 return cmCTest::NIGHTLY;
1146 return cmCTest::EXPERIMENTAL;
1149 //######################################################################
1150 //######################################################################
1151 //######################################################################
1152 //######################################################################
1154 //----------------------------------------------------------------------
1155 int cmCTest::RunMakeCommand(const char* command, std::string* output,
1156 int* retVal, const char* dir, int timeout, std::ofstream& ofs)
1158 // First generate the command and arguments
1159 std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);
1166 std::vector<const char*> argv;
1167 for(std::vector<cmStdString>::const_iterator a = args.begin();
1168 a != args.end(); ++a)
1170 argv.push_back(a->c_str());
1179 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Run command:");
1180 std::vector<const char*>::iterator ait;
1181 for ( ait = argv.begin(); ait != argv.end() && *ait; ++ ait )
1183 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, " \"" << *ait << "\"");
1185 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, std::endl);
1187 // Now create process object
1188 cmsysProcess* cp = cmsysProcess_New();
1189 cmsysProcess_SetCommand(cp, &*argv.begin());
1190 cmsysProcess_SetWorkingDirectory(cp, dir);
1191 cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
1192 cmsysProcess_SetTimeout(cp, timeout);
1193 cmsysProcess_Execute(cp);
1195 // Initialize tick's
1196 std::string::size_type tick = 0;
1197 std::string::size_type tick_len = 1024;
1198 std::string::size_type tick_line_len = 50;
1202 cmCTestLog(this, HANDLER_OUTPUT,
1203 " Each . represents " << tick_len << " bytes of output" << std::endl
1204 << " " << std::flush);
1205 while(cmsysProcess_WaitForData(cp, &data, &length, 0))
1209 for(int cc =0; cc < length; ++cc)
1217 output->append(data, length);
1218 while ( output->size() > (tick * tick_len) )
1221 cmCTestLog(this, HANDLER_OUTPUT, "." << std::flush);
1222 if ( tick % tick_line_len == 0 && tick > 0 )
1224 cmCTestLog(this, HANDLER_OUTPUT, " Size: "
1225 << int((double(output->size()) / 1024.0) + 1) << "K" << std::endl
1226 << " " << std::flush);
1230 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, cmCTestLogWrite(data, length));
1233 ofs << cmCTestLogWrite(data, length);
1236 cmCTestLog(this, OUTPUT, " Size of output: "
1237 << int(double(output->size()) / 1024.0) << "K" << std::endl);
1239 cmsysProcess_WaitForExit(cp, 0);
1241 int result = cmsysProcess_GetState(cp);
1243 if(result == cmsysProcess_State_Exited)
1245 *retVal = cmsysProcess_GetExitValue(cp);
1246 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Command exited with the value: "
1247 << *retVal << std::endl);
1249 else if(result == cmsysProcess_State_Exception)
1251 *retVal = cmsysProcess_GetExitException(cp);
1252 cmCTestLog(this, WARNING, "There was an exception: " << *retVal
1255 else if(result == cmsysProcess_State_Expired)
1257 cmCTestLog(this, WARNING, "There was a timeout" << std::endl);
1259 else if(result == cmsysProcess_State_Error)
1261 *output += "\n*** ERROR executing: ";
1262 *output += cmsysProcess_GetErrorString(cp);
1263 *output += "\n***The build process failed.";
1264 cmCTestLog(this, ERROR_MESSAGE, "There was an error: "
1265 << cmsysProcess_GetErrorString(cp) << std::endl);
1268 cmsysProcess_Delete(cp);
1273 //######################################################################
1274 //######################################################################
1275 //######################################################################
1276 //######################################################################
1278 //----------------------------------------------------------------------
1279 int cmCTest::RunTest(std::vector<const char*> argv,
1280 std::string* output, int *retVal,
1281 std::ostream* log, double testTimeOut,
1282 std::vector<std::string>* environment)
1284 bool modifyEnv = (environment && environment->size()>0);
1286 // determine how much time we have
1287 double timeout = this->GetRemainingTimeAllowed() - 120;
1288 if (this->TimeOut > 0 && this->TimeOut < timeout)
1290 timeout = this->TimeOut;
1293 && testTimeOut < this->GetRemainingTimeAllowed())
1295 timeout = testTimeOut;
1298 // always have at least 1 second if we got to here
1303 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
1304 "Test timeout computed to be: " << timeout << "\n");
1305 if(cmSystemTools::SameFile(argv[0], this->CTestSelf.c_str()) &&
1306 !this->ForceNewCTestProcess)
1309 inst.ConfigType = this->ConfigType;
1310 inst.TimeOut = timeout;
1312 // Capture output of the child ctest.
1313 cmOStringStream oss;
1314 inst.SetStreams(&oss, &oss);
1316 std::vector<std::string> args;
1317 for(unsigned int i =0; i < argv.size(); ++i)
1321 // make sure we pass the timeout in for any build and test
1322 // invocations. Since --build-generator is required this is a
1323 // good place to check for it, and to add the arguments in
1324 if (strcmp(argv[i],"--build-generator") == 0 && timeout > 0)
1326 args.push_back("--test-timeout");
1327 cmOStringStream msg;
1329 args.push_back(msg.str());
1331 args.push_back(argv[i]);
1336 *log << "* Run internal CTest" << std::endl;
1338 std::string oldpath = cmSystemTools::GetCurrentWorkingDirectory();
1340 cmsys::auto_ptr<cmSystemTools::SaveRestoreEnvironment> saveEnv;
1343 saveEnv.reset(new cmSystemTools::SaveRestoreEnvironment);
1344 cmSystemTools::AppendEnv(*environment);
1347 *retVal = inst.Run(args, output);
1348 *output += oss.str();
1351 *log << output->c_str();
1353 cmSystemTools::ChangeDirectory(oldpath.c_str());
1355 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
1356 "Internal cmCTest object used to run test." << std::endl
1357 << *output << std::endl);
1359 return cmsysProcess_State_Exited;
1361 std::vector<char> tempOutput;
1367 cmsys::auto_ptr<cmSystemTools::SaveRestoreEnvironment> saveEnv;
1370 saveEnv.reset(new cmSystemTools::SaveRestoreEnvironment);
1371 cmSystemTools::AppendEnv(*environment);
1374 cmsysProcess* cp = cmsysProcess_New();
1375 cmsysProcess_SetCommand(cp, &*argv.begin());
1376 cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
1377 if(cmSystemTools::GetRunCommandHideConsole())
1379 cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
1382 cmsysProcess_SetTimeout(cp, timeout);
1383 cmsysProcess_Execute(cp);
1387 while(cmsysProcess_WaitForData(cp, &data, &length, 0))
1391 tempOutput.insert(tempOutput.end(), data, data+length);
1393 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, cmCTestLogWrite(data, length));
1396 log->write(data, length);
1400 cmsysProcess_WaitForExit(cp, 0);
1401 if(output && tempOutput.begin() != tempOutput.end())
1403 output->append(&*tempOutput.begin(), tempOutput.size());
1405 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "-- Process completed"
1408 int result = cmsysProcess_GetState(cp);
1410 if(result == cmsysProcess_State_Exited)
1412 *retVal = cmsysProcess_GetExitValue(cp);
1413 if(*retVal != 0 && this->OutputTestOutputOnTestFailure)
1415 OutputTestErrors(tempOutput);
1418 else if(result == cmsysProcess_State_Exception)
1420 if(this->OutputTestOutputOnTestFailure)
1422 OutputTestErrors(tempOutput);
1424 *retVal = cmsysProcess_GetExitException(cp);
1425 std::string outerr = "\n*** Exception executing: ";
1426 outerr += cmsysProcess_GetExceptionString(cp);
1428 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr.c_str() << std::endl
1431 else if(result == cmsysProcess_State_Error)
1433 std::string outerr = "\n*** ERROR executing: ";
1434 outerr += cmsysProcess_GetErrorString(cp);
1436 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr.c_str() << std::endl
1439 cmsysProcess_Delete(cp);
1444 //----------------------------------------------------------------------
1445 std::string cmCTest::SafeBuildIdField(const std::string& value)
1447 std::string safevalue(value);
1449 if (safevalue != "")
1451 // Disallow non-filename and non-space whitespace characters.
1452 // If they occur, replace them with ""
1454 const char *disallowed = "\\/:*?\"<>|\n\r\t\f\v";
1456 if (safevalue.find_first_of(disallowed) != value.npos)
1458 std::string::size_type i = 0;
1459 std::string::size_type n = strlen(disallowed);
1463 for (i= 0; i<n; ++i)
1465 replace[0] = disallowed[i];
1466 cmSystemTools::ReplaceString(safevalue, replace, "");
1470 safevalue = cmXMLSafe(safevalue).str();
1473 if (safevalue == "")
1475 safevalue = "(empty)";
1481 //----------------------------------------------------------------------
1482 void cmCTest::StartXML(std::ostream& ostr, bool append)
1484 if(this->CurrentTag.empty())
1486 cmCTestLog(this, ERROR_MESSAGE,
1487 "Current Tag empty, this may mean"
1488 " NightlStartTime was not set correctly." << std::endl);
1489 cmSystemTools::SetFatalErrorOccured();
1492 // find out about the system
1493 cmsys::SystemInformation info;
1496 info.RunMemoryCheck();
1498 std::string buildname = cmCTest::SafeBuildIdField(
1499 this->GetCTestConfiguration("BuildName"));
1500 std::string stamp = cmCTest::SafeBuildIdField(
1501 this->CurrentTag + "-" + this->GetTestModelString());
1502 std::string site = cmCTest::SafeBuildIdField(
1503 this->GetCTestConfiguration("Site"));
1505 ostr << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1506 << "<Site BuildName=\"" << buildname << "\"\n"
1507 << "\tBuildStamp=\"" << stamp << "\"\n"
1508 << "\tName=\"" << site << "\"\n"
1509 << "\tGenerator=\"ctest-" << cmVersion::GetCMakeVersion() << "\"\n"
1510 << (append? "\tAppend=\"true\"\n":"")
1511 << "\tCompilerName=\"" << this->GetCTestConfiguration("Compiler")
1513 #ifdef _COMPILER_VERSION
1514 << "\tCompilerVersion=\"_COMPILER_VERSION\"\n"
1516 << "\tOSName=\"" << info.GetOSName() << "\"\n"
1517 << "\tHostname=\"" << info.GetHostname() << "\"\n"
1518 << "\tOSRelease=\"" << info.GetOSRelease() << "\"\n"
1519 << "\tOSVersion=\"" << info.GetOSVersion() << "\"\n"
1520 << "\tOSPlatform=\"" << info.GetOSPlatform() << "\"\n"
1521 << "\tIs64Bits=\"" << info.Is64Bits() << "\"\n"
1522 << "\tVendorString=\"" << info.GetVendorString() << "\"\n"
1523 << "\tVendorID=\"" << info.GetVendorID() << "\"\n"
1524 << "\tFamilyID=\"" << info.GetFamilyID() << "\"\n"
1525 << "\tModelID=\"" << info.GetModelID() << "\"\n"
1526 << "\tProcessorCacheSize=\"" << info.GetProcessorCacheSize() << "\"\n"
1527 << "\tNumberOfLogicalCPU=\"" << info.GetNumberOfLogicalCPU() << "\"\n"
1528 << "\tNumberOfPhysicalCPU=\""<< info.GetNumberOfPhysicalCPU() << "\"\n"
1529 << "\tTotalVirtualMemory=\"" << info.GetTotalVirtualMemory() << "\"\n"
1530 << "\tTotalPhysicalMemory=\""<< info.GetTotalPhysicalMemory() << "\"\n"
1531 << "\tLogicalProcessorsPerPhysical=\""
1532 << info.GetLogicalProcessorsPerPhysical() << "\"\n"
1533 << "\tProcessorClockFrequency=\""
1534 << info.GetProcessorClockFrequency() << "\"\n"
1535 << ">" << std::endl;
1536 this->AddSiteProperties(ostr);
1539 //----------------------------------------------------------------------
1540 void cmCTest::AddSiteProperties(std::ostream& ostr)
1542 cmCTestScriptHandler* ch =
1543 static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
1544 cmake* cm = ch->GetCMake();
1545 // if no CMake then this is the old style script and props like
1546 // this will not work anyway.
1551 // This code should go when cdash is changed to use labels only
1552 const char* subproject = cm->GetProperty("SubProject", cmProperty::GLOBAL);
1555 ostr << "<Subproject name=\"" << subproject << "\">\n";
1556 const char* labels =
1557 ch->GetCMake()->GetProperty("SubProjectLabels", cmProperty::GLOBAL);
1560 ostr << " <Labels>\n";
1561 std::string l = labels;
1562 std::vector<std::string> args;
1563 cmSystemTools::ExpandListArgument(l, args);
1564 for(std::vector<std::string>::iterator i = args.begin();
1565 i != args.end(); ++i)
1567 ostr << " <Label>" << i->c_str() << "</Label>\n";
1569 ostr << " </Labels>\n";
1571 ostr << "</Subproject>\n";
1574 // This code should stay when cdash only does label based sub-projects
1575 const char* label = cm->GetProperty("Label", cmProperty::GLOBAL);
1578 ostr << "<Labels>\n";
1579 ostr << " <Label>" << label << "</Label>\n";
1580 ostr << "</Labels>\n";
1585 //----------------------------------------------------------------------
1586 void cmCTest::EndXML(std::ostream& ostr)
1588 ostr << "</Site>" << std::endl;
1591 //----------------------------------------------------------------------
1592 int cmCTest::GenerateCTestNotesOutput(std::ostream& os,
1593 const cmCTest::VectorOfStrings& files)
1595 cmCTest::VectorOfStrings::const_iterator it;
1596 os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1597 << "<?xml-stylesheet type=\"text/xsl\" "
1598 "href=\"Dart/Source/Server/XSL/Build.xsl "
1599 "<file:///Dart/Source/Server/XSL/Build.xsl> \"?>\n"
1600 << "<Site BuildName=\"" << this->GetCTestConfiguration("BuildName")
1601 << "\" BuildStamp=\""
1602 << this->CurrentTag << "-" << this->GetTestModelString() << "\" Name=\""
1603 << this->GetCTestConfiguration("Site") << "\" Generator=\"ctest"
1604 << cmVersion::GetCMakeVersion()
1606 this->AddSiteProperties(os);
1607 os << "<Notes>" << std::endl;
1609 for ( it = files.begin(); it != files.end(); it ++ )
1611 cmCTestLog(this, OUTPUT, "\tAdd file: " << it->c_str() << std::endl);
1612 std::string note_time = this->CurrentTime();
1613 os << "<Note Name=\"" << cmXMLSafe(*it) << "\">\n"
1614 << "<Time>" << cmSystemTools::GetTime() << "</Time>\n"
1615 << "<DateTime>" << note_time << "</DateTime>\n"
1616 << "<Text>" << std::endl;
1617 std::ifstream ifs(it->c_str());
1621 while ( cmSystemTools::GetLineFromStream(ifs, line) )
1623 os << cmXMLSafe(line) << std::endl;
1629 os << "Problem reading file: " << it->c_str() << std::endl;
1630 cmCTestLog(this, ERROR_MESSAGE, "Problem reading file: " << it->c_str()
1631 << " while creating notes" << std::endl);
1634 << "</Note>" << std::endl;
1637 << "</Site>" << std::endl;
1641 //----------------------------------------------------------------------
1642 int cmCTest::GenerateNotesFile(const std::vector<cmStdString> &files)
1644 cmGeneratedFileStream ofs;
1645 if ( !this->OpenOutputFile(this->CurrentTag, "Notes.xml", ofs) )
1647 cmCTestLog(this, ERROR_MESSAGE, "Cannot open notes file" << std::endl);
1651 this->GenerateCTestNotesOutput(ofs, files);
1655 //----------------------------------------------------------------------
1656 int cmCTest::GenerateNotesFile(const char* cfiles)
1663 std::vector<cmStdString> files;
1665 cmCTestLog(this, OUTPUT, "Create notes file" << std::endl);
1667 files = cmSystemTools::SplitString(cfiles, ';');
1668 if ( files.size() == 0 )
1673 return this->GenerateNotesFile(files);
1676 //----------------------------------------------------------------------
1677 std::string cmCTest::Base64GzipEncodeFile(std::string file)
1679 std::string tarFile = file + "_temp.tar.gz";
1680 std::vector<cmStdString> files;
1681 files.push_back(file);
1683 if(!cmSystemTools::CreateTar(tarFile.c_str(), files, true, false, false))
1685 cmCTestLog(this, ERROR_MESSAGE, "Error creating tar while "
1686 "encoding file: " << file << std::endl);
1689 std::string base64 = this->Base64EncodeFile(tarFile);
1690 cmSystemTools::RemoveFile(tarFile.c_str());
1694 //----------------------------------------------------------------------
1695 std::string cmCTest::Base64EncodeFile(std::string file)
1697 long len = cmSystemTools::FileLength(file.c_str());
1698 std::ifstream ifs(file.c_str(), std::ios::in
1703 unsigned char *file_buffer = new unsigned char [ len + 1 ];
1704 ifs.read(reinterpret_cast<char*>(file_buffer), len);
1707 unsigned char *encoded_buffer
1708 = new unsigned char [ static_cast<int>(
1709 static_cast<double>(len) * 1.5 + 5.0) ];
1712 = cmsysBase64_Encode(file_buffer, len, encoded_buffer, 1);
1714 std::string base64 = "";
1715 for(unsigned long i = 0; i < rlen; i++)
1717 base64 += encoded_buffer[i];
1719 delete [] file_buffer;
1720 delete [] encoded_buffer;
1726 //----------------------------------------------------------------------
1727 bool cmCTest::SubmitExtraFiles(const std::vector<cmStdString> &files)
1729 std::vector<cmStdString>::const_iterator it;
1730 for ( it = files.begin();
1734 if ( !cmSystemTools::FileExists(it->c_str()) )
1736 cmCTestLog(this, ERROR_MESSAGE, "Cannot find extra file: "
1737 << it->c_str() << " to submit."
1741 this->AddSubmitFile(PartExtraFiles, it->c_str());
1746 //----------------------------------------------------------------------
1747 bool cmCTest::SubmitExtraFiles(const char* cfiles)
1754 std::vector<cmStdString> files;
1756 cmCTestLog(this, OUTPUT, "Submit extra files" << std::endl);
1758 files = cmSystemTools::SplitString(cfiles, ';');
1759 if ( files.size() == 0 )
1764 return this->SubmitExtraFiles(files);
1768 //-------------------------------------------------------
1769 // for a -D argument convert the next argument into
1770 // the proper list of dashboard steps via SetTest
1771 bool cmCTest::AddTestsForDashboardType(std::string &targ)
1773 if ( targ == "Experimental" )
1775 this->SetTestModel(cmCTest::EXPERIMENTAL);
1776 this->SetTest("Start");
1777 this->SetTest("Configure");
1778 this->SetTest("Build");
1779 this->SetTest("Test");
1780 this->SetTest("Coverage");
1781 this->SetTest("Submit");
1783 else if ( targ == "ExperimentalStart" )
1785 this->SetTestModel(cmCTest::EXPERIMENTAL);
1786 this->SetTest("Start");
1788 else if ( targ == "ExperimentalUpdate" )
1790 this->SetTestModel(cmCTest::EXPERIMENTAL);
1791 this->SetTest("Update");
1793 else if ( targ == "ExperimentalConfigure" )
1795 this->SetTestModel(cmCTest::EXPERIMENTAL);
1796 this->SetTest("Configure");
1798 else if ( targ == "ExperimentalBuild" )
1800 this->SetTestModel(cmCTest::EXPERIMENTAL);
1801 this->SetTest("Build");
1803 else if ( targ == "ExperimentalTest" )
1805 this->SetTestModel(cmCTest::EXPERIMENTAL);
1806 this->SetTest("Test");
1808 else if ( targ == "ExperimentalMemCheck"
1809 || targ == "ExperimentalPurify" )
1811 this->SetTestModel(cmCTest::EXPERIMENTAL);
1812 this->SetTest("MemCheck");
1814 else if ( targ == "ExperimentalCoverage" )
1816 this->SetTestModel(cmCTest::EXPERIMENTAL);
1817 this->SetTest("Coverage");
1819 else if ( targ == "ExperimentalSubmit" )
1821 this->SetTestModel(cmCTest::EXPERIMENTAL);
1822 this->SetTest("Submit");
1824 else if ( targ == "Continuous" )
1826 this->SetTestModel(cmCTest::CONTINUOUS);
1827 this->SetTest("Start");
1828 this->SetTest("Update");
1829 this->SetTest("Configure");
1830 this->SetTest("Build");
1831 this->SetTest("Test");
1832 this->SetTest("Coverage");
1833 this->SetTest("Submit");
1835 else if ( targ == "ContinuousStart" )
1837 this->SetTestModel(cmCTest::CONTINUOUS);
1838 this->SetTest("Start");
1840 else if ( targ == "ContinuousUpdate" )
1842 this->SetTestModel(cmCTest::CONTINUOUS);
1843 this->SetTest("Update");
1845 else if ( targ == "ContinuousConfigure" )
1847 this->SetTestModel(cmCTest::CONTINUOUS);
1848 this->SetTest("Configure");
1850 else if ( targ == "ContinuousBuild" )
1852 this->SetTestModel(cmCTest::CONTINUOUS);
1853 this->SetTest("Build");
1855 else if ( targ == "ContinuousTest" )
1857 this->SetTestModel(cmCTest::CONTINUOUS);
1858 this->SetTest("Test");
1860 else if ( targ == "ContinuousMemCheck"
1861 || targ == "ContinuousPurify" )
1863 this->SetTestModel(cmCTest::CONTINUOUS);
1864 this->SetTest("MemCheck");
1866 else if ( targ == "ContinuousCoverage" )
1868 this->SetTestModel(cmCTest::CONTINUOUS);
1869 this->SetTest("Coverage");
1871 else if ( targ == "ContinuousSubmit" )
1873 this->SetTestModel(cmCTest::CONTINUOUS);
1874 this->SetTest("Submit");
1876 else if ( targ == "Nightly" )
1878 this->SetTestModel(cmCTest::NIGHTLY);
1879 this->SetTest("Start");
1880 this->SetTest("Update");
1881 this->SetTest("Configure");
1882 this->SetTest("Build");
1883 this->SetTest("Test");
1884 this->SetTest("Coverage");
1885 this->SetTest("Submit");
1887 else if ( targ == "NightlyStart" )
1889 this->SetTestModel(cmCTest::NIGHTLY);
1890 this->SetTest("Start");
1892 else if ( targ == "NightlyUpdate" )
1894 this->SetTestModel(cmCTest::NIGHTLY);
1895 this->SetTest("Update");
1897 else if ( targ == "NightlyConfigure" )
1899 this->SetTestModel(cmCTest::NIGHTLY);
1900 this->SetTest("Configure");
1902 else if ( targ == "NightlyBuild" )
1904 this->SetTestModel(cmCTest::NIGHTLY);
1905 this->SetTest("Build");
1907 else if ( targ == "NightlyTest" )
1909 this->SetTestModel(cmCTest::NIGHTLY);
1910 this->SetTest("Test");
1912 else if ( targ == "NightlyMemCheck"
1913 || targ == "NightlyPurify" )
1915 this->SetTestModel(cmCTest::NIGHTLY);
1916 this->SetTest("MemCheck");
1918 else if ( targ == "NightlyCoverage" )
1920 this->SetTestModel(cmCTest::NIGHTLY);
1921 this->SetTest("Coverage");
1923 else if ( targ == "NightlySubmit" )
1925 this->SetTestModel(cmCTest::NIGHTLY);
1926 this->SetTest("Submit");
1928 else if ( targ == "MemoryCheck" )
1930 this->SetTestModel(cmCTest::EXPERIMENTAL);
1931 this->SetTest("Start");
1932 this->SetTest("Configure");
1933 this->SetTest("Build");
1934 this->SetTest("MemCheck");
1935 this->SetTest("Coverage");
1936 this->SetTest("Submit");
1938 else if ( targ == "NightlyMemoryCheck" )
1940 this->SetTestModel(cmCTest::NIGHTLY);
1941 this->SetTest("Start");
1942 this->SetTest("Update");
1943 this->SetTest("Configure");
1944 this->SetTest("Build");
1945 this->SetTest("MemCheck");
1946 this->SetTest("Coverage");
1947 this->SetTest("Submit");
1957 //----------------------------------------------------------------------
1958 void cmCTest::ErrorMessageUnknownDashDValue(std::string &val)
1960 cmCTestLog(this, ERROR_MESSAGE,
1961 "CTest -D called with incorrect option: " << val << std::endl);
1963 cmCTestLog(this, ERROR_MESSAGE,
1964 "Available options are:" << std::endl
1965 << " ctest -D Continuous" << std::endl
1966 << " ctest -D Continuous(Start|Update|Configure|Build)" << std::endl
1967 << " ctest -D Continuous(Test|Coverage|MemCheck|Submit)" << std::endl
1968 << " ctest -D Experimental" << std::endl
1969 << " ctest -D Experimental(Start|Update|Configure|Build)" << std::endl
1970 << " ctest -D Experimental(Test|Coverage|MemCheck|Submit)" << std::endl
1971 << " ctest -D Nightly" << std::endl
1972 << " ctest -D Nightly(Start|Update|Configure|Build)" << std::endl
1973 << " ctest -D Nightly(Test|Coverage|MemCheck|Submit)" << std::endl
1974 << " ctest -D NightlyMemoryCheck" << std::endl);
1978 //----------------------------------------------------------------------
1979 bool cmCTest::CheckArgument(const std::string& arg, const char* varg1,
1982 return (varg1 && arg == varg1) || (varg2 && arg == varg2);
1986 //----------------------------------------------------------------------
1987 // Processes one command line argument (and its arguments if any)
1988 // for many simple options and then returns
1989 void cmCTest::HandleCommandLineArguments(size_t &i,
1990 std::vector<std::string> &args)
1992 std::string arg = args[i];
1994 if(this->CheckArgument(arg, "-F"))
1996 this->Failover = true;
1998 if(this->CheckArgument(arg, "-j", "--parallel") && i < args.size() - 1)
2001 int plevel = atoi(args[i].c_str());
2002 this->SetParallelLevel(plevel);
2003 this->ParallelLevelSetInCli = true;
2005 else if(arg.find("-j") == 0)
2007 int plevel = atoi(arg.substr(2).c_str());
2008 this->SetParallelLevel(plevel);
2009 this->ParallelLevelSetInCli = true;
2012 if(this->CheckArgument(arg, "--no-compress-output"))
2014 this->CompressTestOutput = false;
2015 this->CompressMemCheckOutput = false;
2018 if(this->CheckArgument(arg, "--print-labels"))
2020 this->PrintLabels = true;
2023 if(this->CheckArgument(arg, "--http1.0"))
2025 this->UseHTTP10 = true;
2028 if(this->CheckArgument(arg, "--timeout") && i < args.size() - 1)
2031 double timeout = (double)atof(args[i].c_str());
2032 this->GlobalTimeout = timeout;
2035 if(this->CheckArgument(arg, "--stop-time") && i < args.size() - 1)
2038 this->SetStopTime(args[i]);
2041 if(this->CheckArgument(arg, "-C", "--build-config") &&
2042 i < args.size() - 1)
2045 this->SetConfigType(args[i].c_str());
2048 if(this->CheckArgument(arg, "--debug"))
2051 this->ShowLineNumbers = true;
2053 if(this->CheckArgument(arg, "--track") && i < args.size() - 1)
2056 this->SpecificTrack = args[i];
2058 if(this->CheckArgument(arg, "--show-line-numbers"))
2060 this->ShowLineNumbers = true;
2062 if(this->CheckArgument(arg, "--no-label-summary"))
2064 this->LabelSummary = false;
2066 if(this->CheckArgument(arg, "-Q", "--quiet"))
2070 if(this->CheckArgument(arg, "-V", "--verbose"))
2072 this->Verbose = true;
2074 if(this->CheckArgument(arg, "-B"))
2076 this->BatchJobs = true;
2078 if(this->CheckArgument(arg, "-VV", "--extra-verbose"))
2080 this->ExtraVerbose = true;
2081 this->Verbose = true;
2083 if(this->CheckArgument(arg, "--output-on-failure"))
2085 this->OutputTestOutputOnTestFailure = true;
2088 if(this->CheckArgument(arg, "-N", "--show-only"))
2090 this->ShowOnly = true;
2093 if(this->CheckArgument(arg, "-O", "--output-log") && i < args.size() - 1 )
2096 this->SetOutputLogFileName(args[i].c_str());
2099 if(this->CheckArgument(arg, "--tomorrow-tag"))
2101 this->TomorrowTag = true;
2103 if(this->CheckArgument(arg, "--force-new-ctest-process"))
2105 this->ForceNewCTestProcess = true;
2107 if(this->CheckArgument(arg, "-W", "--max-width") && i < args.size() - 1)
2110 this->MaxTestNameWidth = atoi(args[i].c_str());
2112 if(this->CheckArgument(arg, "--interactive-debug-mode") &&
2113 i < args.size() - 1 )
2116 this->InteractiveDebugMode = cmSystemTools::IsOn(args[i].c_str());
2118 if(this->CheckArgument(arg, "--submit-index") && i < args.size() - 1 )
2121 this->SubmitIndex = atoi(args[i].c_str());
2122 if ( this->SubmitIndex < 0 )
2124 this->SubmitIndex = 0;
2128 if(this->CheckArgument(arg, "--overwrite") && i < args.size() - 1)
2131 this->AddCTestConfigurationOverwrite(args[i].c_str());
2133 if(this->CheckArgument(arg, "-A", "--add-notes") && i < args.size() - 1)
2135 this->ProduceXML = true;
2136 this->SetTest("Notes");
2138 this->SetNotesFiles(args[i].c_str());
2141 // options that control what tests are run
2142 if(this->CheckArgument(arg, "-I", "--tests-information") &&
2143 i < args.size() - 1)
2146 this->GetHandler("test")->SetPersistentOption("TestsToRunInformation",
2148 this->GetHandler("memcheck")->
2149 SetPersistentOption("TestsToRunInformation",args[i].c_str());
2151 if(this->CheckArgument(arg, "-U", "--union"))
2153 this->GetHandler("test")->SetPersistentOption("UseUnion", "true");
2154 this->GetHandler("memcheck")->SetPersistentOption("UseUnion", "true");
2156 if(this->CheckArgument(arg, "-R", "--tests-regex") && i < args.size() - 1)
2159 this->GetHandler("test")->
2160 SetPersistentOption("IncludeRegularExpression", args[i].c_str());
2161 this->GetHandler("memcheck")->
2162 SetPersistentOption("IncludeRegularExpression", args[i].c_str());
2164 if(this->CheckArgument(arg, "-L", "--label-regex") && i < args.size() - 1)
2167 this->GetHandler("test")->
2168 SetPersistentOption("LabelRegularExpression", args[i].c_str());
2169 this->GetHandler("memcheck")->
2170 SetPersistentOption("LabelRegularExpression", args[i].c_str());
2172 if(this->CheckArgument(arg, "-LE", "--label-exclude") && i < args.size() - 1)
2175 this->GetHandler("test")->
2176 SetPersistentOption("ExcludeLabelRegularExpression", args[i].c_str());
2177 this->GetHandler("memcheck")->
2178 SetPersistentOption("ExcludeLabelRegularExpression", args[i].c_str());
2181 if(this->CheckArgument(arg, "-E", "--exclude-regex") &&
2182 i < args.size() - 1)
2185 this->GetHandler("test")->
2186 SetPersistentOption("ExcludeRegularExpression", args[i].c_str());
2187 this->GetHandler("memcheck")->
2188 SetPersistentOption("ExcludeRegularExpression", args[i].c_str());
2192 //----------------------------------------------------------------------
2193 // handle the -S -SR and -SP arguments
2194 void cmCTest::HandleScriptArguments(size_t &i,
2195 std::vector<std::string> &args,
2196 bool &SRArgumentSpecified)
2198 std::string arg = args[i];
2199 if(this->CheckArgument(arg, "-SP", "--script-new-process") &&
2200 i < args.size() - 1 )
2202 this->RunConfigurationScript = true;
2204 cmCTestScriptHandler* ch
2205 = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
2206 // -SR is an internal argument, -SP should be ignored when it is passed
2207 if (!SRArgumentSpecified)
2209 ch->AddConfigurationScript(args[i].c_str(),false);
2213 if(this->CheckArgument(arg, "-SR", "--script-run") &&
2214 i < args.size() - 1 )
2216 SRArgumentSpecified = true;
2217 this->RunConfigurationScript = true;
2219 cmCTestScriptHandler* ch
2220 = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
2221 ch->AddConfigurationScript(args[i].c_str(),true);
2224 if(this->CheckArgument(arg, "-S", "--script") && i < args.size() - 1 )
2226 this->RunConfigurationScript = true;
2228 cmCTestScriptHandler* ch
2229 = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
2230 // -SR is an internal argument, -S should be ignored when it is passed
2231 if (!SRArgumentSpecified)
2233 ch->AddConfigurationScript(args[i].c_str(),true);
2238 //----------------------------------------------------------------------
2239 bool cmCTest::AddVariableDefinition(const std::string &arg)
2243 cmCacheManager::CacheEntryType type = cmCacheManager::UNINITIALIZED;
2245 if (cmCacheManager::ParseEntry(arg.c_str(), name, value, type))
2247 this->Definitions[name] = value;
2254 //----------------------------------------------------------------------
2255 // the main entry point of ctest, called from main
2256 int cmCTest::Run(std::vector<std::string> &args, std::string* output)
2258 this->FindRunningCMake();
2259 const char* ctestExec = "ctest";
2260 bool cmakeAndTest = false;
2261 bool executeTests = true;
2262 bool SRArgumentSpecified = false;
2264 // copy the command line
2265 for(size_t i=0; i < args.size(); ++i)
2267 this->InitialCommandLineArguments.push_back(args[i]);
2270 // process the command line arguments
2271 for(size_t i=1; i < args.size(); ++i)
2273 // handle the simple commandline arguments
2274 this->HandleCommandLineArguments(i,args);
2276 // handle the script arguments -S -SR -SP
2277 this->HandleScriptArguments(i,args,SRArgumentSpecified);
2279 // handle a request for a dashboard
2280 std::string arg = args[i];
2281 if(this->CheckArgument(arg, "-D", "--dashboard") && i < args.size() - 1 )
2283 this->ProduceXML = true;
2285 std::string targ = args[i];
2286 // AddTestsForDashboard parses the dashboard type and converts it
2287 // into the separate stages
2288 if (!this->AddTestsForDashboardType(targ))
2290 if (!this->AddVariableDefinition(targ))
2292 this->ErrorMessageUnknownDashDValue(targ);
2293 executeTests = false;
2298 // If it's not exactly -D, but it starts with -D, then try to parse out
2299 // a variable definition from it, same as CMake does. Unsuccessful
2300 // attempts are simply ignored since previous ctest versions ignore
2301 // this too. (As well as many other unknown command line args.)
2303 if(arg != "-D" && cmSystemTools::StringStartsWith(arg.c_str(), "-D"))
2305 std::string input = arg.substr(2);
2306 this->AddVariableDefinition(input);
2309 if(this->CheckArgument(arg, "-T", "--test-action") &&
2310 (i < args.size() -1) )
2312 this->ProduceXML = true;
2314 if ( !this->SetTest(args[i].c_str(), false) )
2316 executeTests = false;
2317 cmCTestLog(this, ERROR_MESSAGE,
2318 "CTest -T called with incorrect option: "
2319 << args[i].c_str() << std::endl);
2320 cmCTestLog(this, ERROR_MESSAGE, "Available options are:" << std::endl
2321 << " " << ctestExec << " -T all" << std::endl
2322 << " " << ctestExec << " -T start" << std::endl
2323 << " " << ctestExec << " -T update" << std::endl
2324 << " " << ctestExec << " -T configure" << std::endl
2325 << " " << ctestExec << " -T build" << std::endl
2326 << " " << ctestExec << " -T test" << std::endl
2327 << " " << ctestExec << " -T coverage" << std::endl
2328 << " " << ctestExec << " -T memcheck" << std::endl
2329 << " " << ctestExec << " -T notes" << std::endl
2330 << " " << ctestExec << " -T submit" << std::endl);
2334 // what type of test model
2335 if(this->CheckArgument(arg, "-M", "--test-model") &&
2336 (i < args.size() -1) )
2339 std::string const& str = args[i];
2340 if ( cmSystemTools::LowerCase(str) == "nightly" )
2342 this->SetTestModel(cmCTest::NIGHTLY);
2344 else if ( cmSystemTools::LowerCase(str) == "continuous" )
2346 this->SetTestModel(cmCTest::CONTINUOUS);
2348 else if ( cmSystemTools::LowerCase(str) == "experimental" )
2350 this->SetTestModel(cmCTest::EXPERIMENTAL);
2354 executeTests = false;
2355 cmCTestLog(this, ERROR_MESSAGE,
2356 "CTest -M called with incorrect option: " << str.c_str()
2358 cmCTestLog(this, ERROR_MESSAGE, "Available options are:" << std::endl
2359 << " " << ctestExec << " -M Continuous" << std::endl
2360 << " " << ctestExec << " -M Experimental" << std::endl
2361 << " " << ctestExec << " -M Nightly" << std::endl);
2365 if(this->CheckArgument(arg, "--extra-submit") && i < args.size() - 1)
2367 this->ProduceXML = true;
2368 this->SetTest("Submit");
2370 if ( !this->SubmitExtraFiles(args[i].c_str()) )
2376 // --build-and-test options
2377 if(this->CheckArgument(arg, "--build-and-test") && i < args.size() - 1)
2379 cmakeAndTest = true;
2382 if(this->CheckArgument(arg, "--schedule-random"))
2384 this->ScheduleType = "Random";
2387 // pass the argument to all the handlers as well, but i may no longer be
2388 // set to what it was originally so I'm not sure this is working as
2390 cmCTest::t_TestingHandlers::iterator it;
2391 for ( it = this->TestingHandlers.begin();
2392 it != this->TestingHandlers.end();
2395 if ( !it->second->ProcessCommandLineArguments(arg, i, args) )
2397 cmCTestLog(this, ERROR_MESSAGE,
2398 "Problem parsing command line arguments within a handler");
2402 } // the close of the for argument loop
2404 if (!this->ParallelLevelSetInCli)
2406 if (const char *parallel = cmSystemTools::GetEnv("CTEST_PARALLEL_LEVEL"))
2408 int plevel = atoi(parallel);
2409 this->SetParallelLevel(plevel);
2413 // now what sould cmake do? if --build-and-test was specified then
2414 // we run the build and test handler and return
2417 this->Verbose = true;
2418 cmCTestBuildAndTestHandler* handler =
2419 static_cast<cmCTestBuildAndTestHandler*>(this->GetHandler("buildtest"));
2420 int retv = handler->ProcessHandler();
2421 *output = handler->GetOutput();
2422 #ifdef CMAKE_BUILD_WITH_CMAKE
2423 cmDynamicLoader::FlushCache();
2427 cmCTestLog(this, DEBUG, "build and test failing returning: " << retv
2436 // call process directory
2437 if (this->RunConfigurationScript)
2439 if ( this->ExtraVerbose )
2441 cmCTestLog(this, OUTPUT, "* Extra verbosity turned on" << std::endl);
2443 cmCTest::t_TestingHandlers::iterator it;
2444 for ( it = this->TestingHandlers.begin();
2445 it != this->TestingHandlers.end();
2448 it->second->SetVerbose(this->ExtraVerbose);
2449 it->second->SetSubmitIndex(this->SubmitIndex);
2451 this->GetHandler("script")->SetVerbose(this->Verbose);
2452 res = this->GetHandler("script")->ProcessHandler();
2455 cmCTestLog(this, DEBUG, "running script failing returning: " << res
2462 // What is this? -V seems to be the same as -VV,
2463 // and Verbose is always on in this case
2464 this->ExtraVerbose = this->Verbose;
2465 this->Verbose = true;
2466 cmCTest::t_TestingHandlers::iterator it;
2467 for ( it = this->TestingHandlers.begin();
2468 it != this->TestingHandlers.end();
2471 it->second->SetVerbose(this->Verbose);
2472 it->second->SetSubmitIndex(this->SubmitIndex);
2474 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
2475 if(!this->Initialize(cwd.c_str(), 0))
2478 cmCTestLog(this, ERROR_MESSAGE, "Problem initializing the dashboard."
2483 res = this->ProcessTests();
2489 cmCTestLog(this, DEBUG, "Running a test(s) failed returning : " << res
2498 //----------------------------------------------------------------------
2499 void cmCTest::FindRunningCMake()
2501 // Find our own executable.
2502 this->CTestSelf = cmSystemTools::GetExecutableDirectory();
2503 this->CTestSelf += "/ctest";
2504 this->CTestSelf += cmSystemTools::GetExecutableExtension();
2505 if(!cmSystemTools::FileExists(this->CTestSelf.c_str()))
2507 cmSystemTools::Error("CTest executable cannot be found at ",
2508 this->CTestSelf.c_str());
2511 this->CMakeSelf = cmSystemTools::GetExecutableDirectory();
2512 this->CMakeSelf += "/cmake";
2513 this->CMakeSelf += cmSystemTools::GetExecutableExtension();
2514 if(!cmSystemTools::FileExists(this->CMakeSelf.c_str()))
2516 cmSystemTools::Error("CMake executable cannot be found at ",
2517 this->CMakeSelf.c_str());
2521 //----------------------------------------------------------------------
2522 void cmCTest::SetNotesFiles(const char* notes)
2528 this->NotesFiles = notes;
2531 //----------------------------------------------------------------------
2532 void cmCTest::SetStopTime(std::string time)
2534 this->StopTime = time;
2535 this->DetermineNextDayStop();
2538 //----------------------------------------------------------------------
2539 int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf)
2542 VectorOfStrings dirs;
2543 VectorOfStrings ndirs;
2544 cmCTestLog(this, DEBUG, "* Read custom CTest configuration directory: "
2545 << dir << std::endl);
2547 std::string fname = dir;
2548 fname += "/CTestCustom.cmake";
2549 cmCTestLog(this, DEBUG, "* Check for file: "
2550 << fname.c_str() << std::endl);
2551 if ( cmSystemTools::FileExists(fname.c_str()) )
2553 cmCTestLog(this, DEBUG, "* Read custom CTest configuration file: "
2554 << fname.c_str() << std::endl);
2555 bool erroroc = cmSystemTools::GetErrorOccuredFlag();
2556 cmSystemTools::ResetErrorOccuredFlag();
2558 if ( !mf->ReadListFile(0, fname.c_str()) ||
2559 cmSystemTools::GetErrorOccuredFlag() )
2561 cmCTestLog(this, ERROR_MESSAGE,
2562 "Problem reading custom configuration: "
2563 << fname.c_str() << std::endl);
2568 cmSystemTools::SetErrorOccured();
2572 std::string rexpr = dir;
2573 rexpr += "/CTestCustom.ctest";
2574 cmCTestLog(this, DEBUG, "* Check for file: "
2575 << rexpr.c_str() << std::endl);
2576 if ( !found && cmSystemTools::FileExists(rexpr.c_str()) )
2580 gl.FindFiles(rexpr);
2581 std::vector<std::string>& files = gl.GetFiles();
2582 std::vector<std::string>::iterator fileIt;
2583 for ( fileIt = files.begin(); fileIt != files.end();
2586 cmCTestLog(this, DEBUG, "* Read custom CTest configuration file: "
2587 << fileIt->c_str() << std::endl);
2588 if ( !mf->ReadListFile(0, fileIt->c_str()) ||
2589 cmSystemTools::GetErrorOccuredFlag() )
2591 cmCTestLog(this, ERROR_MESSAGE,
2592 "Problem reading custom configuration: "
2593 << fileIt->c_str() << std::endl);
2601 cmCTest::t_TestingHandlers::iterator it;
2602 for ( it = this->TestingHandlers.begin();
2603 it != this->TestingHandlers.end(); ++ it )
2605 cmCTestLog(this, DEBUG,
2606 "* Read custom CTest configuration vectors for handler: "
2607 << it->first.c_str() << " (" << it->second << ")" << std::endl);
2608 it->second->PopulateCustomVectors(mf);
2615 //----------------------------------------------------------------------
2616 void cmCTest::PopulateCustomVector(cmMakefile* mf, const char* def,
2617 VectorOfStrings& vec)
2623 const char* dval = mf->GetDefinition(def);
2628 cmCTestLog(this, DEBUG, "PopulateCustomVector: " << def << std::endl);
2629 std::vector<std::string> slist;
2630 cmSystemTools::ExpandListArgument(dval, slist);
2631 std::vector<std::string>::iterator it;
2635 for ( it = slist.begin(); it != slist.end(); ++it )
2637 cmCTestLog(this, DEBUG, " -- " << it->c_str() << std::endl);
2638 vec.push_back(it->c_str());
2642 //----------------------------------------------------------------------
2643 void cmCTest::PopulateCustomInteger(cmMakefile* mf, const char* def, int& val)
2649 const char* dval = mf->GetDefinition(def);
2657 //----------------------------------------------------------------------
2658 std::string cmCTest::GetShortPathToFile(const char* cfname)
2660 const std::string& sourceDir
2661 = cmSystemTools::CollapseFullPath(
2662 this->GetCTestConfiguration("SourceDirectory").c_str());
2663 const std::string& buildDir
2664 = cmSystemTools::CollapseFullPath(
2665 this->GetCTestConfiguration("BuildDirectory").c_str());
2666 std::string fname = cmSystemTools::CollapseFullPath(cfname);
2668 // Find relative paths to both directories
2669 std::string srcRelpath
2670 = cmSystemTools::RelativePath(sourceDir.c_str(), fname.c_str());
2671 std::string bldRelpath
2672 = cmSystemTools::RelativePath(buildDir.c_str(), fname.c_str());
2674 // If any contains "." it is not parent directory
2675 bool inSrc = srcRelpath.find("..") == srcRelpath.npos;
2676 bool inBld = bldRelpath.find("..") == bldRelpath.npos;
2677 // TODO: Handle files with .. in their name
2679 std::string* res = 0;
2681 if ( inSrc && inBld )
2683 // If both have relative path with no dots, pick the shorter one
2684 if ( srcRelpath.size() < bldRelpath.size() )
2710 cmSystemTools::ConvertToUnixSlashes(*res);
2713 if ( path[path.size()-1] == '/' )
2715 path = path.substr(0, path.size()-1);
2719 cmsys::SystemTools::ReplaceString(path, ":", "_");
2720 cmsys::SystemTools::ReplaceString(path, " ", "_");
2724 //----------------------------------------------------------------------
2725 std::string cmCTest::GetCTestConfiguration(const char *name)
2727 if ( this->CTestConfigurationOverwrites.find(name) !=
2728 this->CTestConfigurationOverwrites.end() )
2730 return this->CTestConfigurationOverwrites[name];
2732 return this->CTestConfiguration[name];
2735 //----------------------------------------------------------------------
2736 void cmCTest::EmptyCTestConfiguration()
2738 this->CTestConfiguration.clear();
2741 //----------------------------------------------------------------------
2742 void cmCTest::DetermineNextDayStop()
2745 time_t current_time = time(0);
2746 lctime = gmtime(¤t_time);
2747 int gm_hour = lctime->tm_hour;
2748 time_t gm_time = mktime(lctime);
2749 lctime = localtime(¤t_time);
2750 int local_hour = lctime->tm_hour;
2752 int tzone_offset = local_hour - gm_hour;
2753 if(gm_time > current_time && gm_hour < local_hour)
2755 // this means gm_time is on the next day
2758 else if(gm_time < current_time && gm_hour > local_hour)
2760 // this means gm_time is on the previous day
2764 tzone_offset *= 100;
2766 sprintf(buf, "%d%02d%02d %s %+05i",
2767 lctime->tm_year + 1900,
2770 this->StopTime.c_str(),
2773 time_t stop_time = curl_getdate(buf, ¤t_time);
2775 if(stop_time < current_time)
2777 this->NextDayStopTime = true;
2781 //----------------------------------------------------------------------
2782 void cmCTest::SetCTestConfiguration(const char *name, const char* value)
2784 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "SetCTestConfiguration:"
2785 << name << ":" << (value ? value : "(null)") << "\n");
2793 this->CTestConfiguration.erase(name);
2796 this->CTestConfiguration[name] = value;
2800 //----------------------------------------------------------------------
2801 std::string cmCTest::GetCurrentTag()
2803 return this->CurrentTag;
2806 //----------------------------------------------------------------------
2807 std::string cmCTest::GetBinaryDir()
2809 return this->BinaryDir;
2812 //----------------------------------------------------------------------
2813 std::string const& cmCTest::GetConfigType()
2815 return this->ConfigType;
2818 //----------------------------------------------------------------------
2819 bool cmCTest::GetShowOnly()
2821 return this->ShowOnly;
2824 //----------------------------------------------------------------------
2825 int cmCTest::GetMaxTestNameWidth() const
2827 return this->MaxTestNameWidth;
2830 //----------------------------------------------------------------------
2831 void cmCTest::SetProduceXML(bool v)
2833 this->ProduceXML = v;
2836 //----------------------------------------------------------------------
2837 bool cmCTest::GetProduceXML()
2839 return this->ProduceXML;
2842 //----------------------------------------------------------------------
2843 const char* cmCTest::GetSpecificTrack()
2845 if ( this->SpecificTrack.empty() )
2849 return this->SpecificTrack.c_str();
2852 //----------------------------------------------------------------------
2853 void cmCTest::SetSpecificTrack(const char* track)
2857 this->SpecificTrack = "";
2860 this->SpecificTrack = track;
2863 //----------------------------------------------------------------------
2864 void cmCTest::AddSubmitFile(Part part, const char* name)
2866 this->Parts[part].SubmitFiles.push_back(name);
2869 //----------------------------------------------------------------------
2870 void cmCTest::AddCTestConfigurationOverwrite(const char* encstr)
2872 std::string overStr = encstr;
2873 size_t epos = overStr.find("=");
2874 if ( epos == overStr.npos )
2876 cmCTestLog(this, ERROR_MESSAGE,
2877 "CTest configuration overwrite specified in the wrong format."
2879 << "Valid format is: --overwrite key=value" << std::endl
2880 << "The specified was: --overwrite " << overStr.c_str() << std::endl);
2883 std::string key = overStr.substr(0, epos);
2884 std::string value = overStr.substr(epos+1, overStr.npos);
2885 this->CTestConfigurationOverwrites[key] = value;
2888 //----------------------------------------------------------------------
2889 void cmCTest::SetConfigType(const char* ct)
2891 this->ConfigType = ct?ct:"";
2892 cmSystemTools::ReplaceString(this->ConfigType, ".\\", "");
2893 std::string confTypeEnv
2894 = "CMAKE_CONFIG_TYPE=" + this->ConfigType;
2895 cmSystemTools::PutEnv(confTypeEnv.c_str());
2898 //----------------------------------------------------------------------
2899 bool cmCTest::SetCTestConfigurationFromCMakeVariable(cmMakefile* mf,
2900 const char* dconfig, const char* cmake_var)
2903 ctvar = mf->GetDefinition(cmake_var);
2908 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
2909 "SetCTestConfigurationFromCMakeVariable:"
2910 << dconfig << ":" << cmake_var << std::endl);
2911 this->SetCTestConfiguration(dconfig, ctvar);
2915 bool cmCTest::RunCommand(
2916 const char* command,
2917 std::string* stdOut,
2918 std::string* stdErr,
2923 std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);
2930 std::vector<const char*> argv;
2931 for(std::vector<cmStdString>::const_iterator a = args.begin();
2932 a != args.end(); ++a)
2934 argv.push_back(a->c_str());
2941 cmsysProcess* cp = cmsysProcess_New();
2942 cmsysProcess_SetCommand(cp, &*argv.begin());
2943 cmsysProcess_SetWorkingDirectory(cp, dir);
2944 if(cmSystemTools::GetRunCommandHideConsole())
2946 cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
2948 cmsysProcess_SetTimeout(cp, timeout);
2949 cmsysProcess_Execute(cp);
2951 std::vector<char> tempOutput;
2952 std::vector<char> tempError;
2959 res = cmsysProcess_WaitForData(cp, &data, &length, 0);
2962 case cmsysProcess_Pipe_STDOUT:
2963 tempOutput.insert(tempOutput.end(), data, data+length);
2965 case cmsysProcess_Pipe_STDERR:
2966 tempError.insert(tempError.end(), data, data+length);
2971 if ( (res == cmsysProcess_Pipe_STDOUT ||
2972 res == cmsysProcess_Pipe_STDERR) && this->ExtraVerbose )
2974 cmSystemTools::Stdout(data, length);
2978 cmsysProcess_WaitForExit(cp, 0);
2979 if ( tempOutput.size() > 0 )
2981 stdOut->append(&*tempOutput.begin(), tempOutput.size());
2983 if ( tempError.size() > 0 )
2985 stdErr->append(&*tempError.begin(), tempError.size());
2989 if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exited)
2993 *retVal = cmsysProcess_GetExitValue(cp);
2997 if ( cmsysProcess_GetExitValue(cp) != 0 )
3003 else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exception)
3005 const char* exception_str = cmsysProcess_GetExceptionString(cp);
3006 cmCTestLog(this, ERROR_MESSAGE, exception_str << std::endl);
3007 stdErr->append(exception_str, strlen(exception_str));
3010 else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Error)
3012 const char* error_str = cmsysProcess_GetErrorString(cp);
3013 cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
3014 stdErr->append(error_str, strlen(error_str));
3017 else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Expired)
3019 const char* error_str = "Process terminated due to timeout\n";
3020 cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
3021 stdErr->append(error_str, strlen(error_str));
3025 cmsysProcess_Delete(cp);
3029 //----------------------------------------------------------------------
3030 void cmCTest::SetOutputLogFileName(const char* name)
3032 if ( this->OutputLogFile)
3034 delete this->OutputLogFile;
3035 this->OutputLogFile= 0;
3039 this->OutputLogFile = new cmGeneratedFileStream(name);
3043 //----------------------------------------------------------------------
3044 static const char* cmCTestStringLogType[] =
3049 "HANDLER_VERBOSE_OUTPUT",
3055 //----------------------------------------------------------------------
3063 #define cmCTestLogOutputFileLine(stream) \
3064 if ( this->ShowLineNumbers ) \
3066 (stream) << std::endl << file << ":" << line << " "; \
3069 void cmCTest::InitStreams()
3071 // By default we write output to the process output streams.
3072 this->StreamOut = &std::cout;
3073 this->StreamErr = &std::cerr;
3076 void cmCTest::Log(int logType, const char* file, int line, const char* msg)
3078 if ( !msg || !*msg )
3082 if ( this->OutputLogFile )
3084 bool display = true;
3085 if ( logType == cmCTest::DEBUG && !this->Debug ) { display = false; }
3086 if ( logType == cmCTest::HANDLER_VERBOSE_OUTPUT && !this->Debug &&
3087 !this->ExtraVerbose ) { display = false; }
3090 cmCTestLogOutputFileLine(*this->OutputLogFile);
3091 if ( logType != this->OutputLogFileLastTag )
3093 *this->OutputLogFile << "[";
3094 if ( logType >= OTHER || logType < 0 )
3096 *this->OutputLogFile << "OTHER";
3100 *this->OutputLogFile << cmCTestStringLogType[logType];
3102 *this->OutputLogFile << "] " << std::endl << std::flush;
3104 *this->OutputLogFile << msg << std::flush;
3105 if ( logType != this->OutputLogFileLastTag )
3107 *this->OutputLogFile << std::endl << std::flush;
3108 this->OutputLogFileLastTag = logType;
3114 std::ostream& out = *this->StreamOut;
3115 std::ostream& err = *this->StreamErr;
3121 cmCTestLogOutputFileLine(out);
3126 case OUTPUT: case HANDLER_OUTPUT:
3127 if ( this->Debug || this->Verbose )
3129 cmCTestLogOutputFileLine(out);
3134 case HANDLER_VERBOSE_OUTPUT:
3135 if ( this->Debug || this->ExtraVerbose )
3137 cmCTestLogOutputFileLine(out);
3143 cmCTestLogOutputFileLine(err);
3148 cmCTestLogOutputFileLine(err);
3151 cmSystemTools::SetErrorOccured();
3154 cmCTestLogOutputFileLine(out);
3161 //-------------------------------------------------------------------------
3162 double cmCTest::GetRemainingTimeAllowed()
3164 if (!this->GetHandler("script"))
3169 cmCTestScriptHandler* ch
3170 = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
3172 return ch->GetRemainingTimeAllowed();
3175 //----------------------------------------------------------------------
3176 void cmCTest::OutputTestErrors(std::vector<char> const &process_output)
3178 std::string test_outputs("\n*** Test Failed:\n");
3179 if(process_output.size())
3181 test_outputs.append(&*process_output.begin(), process_output.size());
3183 cmCTestLog(this, HANDLER_OUTPUT, test_outputs << std::endl << std::flush);
3186 //----------------------------------------------------------------------
3187 bool cmCTest::CompressString(std::string& str)
3192 unsigned char* in = reinterpret_cast<unsigned char*>(
3193 const_cast<char*>(str.c_str()));
3194 //zlib makes the guarantee that this is the maximum output size
3195 int outSize = static_cast<int>(
3196 static_cast<double>(str.size()) * 1.001 + 13.0);
3197 unsigned char* out = new unsigned char[outSize];
3199 strm.zalloc = Z_NULL;
3200 strm.zfree = Z_NULL;
3201 strm.opaque = Z_NULL;
3202 ret = deflateInit(&strm, -1); //default compression level
3209 strm.avail_in = static_cast<uInt>(str.size());
3211 strm.avail_out = outSize;
3212 strm.next_out = out;
3213 ret = deflate(&strm, Z_FINISH);
3215 if(ret == Z_STREAM_ERROR || ret != Z_STREAM_END)
3217 cmCTestLog(this, ERROR_MESSAGE, "Error during gzip compression."
3223 (void)deflateEnd(&strm);
3225 // Now base64 encode the resulting binary string
3226 unsigned char* base64EncodedBuffer
3227 = new unsigned char[static_cast<int>(outSize * 1.5)];
3230 = cmsysBase64_Encode(out, strm.total_out, base64EncodedBuffer, 1);
3233 str.append(reinterpret_cast<char*>(base64EncodedBuffer), rlen);
3235 delete [] base64EncodedBuffer;