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>
56 #if defined(__BEOS__) && !defined(__HAIKU__)
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->OutputTestOutputOnTestFailure = false;
331 this->ComputedCompressTestOutput = false;
332 this->ComputedCompressMemCheckOutput = false;
333 if(cmSystemTools::GetEnv("CTEST_OUTPUT_ON_FAILURE"))
335 this->OutputTestOutputOnTestFailure = true;
339 this->Parts[PartStart].SetName("Start");
340 this->Parts[PartUpdate].SetName("Update");
341 this->Parts[PartConfigure].SetName("Configure");
342 this->Parts[PartBuild].SetName("Build");
343 this->Parts[PartTest].SetName("Test");
344 this->Parts[PartCoverage].SetName("Coverage");
345 this->Parts[PartMemCheck].SetName("MemCheck");
346 this->Parts[PartSubmit].SetName("Submit");
347 this->Parts[PartNotes].SetName("Notes");
348 this->Parts[PartExtraFiles].SetName("ExtraFiles");
349 this->Parts[PartUpload].SetName("Upload");
351 // Fill the part name-to-id map.
352 for(Part p = PartStart; p != PartCount; p = Part(p+1))
354 this->PartMap[cmSystemTools::LowerCase(this->Parts[p].GetName())] = p;
357 this->ShortDateFormat = true;
359 this->TestingHandlers["build"] = new cmCTestBuildHandler;
360 this->TestingHandlers["buildtest"] = new cmCTestBuildAndTestHandler;
361 this->TestingHandlers["coverage"] = new cmCTestCoverageHandler;
362 this->TestingHandlers["script"] = new cmCTestScriptHandler;
363 this->TestingHandlers["test"] = new cmCTestTestHandler;
364 this->TestingHandlers["update"] = new cmCTestUpdateHandler;
365 this->TestingHandlers["configure"] = new cmCTestConfigureHandler;
366 this->TestingHandlers["memcheck"] = new cmCTestMemCheckHandler;
367 this->TestingHandlers["submit"] = new cmCTestSubmitHandler;
368 this->TestingHandlers["upload"] = new cmCTestUploadHandler;
370 cmCTest::t_TestingHandlers::iterator it;
371 for ( it = this->TestingHandlers.begin();
372 it != this->TestingHandlers.end(); ++ it )
374 it->second->SetCTestInstance(this);
377 // Make sure we can capture the build tool output.
378 cmSystemTools::EnableVSConsoleOutput();
381 //----------------------------------------------------------------------
384 cmCTest::t_TestingHandlers::iterator it;
385 for ( it = this->TestingHandlers.begin();
386 it != this->TestingHandlers.end(); ++ it )
391 this->SetOutputLogFileName(0);
394 void cmCTest::SetParallelLevel(int level)
396 this->ParallelLevel = level < 1 ? 1 : level;
399 //----------------------------------------------------------------------------
400 bool cmCTest::ShouldCompressTestOutput()
402 if(!this->ComputedCompressTestOutput)
404 std::string cdashVersion = this->GetCDashVersion();
406 bool cdashSupportsGzip = cmSystemTools::VersionCompare(
407 cmSystemTools::OP_GREATER, cdashVersion.c_str(), "1.6") ||
408 cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
409 cdashVersion.c_str(), "1.6");
410 this->CompressTestOutput &= cdashSupportsGzip;
411 this->ComputedCompressTestOutput = true;
413 return this->CompressTestOutput;
416 //----------------------------------------------------------------------------
417 bool cmCTest::ShouldCompressMemCheckOutput()
419 if(!this->ComputedCompressMemCheckOutput)
421 std::string cdashVersion = this->GetCDashVersion();
423 bool compressionSupported = cmSystemTools::VersionCompare(
424 cmSystemTools::OP_GREATER, cdashVersion.c_str(), "1.9.0");
425 this->CompressMemCheckOutput &= compressionSupported;
426 this->ComputedCompressMemCheckOutput = true;
428 return this->CompressMemCheckOutput;
431 //----------------------------------------------------------------------------
432 std::string cmCTest::GetCDashVersion()
434 #ifdef CMAKE_BUILD_WITH_CMAKE
435 //First query the server. If that fails, fall back to the local setting
436 std::string response;
437 std::string url = "http://";
438 url += this->GetCTestConfiguration("DropSite");
440 std::string cdashUri = this->GetCTestConfiguration("DropLocation");
441 cdashUri = cdashUri.substr(0, cdashUri.find("/submit.php"));
444 if ( ! cdashUri.empty() )
446 url += cdashUri + "/api/getversion.php";
447 res = cmCTest::HTTPRequest(url, cmCTest::HTTP_GET, response, "", "", 3);
450 return res ? this->GetCTestConfiguration("CDashVersion") : response;
452 return this->GetCTestConfiguration("CDashVersion");
456 //----------------------------------------------------------------------------
457 cmCTest::Part cmCTest::GetPartFromName(const char* name)
459 // Look up by lower-case to make names case-insensitive.
460 std::string lower_name = cmSystemTools::LowerCase(name);
461 PartMapType::const_iterator i = this->PartMap.find(lower_name);
462 if(i != this->PartMap.end())
467 // The string does not name a valid part.
471 //----------------------------------------------------------------------
472 int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
474 cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
475 if(!this->InteractiveDebugMode)
477 this->BlockTestErrorDiagnostics();
481 cmSystemTools::PutEnv("CTEST_INTERACTIVE_DEBUG_MODE=1");
484 this->BinaryDir = binary_dir;
485 cmSystemTools::ConvertToUnixSlashes(this->BinaryDir);
487 this->UpdateCTestConfiguration();
489 cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
490 if ( this->ProduceXML )
492 cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
493 cmCTestLog(this, OUTPUT,
494 " Site: " << this->GetCTestConfiguration("Site") << std::endl
495 << " Build name: " << this->GetCTestConfiguration("BuildName")
497 cmCTestLog(this, DEBUG, "Produce XML is on" << std::endl);
498 if ( this->TestModel == cmCTest::NIGHTLY &&
499 this->GetCTestConfiguration("NightlyStartTime").empty() )
501 cmCTestLog(this, WARNING,
502 "WARNING: No nightly start time found please set in"
503 " CTestConfig.cmake or DartConfig.cmake" << std::endl);
504 cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
510 cmGlobalGenerator gg;
511 gg.SetCMakeInstance(&cm);
512 cmsys::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator());
513 cmMakefile *mf = lg->GetMakefile();
514 if ( !this->ReadCustomConfigurationFileTree(this->BinaryDir.c_str(), mf) )
516 cmCTestLog(this, DEBUG, "Cannot find custom configuration file tree"
521 if ( this->ProduceXML )
523 // Verify "Testing" directory exists:
525 std::string testingDir = this->BinaryDir + "/Testing";
526 if ( cmSystemTools::FileExists(testingDir.c_str()) )
528 if ( !cmSystemTools::FileIsDirectory(testingDir.c_str()) )
530 cmCTestLog(this, ERROR_MESSAGE, "File " << testingDir
531 << " is in the place of the testing directory" << std::endl);
537 if ( !cmSystemTools::MakeDirectory(testingDir.c_str()) )
539 cmCTestLog(this, ERROR_MESSAGE, "Cannot create directory "
540 << testingDir << std::endl);
545 // Create new "TAG" file or read existing one:
547 bool createNewTag = true;
550 createNewTag = command->ShouldCreateNewTag();
553 std::string tagfile = testingDir + "/TAG";
554 std::ifstream tfin(tagfile.c_str());
559 time_t tctime = time(0);
560 if ( this->TomorrowTag )
562 tctime += ( 24 * 60 * 60 );
564 struct tm *lctime = gmtime(&tctime);
565 if ( tfin && cmSystemTools::GetLineFromStream(tfin, tag) )
572 sscanf(tag.c_str(), "%04d%02d%02d-%02d%02d",
573 &year, &mon, &day, &hour, &min);
574 if ( year != lctime->tm_year + 1900 ||
575 mon != lctime->tm_mon+1 ||
576 day != lctime->tm_mday )
581 if ( cmSystemTools::GetLineFromStream(tfin, tagmode) )
583 if (tagmode.size() > 4 && !this->Parts[PartStart])
585 this->TestModel = cmCTest::GetTestModelFromString(tagmode.c_str());
590 if (tag.size() == 0 || (0 != command) || this->Parts[PartStart])
592 cmCTestLog(this, DEBUG, "TestModel: " << this->GetTestModelString()
594 cmCTestLog(this, DEBUG, "TestModel: " << this->TestModel << std::endl);
595 if ( this->TestModel == cmCTest::NIGHTLY )
597 lctime = this->GetNightlyTime(
598 this->GetCTestConfiguration("NightlyStartTime"),
601 char datestring[100];
602 sprintf(datestring, "%04d%02d%02d-%02d%02d",
603 lctime->tm_year + 1900,
609 std::ofstream ofs(tagfile.c_str());
612 ofs << tag << std::endl;
613 ofs << this->GetTestModelString() << std::endl;
618 cmCTestLog(this, OUTPUT, "Create new tag: " << tag << " - "
619 << this->GetTestModelString() << std::endl);
627 cmSystemTools::GetLineFromStream(tfin, tag);
633 cmCTestLog(this, ERROR_MESSAGE,
634 "Cannot read existing TAG file in " << testingDir
639 cmCTestLog(this, OUTPUT, " Use existing tag: " << tag << " - "
640 << this->GetTestModelString() << std::endl);
643 this->CurrentTag = tag;
649 //----------------------------------------------------------------------
650 bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command)
653 = this->GetCTestConfiguration("SourceDirectory").c_str();
654 std::string bld_dir = this->GetCTestConfiguration("BuildDirectory").c_str();
655 this->DartVersion = 1;
656 for(Part p = PartStart; p != PartCount; p = Part(p+1))
658 this->Parts[p].SubmitFiles.clear();
661 cmMakefile* mf = command->GetMakefile();
664 std::string src_dir_fname = src_dir;
665 src_dir_fname += "/CTestConfig.cmake";
666 cmSystemTools::ConvertToUnixSlashes(src_dir_fname);
668 std::string bld_dir_fname = bld_dir;
669 bld_dir_fname += "/CTestConfig.cmake";
670 cmSystemTools::ConvertToUnixSlashes(bld_dir_fname);
672 if ( cmSystemTools::FileExists(bld_dir_fname.c_str()) )
674 fname = bld_dir_fname;
676 else if ( cmSystemTools::FileExists(src_dir_fname.c_str()) )
678 fname = src_dir_fname;
681 if ( !fname.empty() )
683 cmCTestLog(this, OUTPUT, " Reading ctest configuration file: "
684 << fname.c_str() << std::endl);
685 bool readit = mf->ReadListFile(mf->GetCurrentListFile(),
689 std::string m = "Could not find include file: ";
691 command->SetError(m.c_str());
697 cmCTestLog(this, WARNING,
698 "Cannot locate CTest configuration: in BuildDirectory: "
699 << bld_dir_fname.c_str() << std::endl);
700 cmCTestLog(this, WARNING,
701 "Cannot locate CTest configuration: in SourceDirectory: "
702 << src_dir_fname.c_str() << std::endl);
705 this->SetCTestConfigurationFromCMakeVariable(mf, "NightlyStartTime",
706 "CTEST_NIGHTLY_START_TIME");
707 this->SetCTestConfigurationFromCMakeVariable(mf, "Site", "CTEST_SITE");
708 this->SetCTestConfigurationFromCMakeVariable(mf, "BuildName",
710 const char* dartVersion = mf->GetDefinition("CTEST_DART_SERVER_VERSION");
713 this->DartVersion = atoi(dartVersion);
714 if ( this->DartVersion < 0 )
716 cmCTestLog(this, ERROR_MESSAGE, "Invalid Dart server version: "
717 << dartVersion << ". Please specify the version number."
723 if ( !this->Initialize(bld_dir.c_str(), command) )
727 cmCTestLog(this, OUTPUT, " Use " << this->GetTestModelString()
728 << " tag: " << this->GetCurrentTag() << std::endl);
733 //----------------------------------------------------------------------
734 bool cmCTest::UpdateCTestConfiguration()
736 if ( this->SuppressUpdatingCTestConfiguration )
740 std::string fileName = this->CTestConfigFile;
741 if ( fileName.empty() )
743 fileName = this->BinaryDir + "/CTestConfiguration.ini";
744 if ( !cmSystemTools::FileExists(fileName.c_str()) )
746 fileName = this->BinaryDir + "/DartConfiguration.tcl";
749 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "UpdateCTestConfiguration from :"
750 << fileName.c_str() << "\n");
751 if ( !cmSystemTools::FileExists(fileName.c_str()) )
753 // No need to exit if we are not producing XML
754 if ( this->ProduceXML )
756 cmCTestLog(this, ERROR_MESSAGE, "Cannot find file: " << fileName.c_str()
763 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Parse Config file:"
764 << fileName.c_str() << "\n");
765 // parse the dart test file
766 std::ifstream fin(fileName.c_str());
777 fin.getline(buffer, 1023);
779 std::string line = cmCTest::CleanString(buffer);
784 while ( fin && (line[line.size()-1] == '\\') )
786 line = line.substr(0, line.size()-1);
788 fin.getline(buffer, 1023);
790 line += cmCTest::CleanString(buffer);
792 if ( line[0] == '#' )
796 std::string::size_type cpos = line.find_first_of(":");
797 if ( cpos == line.npos )
801 std::string key = line.substr(0, cpos);
803 = cmCTest::CleanString(line.substr(cpos+1, line.npos));
804 this->CTestConfiguration[key] = value;
808 if ( !this->GetCTestConfiguration("BuildDirectory").empty() )
810 this->BinaryDir = this->GetCTestConfiguration("BuildDirectory");
811 cmSystemTools::ChangeDirectory(this->BinaryDir.c_str());
813 this->TimeOut = atoi(this->GetCTestConfiguration("TimeOut").c_str());
814 if ( this->ProduceXML )
816 this->CompressXMLFiles = cmSystemTools::IsOn(
817 this->GetCTestConfiguration("CompressSubmission").c_str());
822 //----------------------------------------------------------------------
823 void cmCTest::BlockTestErrorDiagnostics()
825 cmSystemTools::PutEnv("DART_TEST_FROM_DART=1");
826 cmSystemTools::PutEnv("DASHBOARD_TEST_FROM_CTEST=" CMake_VERSION);
828 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
829 #elif defined(__BEOS__) || defined(__HAIKU__)
834 //----------------------------------------------------------------------
835 void cmCTest::SetTestModel(int mode)
837 this->InteractiveDebugMode = false;
838 this->TestModel = mode;
841 //----------------------------------------------------------------------
842 bool cmCTest::SetTest(const char* ttype, bool report)
844 if ( cmSystemTools::LowerCase(ttype) == "all" )
846 for(Part p = PartStart; p != PartCount; p = Part(p+1))
848 this->Parts[p].Enable();
852 Part p = this->GetPartFromName(ttype);
855 this->Parts[p].Enable();
862 cmCTestLog(this, ERROR_MESSAGE, "Don't know about test \"" << ttype
863 << "\" yet..." << std::endl);
869 //----------------------------------------------------------------------
870 void cmCTest::Finalize()
874 //----------------------------------------------------------------------
875 bool cmCTest::OpenOutputFile(const std::string& path,
876 const std::string& name, cmGeneratedFileStream& stream,
879 std::string testingDir = this->BinaryDir + "/Testing";
880 if ( path.size() > 0 )
882 testingDir += "/" + path;
884 if ( cmSystemTools::FileExists(testingDir.c_str()) )
886 if ( !cmSystemTools::FileIsDirectory(testingDir.c_str()) )
888 cmCTestLog(this, ERROR_MESSAGE, "File " << testingDir
889 << " is in the place of the testing directory"
896 if ( !cmSystemTools::MakeDirectory(testingDir.c_str()) )
898 cmCTestLog(this, ERROR_MESSAGE, "Cannot create directory " << testingDir
903 std::string filename = testingDir + "/" + name;
904 stream.Open(filename.c_str());
907 cmCTestLog(this, ERROR_MESSAGE, "Problem opening file: " << filename
913 if ( this->CompressXMLFiles )
915 stream.SetCompression(true);
921 //----------------------------------------------------------------------
922 bool cmCTest::AddIfExists(Part part, const char* file)
924 if ( this->CTestFileExists(file) )
926 this->AddSubmitFile(part, file);
930 std::string name = file;
932 if ( this->CTestFileExists(name.c_str()) )
934 this->AddSubmitFile(part, file);
944 //----------------------------------------------------------------------
945 bool cmCTest::CTestFileExists(const std::string& filename)
947 std::string testingDir = this->BinaryDir + "/Testing/" +
948 this->CurrentTag + "/" + filename;
949 return cmSystemTools::FileExists(testingDir.c_str());
952 //----------------------------------------------------------------------
953 cmCTestGenericHandler* cmCTest::GetInitializedHandler(const char* handler)
955 cmCTest::t_TestingHandlers::iterator it =
956 this->TestingHandlers.find(handler);
957 if ( it == this->TestingHandlers.end() )
961 it->second->Initialize();
965 //----------------------------------------------------------------------
966 cmCTestGenericHandler* cmCTest::GetHandler(const char* handler)
968 cmCTest::t_TestingHandlers::iterator it =
969 this->TestingHandlers.find(handler);
970 if ( it == this->TestingHandlers.end() )
977 //----------------------------------------------------------------------
978 int cmCTest::ExecuteHandler(const char* shandler)
980 cmCTestGenericHandler* handler = this->GetHandler(shandler);
985 handler->Initialize();
986 return handler->ProcessHandler();
989 //----------------------------------------------------------------------
990 int cmCTest::ProcessTests()
994 int update_count = 0;
996 for(Part p = PartStart; notest && p != PartCount; p = Part(p+1))
998 notest = !this->Parts[p];
1000 if (this->Parts[PartUpdate] &&
1001 (this->GetRemainingTimeAllowed() - 120 > 0))
1003 cmCTestGenericHandler* uphandler = this->GetHandler("update");
1004 uphandler->SetPersistentOption("SourceDirectory",
1005 this->GetCTestConfiguration("SourceDirectory").c_str());
1006 update_count = uphandler->ProcessHandler();
1007 if ( update_count < 0 )
1009 res |= cmCTest::UPDATE_ERRORS;
1012 if ( this->TestModel == cmCTest::CONTINUOUS && !update_count )
1016 if (this->Parts[PartConfigure] &&
1017 (this->GetRemainingTimeAllowed() - 120 > 0))
1019 if (this->GetHandler("configure")->ProcessHandler() < 0)
1021 res |= cmCTest::CONFIGURE_ERRORS;
1024 if (this->Parts[PartBuild] &&
1025 (this->GetRemainingTimeAllowed() - 120 > 0))
1027 this->UpdateCTestConfiguration();
1028 if (this->GetHandler("build")->ProcessHandler() < 0)
1030 res |= cmCTest::BUILD_ERRORS;
1033 if ((this->Parts[PartTest] || notest) &&
1034 (this->GetRemainingTimeAllowed() - 120 > 0))
1036 this->UpdateCTestConfiguration();
1037 if (this->GetHandler("test")->ProcessHandler() < 0)
1039 res |= cmCTest::TEST_ERRORS;
1042 if (this->Parts[PartCoverage] &&
1043 (this->GetRemainingTimeAllowed() - 120 > 0))
1045 this->UpdateCTestConfiguration();
1046 if (this->GetHandler("coverage")->ProcessHandler() < 0)
1048 res |= cmCTest::COVERAGE_ERRORS;
1051 if (this->Parts[PartMemCheck] &&
1052 (this->GetRemainingTimeAllowed() - 120 > 0))
1054 this->UpdateCTestConfiguration();
1055 if (this->GetHandler("memcheck")->ProcessHandler() < 0)
1057 res |= cmCTest::MEMORY_ERRORS;
1062 std::string notes_dir = this->BinaryDir + "/Testing/Notes";
1063 if ( cmSystemTools::FileIsDirectory(notes_dir.c_str()) )
1066 d.Load(notes_dir.c_str());
1068 for ( kk = 0; kk < d.GetNumberOfFiles(); kk ++ )
1070 const char* file = d.GetFile(kk);
1071 std::string fullname = notes_dir + "/" + file;
1072 if ( cmSystemTools::FileExists(fullname.c_str()) &&
1073 !cmSystemTools::FileIsDirectory(fullname.c_str()) )
1075 if ( this->NotesFiles.size() > 0 )
1077 this->NotesFiles += ";";
1079 this->NotesFiles += fullname;
1080 this->Parts[PartNotes].Enable();
1085 if (this->Parts[PartNotes])
1087 this->UpdateCTestConfiguration();
1088 if ( this->NotesFiles.size() )
1090 this->GenerateNotesFile(this->NotesFiles.c_str());
1093 if (this->Parts[PartSubmit])
1095 this->UpdateCTestConfiguration();
1096 if (this->GetHandler("submit")->ProcessHandler() < 0)
1098 res |= cmCTest::SUBMIT_ERRORS;
1103 cmCTestLog(this, ERROR_MESSAGE, "Errors while running CTest"
1109 //----------------------------------------------------------------------
1110 std::string cmCTest::GetTestModelString()
1112 if ( !this->SpecificTrack.empty() )
1114 return this->SpecificTrack;
1116 switch ( this->TestModel )
1118 case cmCTest::NIGHTLY:
1120 case cmCTest::CONTINUOUS:
1121 return "Continuous";
1123 return "Experimental";
1126 //----------------------------------------------------------------------
1127 int cmCTest::GetTestModelFromString(const char* str)
1131 return cmCTest::EXPERIMENTAL;
1133 std::string rstr = cmSystemTools::LowerCase(str);
1134 if ( strncmp(rstr.c_str(), "cont", 4) == 0 )
1136 return cmCTest::CONTINUOUS;
1138 if ( strncmp(rstr.c_str(), "nigh", 4) == 0 )
1140 return cmCTest::NIGHTLY;
1142 return cmCTest::EXPERIMENTAL;
1145 //######################################################################
1146 //######################################################################
1147 //######################################################################
1148 //######################################################################
1150 //----------------------------------------------------------------------
1151 int cmCTest::RunMakeCommand(const char* command, std::string* output,
1152 int* retVal, const char* dir, int timeout, std::ofstream& ofs)
1154 // First generate the command and arguments
1155 std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);
1162 std::vector<const char*> argv;
1163 for(std::vector<cmStdString>::const_iterator a = args.begin();
1164 a != args.end(); ++a)
1166 argv.push_back(a->c_str());
1175 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Run command:");
1176 std::vector<const char*>::iterator ait;
1177 for ( ait = argv.begin(); ait != argv.end() && *ait; ++ ait )
1179 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, " \"" << *ait << "\"");
1181 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, std::endl);
1183 // Now create process object
1184 cmsysProcess* cp = cmsysProcess_New();
1185 cmsysProcess_SetCommand(cp, &*argv.begin());
1186 cmsysProcess_SetWorkingDirectory(cp, dir);
1187 cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
1188 cmsysProcess_SetTimeout(cp, timeout);
1189 cmsysProcess_Execute(cp);
1191 // Initialize tick's
1192 std::string::size_type tick = 0;
1193 std::string::size_type tick_len = 1024;
1194 std::string::size_type tick_line_len = 50;
1198 cmCTestLog(this, HANDLER_OUTPUT,
1199 " Each . represents " << tick_len << " bytes of output" << std::endl
1200 << " " << std::flush);
1201 while(cmsysProcess_WaitForData(cp, &data, &length, 0))
1205 for(int cc =0; cc < length; ++cc)
1213 output->append(data, length);
1214 while ( output->size() > (tick * tick_len) )
1217 cmCTestLog(this, HANDLER_OUTPUT, "." << std::flush);
1218 if ( tick % tick_line_len == 0 && tick > 0 )
1220 cmCTestLog(this, HANDLER_OUTPUT, " Size: "
1221 << int((double(output->size()) / 1024.0) + 1) << "K" << std::endl
1222 << " " << std::flush);
1226 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, cmCTestLogWrite(data, length));
1229 ofs << cmCTestLogWrite(data, length);
1232 cmCTestLog(this, OUTPUT, " Size of output: "
1233 << int(double(output->size()) / 1024.0) << "K" << std::endl);
1235 cmsysProcess_WaitForExit(cp, 0);
1237 int result = cmsysProcess_GetState(cp);
1239 if(result == cmsysProcess_State_Exited)
1241 *retVal = cmsysProcess_GetExitValue(cp);
1242 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Command exited with the value: "
1243 << *retVal << std::endl);
1245 else if(result == cmsysProcess_State_Exception)
1247 *retVal = cmsysProcess_GetExitException(cp);
1248 cmCTestLog(this, WARNING, "There was an exception: " << *retVal
1251 else if(result == cmsysProcess_State_Expired)
1253 cmCTestLog(this, WARNING, "There was a timeout" << std::endl);
1255 else if(result == cmsysProcess_State_Error)
1257 *output += "\n*** ERROR executing: ";
1258 *output += cmsysProcess_GetErrorString(cp);
1259 *output += "\n***The build process failed.";
1260 cmCTestLog(this, ERROR_MESSAGE, "There was an error: "
1261 << cmsysProcess_GetErrorString(cp) << std::endl);
1264 cmsysProcess_Delete(cp);
1269 //######################################################################
1270 //######################################################################
1271 //######################################################################
1272 //######################################################################
1274 //----------------------------------------------------------------------
1275 int cmCTest::RunTest(std::vector<const char*> argv,
1276 std::string* output, int *retVal,
1277 std::ostream* log, double testTimeOut,
1278 std::vector<std::string>* environment)
1280 bool modifyEnv = (environment && environment->size()>0);
1282 // determine how much time we have
1283 double timeout = this->GetRemainingTimeAllowed() - 120;
1284 if (this->TimeOut > 0 && this->TimeOut < timeout)
1286 timeout = this->TimeOut;
1289 && testTimeOut < this->GetRemainingTimeAllowed())
1291 timeout = testTimeOut;
1294 // always have at least 1 second if we got to here
1299 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
1300 "Test timeout computed to be: " << timeout << "\n");
1301 if(cmSystemTools::SameFile(argv[0], this->CTestSelf.c_str()) &&
1302 !this->ForceNewCTestProcess)
1305 inst.ConfigType = this->ConfigType;
1306 inst.TimeOut = timeout;
1308 // Capture output of the child ctest.
1309 cmOStringStream oss;
1310 inst.SetStreams(&oss, &oss);
1312 std::vector<std::string> args;
1313 for(unsigned int i =0; i < argv.size(); ++i)
1317 // make sure we pass the timeout in for any build and test
1318 // invocations. Since --build-generator is required this is a
1319 // good place to check for it, and to add the arguments in
1320 if (strcmp(argv[i],"--build-generator") == 0 && timeout > 0)
1322 args.push_back("--test-timeout");
1323 cmOStringStream msg;
1325 args.push_back(msg.str());
1327 args.push_back(argv[i]);
1332 *log << "* Run internal CTest" << std::endl;
1334 std::string oldpath = cmSystemTools::GetCurrentWorkingDirectory();
1336 cmsys::auto_ptr<cmSystemTools::SaveRestoreEnvironment> saveEnv;
1339 saveEnv.reset(new cmSystemTools::SaveRestoreEnvironment);
1340 cmSystemTools::AppendEnv(*environment);
1343 *retVal = inst.Run(args, output);
1344 *output += oss.str();
1347 *log << output->c_str();
1349 cmSystemTools::ChangeDirectory(oldpath.c_str());
1351 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
1352 "Internal cmCTest object used to run test." << std::endl
1353 << *output << std::endl);
1355 return cmsysProcess_State_Exited;
1357 std::vector<char> tempOutput;
1363 cmsys::auto_ptr<cmSystemTools::SaveRestoreEnvironment> saveEnv;
1366 saveEnv.reset(new cmSystemTools::SaveRestoreEnvironment);
1367 cmSystemTools::AppendEnv(*environment);
1370 cmsysProcess* cp = cmsysProcess_New();
1371 cmsysProcess_SetCommand(cp, &*argv.begin());
1372 cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
1373 if(cmSystemTools::GetRunCommandHideConsole())
1375 cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
1378 cmsysProcess_SetTimeout(cp, timeout);
1379 cmsysProcess_Execute(cp);
1383 while(cmsysProcess_WaitForData(cp, &data, &length, 0))
1387 tempOutput.insert(tempOutput.end(), data, data+length);
1389 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, cmCTestLogWrite(data, length));
1392 log->write(data, length);
1396 cmsysProcess_WaitForExit(cp, 0);
1397 if(output && tempOutput.begin() != tempOutput.end())
1399 output->append(&*tempOutput.begin(), tempOutput.size());
1401 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "-- Process completed"
1404 int result = cmsysProcess_GetState(cp);
1406 if(result == cmsysProcess_State_Exited)
1408 *retVal = cmsysProcess_GetExitValue(cp);
1409 if(*retVal != 0 && this->OutputTestOutputOnTestFailure)
1411 OutputTestErrors(tempOutput);
1414 else if(result == cmsysProcess_State_Exception)
1416 if(this->OutputTestOutputOnTestFailure)
1418 OutputTestErrors(tempOutput);
1420 *retVal = cmsysProcess_GetExitException(cp);
1421 std::string outerr = "\n*** Exception executing: ";
1422 outerr += cmsysProcess_GetExceptionString(cp);
1424 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr.c_str() << std::endl
1427 else if(result == cmsysProcess_State_Error)
1429 std::string outerr = "\n*** ERROR executing: ";
1430 outerr += cmsysProcess_GetErrorString(cp);
1432 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr.c_str() << std::endl
1435 cmsysProcess_Delete(cp);
1440 //----------------------------------------------------------------------
1441 std::string cmCTest::SafeBuildIdField(const std::string& value)
1443 std::string safevalue(value);
1445 if (safevalue != "")
1447 // Disallow non-filename and non-space whitespace characters.
1448 // If they occur, replace them with ""
1450 const char *disallowed = "\\/:*?\"<>|\n\r\t\f\v";
1452 if (safevalue.find_first_of(disallowed) != value.npos)
1454 std::string::size_type i = 0;
1455 std::string::size_type n = strlen(disallowed);
1459 for (i= 0; i<n; ++i)
1461 replace[0] = disallowed[i];
1462 cmSystemTools::ReplaceString(safevalue, replace, "");
1466 safevalue = cmXMLSafe(safevalue).str();
1469 if (safevalue == "")
1471 safevalue = "(empty)";
1477 //----------------------------------------------------------------------
1478 void cmCTest::StartXML(std::ostream& ostr, bool append)
1480 if(this->CurrentTag.empty())
1482 cmCTestLog(this, ERROR_MESSAGE,
1483 "Current Tag empty, this may mean"
1484 " NightlStartTime was not set correctly." << std::endl);
1485 cmSystemTools::SetFatalErrorOccured();
1488 // find out about the system
1489 cmsys::SystemInformation info;
1492 info.RunMemoryCheck();
1494 std::string buildname = cmCTest::SafeBuildIdField(
1495 this->GetCTestConfiguration("BuildName"));
1496 std::string stamp = cmCTest::SafeBuildIdField(
1497 this->CurrentTag + "-" + this->GetTestModelString());
1498 std::string site = cmCTest::SafeBuildIdField(
1499 this->GetCTestConfiguration("Site"));
1501 ostr << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1502 << "<Site BuildName=\"" << buildname << "\"\n"
1503 << "\tBuildStamp=\"" << stamp << "\"\n"
1504 << "\tName=\"" << site << "\"\n"
1505 << "\tGenerator=\"ctest-" << cmVersion::GetCMakeVersion() << "\"\n"
1506 << (append? "\tAppend=\"true\"\n":"")
1507 << "\tCompilerName=\"" << this->GetCTestConfiguration("Compiler")
1509 #ifdef _COMPILER_VERSION
1510 << "\tCompilerVersion=\"_COMPILER_VERSION\"\n"
1512 << "\tOSName=\"" << info.GetOSName() << "\"\n"
1513 << "\tHostname=\"" << info.GetHostname() << "\"\n"
1514 << "\tOSRelease=\"" << info.GetOSRelease() << "\"\n"
1515 << "\tOSVersion=\"" << info.GetOSVersion() << "\"\n"
1516 << "\tOSPlatform=\"" << info.GetOSPlatform() << "\"\n"
1517 << "\tIs64Bits=\"" << info.Is64Bits() << "\"\n"
1518 << "\tVendorString=\"" << info.GetVendorString() << "\"\n"
1519 << "\tVendorID=\"" << info.GetVendorID() << "\"\n"
1520 << "\tFamilyID=\"" << info.GetFamilyID() << "\"\n"
1521 << "\tModelID=\"" << info.GetModelID() << "\"\n"
1522 << "\tProcessorCacheSize=\"" << info.GetProcessorCacheSize() << "\"\n"
1523 << "\tNumberOfLogicalCPU=\"" << info.GetNumberOfLogicalCPU() << "\"\n"
1524 << "\tNumberOfPhysicalCPU=\""<< info.GetNumberOfPhysicalCPU() << "\"\n"
1525 << "\tTotalVirtualMemory=\"" << info.GetTotalVirtualMemory() << "\"\n"
1526 << "\tTotalPhysicalMemory=\""<< info.GetTotalPhysicalMemory() << "\"\n"
1527 << "\tLogicalProcessorsPerPhysical=\""
1528 << info.GetLogicalProcessorsPerPhysical() << "\"\n"
1529 << "\tProcessorClockFrequency=\""
1530 << info.GetProcessorClockFrequency() << "\"\n"
1531 << ">" << std::endl;
1532 this->AddSiteProperties(ostr);
1535 //----------------------------------------------------------------------
1536 void cmCTest::AddSiteProperties(std::ostream& ostr)
1538 cmCTestScriptHandler* ch =
1539 static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
1540 cmake* cm = ch->GetCMake();
1541 // if no CMake then this is the old style script and props like
1542 // this will not work anyway.
1547 // This code should go when cdash is changed to use labels only
1548 const char* subproject = cm->GetProperty("SubProject", cmProperty::GLOBAL);
1551 ostr << "<Subproject name=\"" << subproject << "\">\n";
1552 const char* labels =
1553 ch->GetCMake()->GetProperty("SubProjectLabels", cmProperty::GLOBAL);
1556 ostr << " <Labels>\n";
1557 std::string l = labels;
1558 std::vector<std::string> args;
1559 cmSystemTools::ExpandListArgument(l, args);
1560 for(std::vector<std::string>::iterator i = args.begin();
1561 i != args.end(); ++i)
1563 ostr << " <Label>" << i->c_str() << "</Label>\n";
1565 ostr << " </Labels>\n";
1567 ostr << "</Subproject>\n";
1570 // This code should stay when cdash only does label based sub-projects
1571 const char* label = cm->GetProperty("Label", cmProperty::GLOBAL);
1574 ostr << "<Labels>\n";
1575 ostr << " <Label>" << label << "</Label>\n";
1576 ostr << "</Labels>\n";
1581 //----------------------------------------------------------------------
1582 void cmCTest::EndXML(std::ostream& ostr)
1584 ostr << "</Site>" << std::endl;
1587 //----------------------------------------------------------------------
1588 int cmCTest::GenerateCTestNotesOutput(std::ostream& os,
1589 const cmCTest::VectorOfStrings& files)
1591 cmCTest::VectorOfStrings::const_iterator it;
1592 os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1593 << "<?xml-stylesheet type=\"text/xsl\" "
1594 "href=\"Dart/Source/Server/XSL/Build.xsl "
1595 "<file:///Dart/Source/Server/XSL/Build.xsl> \"?>\n"
1596 << "<Site BuildName=\"" << this->GetCTestConfiguration("BuildName")
1597 << "\" BuildStamp=\""
1598 << this->CurrentTag << "-" << this->GetTestModelString() << "\" Name=\""
1599 << this->GetCTestConfiguration("Site") << "\" Generator=\"ctest"
1600 << cmVersion::GetCMakeVersion()
1602 this->AddSiteProperties(os);
1603 os << "<Notes>" << std::endl;
1605 for ( it = files.begin(); it != files.end(); it ++ )
1607 cmCTestLog(this, OUTPUT, "\tAdd file: " << it->c_str() << std::endl);
1608 std::string note_time = this->CurrentTime();
1609 os << "<Note Name=\"" << cmXMLSafe(*it) << "\">\n"
1610 << "<Time>" << cmSystemTools::GetTime() << "</Time>\n"
1611 << "<DateTime>" << note_time << "</DateTime>\n"
1612 << "<Text>" << std::endl;
1613 std::ifstream ifs(it->c_str());
1617 while ( cmSystemTools::GetLineFromStream(ifs, line) )
1619 os << cmXMLSafe(line) << std::endl;
1625 os << "Problem reading file: " << it->c_str() << std::endl;
1626 cmCTestLog(this, ERROR_MESSAGE, "Problem reading file: " << it->c_str()
1627 << " while creating notes" << std::endl);
1630 << "</Note>" << std::endl;
1633 << "</Site>" << std::endl;
1637 //----------------------------------------------------------------------
1638 int cmCTest::GenerateNotesFile(const std::vector<cmStdString> &files)
1640 cmGeneratedFileStream ofs;
1641 if ( !this->OpenOutputFile(this->CurrentTag, "Notes.xml", ofs) )
1643 cmCTestLog(this, ERROR_MESSAGE, "Cannot open notes file" << std::endl);
1647 this->GenerateCTestNotesOutput(ofs, files);
1651 //----------------------------------------------------------------------
1652 int cmCTest::GenerateNotesFile(const char* cfiles)
1659 std::vector<cmStdString> files;
1661 cmCTestLog(this, OUTPUT, "Create notes file" << std::endl);
1663 files = cmSystemTools::SplitString(cfiles, ';');
1664 if ( files.size() == 0 )
1669 return this->GenerateNotesFile(files);
1672 //----------------------------------------------------------------------
1673 std::string cmCTest::Base64GzipEncodeFile(std::string file)
1675 std::string tarFile = file + "_temp.tar.gz";
1676 std::vector<cmStdString> files;
1677 files.push_back(file);
1679 if(!cmSystemTools::CreateTar(tarFile.c_str(), files, true, false, false))
1681 cmCTestLog(this, ERROR_MESSAGE, "Error creating tar while "
1682 "encoding file: " << file << std::endl);
1685 std::string base64 = this->Base64EncodeFile(tarFile);
1686 cmSystemTools::RemoveFile(tarFile.c_str());
1690 //----------------------------------------------------------------------
1691 std::string cmCTest::Base64EncodeFile(std::string file)
1693 long len = cmSystemTools::FileLength(file.c_str());
1694 std::ifstream ifs(file.c_str(), std::ios::in
1699 unsigned char *file_buffer = new unsigned char [ len + 1 ];
1700 ifs.read(reinterpret_cast<char*>(file_buffer), len);
1703 unsigned char *encoded_buffer
1704 = new unsigned char [ static_cast<int>(
1705 static_cast<double>(len) * 1.5 + 5.0) ];
1708 = cmsysBase64_Encode(file_buffer, len, encoded_buffer, 1);
1710 std::string base64 = "";
1711 for(unsigned long i = 0; i < rlen; i++)
1713 base64 += encoded_buffer[i];
1715 delete [] file_buffer;
1716 delete [] encoded_buffer;
1722 //----------------------------------------------------------------------
1723 bool cmCTest::SubmitExtraFiles(const std::vector<cmStdString> &files)
1725 std::vector<cmStdString>::const_iterator it;
1726 for ( it = files.begin();
1730 if ( !cmSystemTools::FileExists(it->c_str()) )
1732 cmCTestLog(this, ERROR_MESSAGE, "Cannot find extra file: "
1733 << it->c_str() << " to submit."
1737 this->AddSubmitFile(PartExtraFiles, it->c_str());
1742 //----------------------------------------------------------------------
1743 bool cmCTest::SubmitExtraFiles(const char* cfiles)
1750 std::vector<cmStdString> files;
1752 cmCTestLog(this, OUTPUT, "Submit extra files" << std::endl);
1754 files = cmSystemTools::SplitString(cfiles, ';');
1755 if ( files.size() == 0 )
1760 return this->SubmitExtraFiles(files);
1764 //-------------------------------------------------------
1765 // for a -D argument convert the next argument into
1766 // the proper list of dashboard steps via SetTest
1767 bool cmCTest::AddTestsForDashboardType(std::string &targ)
1769 if ( targ == "Experimental" )
1771 this->SetTestModel(cmCTest::EXPERIMENTAL);
1772 this->SetTest("Start");
1773 this->SetTest("Configure");
1774 this->SetTest("Build");
1775 this->SetTest("Test");
1776 this->SetTest("Coverage");
1777 this->SetTest("Submit");
1779 else if ( targ == "ExperimentalStart" )
1781 this->SetTestModel(cmCTest::EXPERIMENTAL);
1782 this->SetTest("Start");
1784 else if ( targ == "ExperimentalUpdate" )
1786 this->SetTestModel(cmCTest::EXPERIMENTAL);
1787 this->SetTest("Update");
1789 else if ( targ == "ExperimentalConfigure" )
1791 this->SetTestModel(cmCTest::EXPERIMENTAL);
1792 this->SetTest("Configure");
1794 else if ( targ == "ExperimentalBuild" )
1796 this->SetTestModel(cmCTest::EXPERIMENTAL);
1797 this->SetTest("Build");
1799 else if ( targ == "ExperimentalTest" )
1801 this->SetTestModel(cmCTest::EXPERIMENTAL);
1802 this->SetTest("Test");
1804 else if ( targ == "ExperimentalMemCheck"
1805 || targ == "ExperimentalPurify" )
1807 this->SetTestModel(cmCTest::EXPERIMENTAL);
1808 this->SetTest("MemCheck");
1810 else if ( targ == "ExperimentalCoverage" )
1812 this->SetTestModel(cmCTest::EXPERIMENTAL);
1813 this->SetTest("Coverage");
1815 else if ( targ == "ExperimentalSubmit" )
1817 this->SetTestModel(cmCTest::EXPERIMENTAL);
1818 this->SetTest("Submit");
1820 else if ( targ == "Continuous" )
1822 this->SetTestModel(cmCTest::CONTINUOUS);
1823 this->SetTest("Start");
1824 this->SetTest("Update");
1825 this->SetTest("Configure");
1826 this->SetTest("Build");
1827 this->SetTest("Test");
1828 this->SetTest("Coverage");
1829 this->SetTest("Submit");
1831 else if ( targ == "ContinuousStart" )
1833 this->SetTestModel(cmCTest::CONTINUOUS);
1834 this->SetTest("Start");
1836 else if ( targ == "ContinuousUpdate" )
1838 this->SetTestModel(cmCTest::CONTINUOUS);
1839 this->SetTest("Update");
1841 else if ( targ == "ContinuousConfigure" )
1843 this->SetTestModel(cmCTest::CONTINUOUS);
1844 this->SetTest("Configure");
1846 else if ( targ == "ContinuousBuild" )
1848 this->SetTestModel(cmCTest::CONTINUOUS);
1849 this->SetTest("Build");
1851 else if ( targ == "ContinuousTest" )
1853 this->SetTestModel(cmCTest::CONTINUOUS);
1854 this->SetTest("Test");
1856 else if ( targ == "ContinuousMemCheck"
1857 || targ == "ContinuousPurify" )
1859 this->SetTestModel(cmCTest::CONTINUOUS);
1860 this->SetTest("MemCheck");
1862 else if ( targ == "ContinuousCoverage" )
1864 this->SetTestModel(cmCTest::CONTINUOUS);
1865 this->SetTest("Coverage");
1867 else if ( targ == "ContinuousSubmit" )
1869 this->SetTestModel(cmCTest::CONTINUOUS);
1870 this->SetTest("Submit");
1872 else if ( targ == "Nightly" )
1874 this->SetTestModel(cmCTest::NIGHTLY);
1875 this->SetTest("Start");
1876 this->SetTest("Update");
1877 this->SetTest("Configure");
1878 this->SetTest("Build");
1879 this->SetTest("Test");
1880 this->SetTest("Coverage");
1881 this->SetTest("Submit");
1883 else if ( targ == "NightlyStart" )
1885 this->SetTestModel(cmCTest::NIGHTLY);
1886 this->SetTest("Start");
1888 else if ( targ == "NightlyUpdate" )
1890 this->SetTestModel(cmCTest::NIGHTLY);
1891 this->SetTest("Update");
1893 else if ( targ == "NightlyConfigure" )
1895 this->SetTestModel(cmCTest::NIGHTLY);
1896 this->SetTest("Configure");
1898 else if ( targ == "NightlyBuild" )
1900 this->SetTestModel(cmCTest::NIGHTLY);
1901 this->SetTest("Build");
1903 else if ( targ == "NightlyTest" )
1905 this->SetTestModel(cmCTest::NIGHTLY);
1906 this->SetTest("Test");
1908 else if ( targ == "NightlyMemCheck"
1909 || targ == "NightlyPurify" )
1911 this->SetTestModel(cmCTest::NIGHTLY);
1912 this->SetTest("MemCheck");
1914 else if ( targ == "NightlyCoverage" )
1916 this->SetTestModel(cmCTest::NIGHTLY);
1917 this->SetTest("Coverage");
1919 else if ( targ == "NightlySubmit" )
1921 this->SetTestModel(cmCTest::NIGHTLY);
1922 this->SetTest("Submit");
1924 else if ( targ == "MemoryCheck" )
1926 this->SetTestModel(cmCTest::EXPERIMENTAL);
1927 this->SetTest("Start");
1928 this->SetTest("Configure");
1929 this->SetTest("Build");
1930 this->SetTest("MemCheck");
1931 this->SetTest("Coverage");
1932 this->SetTest("Submit");
1934 else if ( targ == "NightlyMemoryCheck" )
1936 this->SetTestModel(cmCTest::NIGHTLY);
1937 this->SetTest("Start");
1938 this->SetTest("Update");
1939 this->SetTest("Configure");
1940 this->SetTest("Build");
1941 this->SetTest("MemCheck");
1942 this->SetTest("Coverage");
1943 this->SetTest("Submit");
1953 //----------------------------------------------------------------------
1954 void cmCTest::ErrorMessageUnknownDashDValue(std::string &val)
1956 cmCTestLog(this, ERROR_MESSAGE,
1957 "CTest -D called with incorrect option: " << val << std::endl);
1959 cmCTestLog(this, ERROR_MESSAGE,
1960 "Available options are:" << std::endl
1961 << " ctest -D Continuous" << std::endl
1962 << " ctest -D Continuous(Start|Update|Configure|Build)" << std::endl
1963 << " ctest -D Continuous(Test|Coverage|MemCheck|Submit)" << std::endl
1964 << " ctest -D Experimental" << std::endl
1965 << " ctest -D Experimental(Start|Update|Configure|Build)" << std::endl
1966 << " ctest -D Experimental(Test|Coverage|MemCheck|Submit)" << std::endl
1967 << " ctest -D Nightly" << std::endl
1968 << " ctest -D Nightly(Start|Update|Configure|Build)" << std::endl
1969 << " ctest -D Nightly(Test|Coverage|MemCheck|Submit)" << std::endl
1970 << " ctest -D NightlyMemoryCheck" << std::endl);
1974 //----------------------------------------------------------------------
1975 bool cmCTest::CheckArgument(const std::string& arg, const char* varg1,
1978 return (varg1 && arg == varg1) || (varg2 && arg == varg2);
1982 //----------------------------------------------------------------------
1983 // Processes one command line argument (and its arguments if any)
1984 // for many simple options and then returns
1985 void cmCTest::HandleCommandLineArguments(size_t &i,
1986 std::vector<std::string> &args)
1988 std::string arg = args[i];
1990 if(this->CheckArgument(arg, "-F"))
1992 this->Failover = true;
1994 if(this->CheckArgument(arg, "-j", "--parallel") && i < args.size() - 1)
1997 int plevel = atoi(args[i].c_str());
1998 this->SetParallelLevel(plevel);
2000 else if(arg.find("-j") == 0)
2002 int plevel = atoi(arg.substr(2).c_str());
2003 this->SetParallelLevel(plevel);
2006 if(this->CheckArgument(arg, "--no-compress-output"))
2008 this->CompressTestOutput = false;
2009 this->CompressMemCheckOutput = false;
2012 if(this->CheckArgument(arg, "--print-labels"))
2014 this->PrintLabels = true;
2017 if(this->CheckArgument(arg, "--http1.0"))
2019 this->UseHTTP10 = true;
2022 if(this->CheckArgument(arg, "--timeout") && i < args.size() - 1)
2025 double timeout = (double)atof(args[i].c_str());
2026 this->GlobalTimeout = timeout;
2029 if(this->CheckArgument(arg, "--stop-time") && i < args.size() - 1)
2032 this->SetStopTime(args[i]);
2035 if(this->CheckArgument(arg, "-C", "--build-config") &&
2036 i < args.size() - 1)
2039 this->SetConfigType(args[i].c_str());
2042 if(this->CheckArgument(arg, "--debug"))
2045 this->ShowLineNumbers = true;
2047 if(this->CheckArgument(arg, "--track") && i < args.size() - 1)
2050 this->SpecificTrack = args[i];
2052 if(this->CheckArgument(arg, "--show-line-numbers"))
2054 this->ShowLineNumbers = true;
2056 if(this->CheckArgument(arg, "--no-label-summary"))
2058 this->LabelSummary = false;
2060 if(this->CheckArgument(arg, "-Q", "--quiet"))
2064 if(this->CheckArgument(arg, "-V", "--verbose"))
2066 this->Verbose = true;
2068 if(this->CheckArgument(arg, "-B"))
2070 this->BatchJobs = true;
2072 if(this->CheckArgument(arg, "-VV", "--extra-verbose"))
2074 this->ExtraVerbose = true;
2075 this->Verbose = true;
2077 if(this->CheckArgument(arg, "--output-on-failure"))
2079 this->OutputTestOutputOnTestFailure = true;
2082 if(this->CheckArgument(arg, "-N", "--show-only"))
2084 this->ShowOnly = true;
2087 if(this->CheckArgument(arg, "-O", "--output-log") && i < args.size() - 1 )
2090 this->SetOutputLogFileName(args[i].c_str());
2093 if(this->CheckArgument(arg, "--tomorrow-tag"))
2095 this->TomorrowTag = true;
2097 if(this->CheckArgument(arg, "--force-new-ctest-process"))
2099 this->ForceNewCTestProcess = true;
2101 if(this->CheckArgument(arg, "-W", "--max-width") && i < args.size() - 1)
2104 this->MaxTestNameWidth = atoi(args[i].c_str());
2106 if(this->CheckArgument(arg, "--interactive-debug-mode") &&
2107 i < args.size() - 1 )
2110 this->InteractiveDebugMode = cmSystemTools::IsOn(args[i].c_str());
2112 if(this->CheckArgument(arg, "--submit-index") && i < args.size() - 1 )
2115 this->SubmitIndex = atoi(args[i].c_str());
2116 if ( this->SubmitIndex < 0 )
2118 this->SubmitIndex = 0;
2122 if(this->CheckArgument(arg, "--overwrite") && i < args.size() - 1)
2125 this->AddCTestConfigurationOverwrite(args[i].c_str());
2127 if(this->CheckArgument(arg, "-A", "--add-notes") && i < args.size() - 1)
2129 this->ProduceXML = true;
2130 this->SetTest("Notes");
2132 this->SetNotesFiles(args[i].c_str());
2135 // options that control what tests are run
2136 if(this->CheckArgument(arg, "-I", "--tests-information") &&
2137 i < args.size() - 1)
2140 this->GetHandler("test")->SetPersistentOption("TestsToRunInformation",
2142 this->GetHandler("memcheck")->
2143 SetPersistentOption("TestsToRunInformation",args[i].c_str());
2145 if(this->CheckArgument(arg, "-U", "--union"))
2147 this->GetHandler("test")->SetPersistentOption("UseUnion", "true");
2148 this->GetHandler("memcheck")->SetPersistentOption("UseUnion", "true");
2150 if(this->CheckArgument(arg, "-R", "--tests-regex") && i < args.size() - 1)
2153 this->GetHandler("test")->
2154 SetPersistentOption("IncludeRegularExpression", args[i].c_str());
2155 this->GetHandler("memcheck")->
2156 SetPersistentOption("IncludeRegularExpression", args[i].c_str());
2158 if(this->CheckArgument(arg, "-L", "--label-regex") && i < args.size() - 1)
2161 this->GetHandler("test")->
2162 SetPersistentOption("LabelRegularExpression", args[i].c_str());
2163 this->GetHandler("memcheck")->
2164 SetPersistentOption("LabelRegularExpression", args[i].c_str());
2166 if(this->CheckArgument(arg, "-LE", "--label-exclude") && i < args.size() - 1)
2169 this->GetHandler("test")->
2170 SetPersistentOption("ExcludeLabelRegularExpression", args[i].c_str());
2171 this->GetHandler("memcheck")->
2172 SetPersistentOption("ExcludeLabelRegularExpression", args[i].c_str());
2175 if(this->CheckArgument(arg, "-E", "--exclude-regex") &&
2176 i < args.size() - 1)
2179 this->GetHandler("test")->
2180 SetPersistentOption("ExcludeRegularExpression", args[i].c_str());
2181 this->GetHandler("memcheck")->
2182 SetPersistentOption("ExcludeRegularExpression", args[i].c_str());
2186 //----------------------------------------------------------------------
2187 // handle the -S -SR and -SP arguments
2188 void cmCTest::HandleScriptArguments(size_t &i,
2189 std::vector<std::string> &args,
2190 bool &SRArgumentSpecified)
2192 std::string arg = args[i];
2193 if(this->CheckArgument(arg, "-SP", "--script-new-process") &&
2194 i < args.size() - 1 )
2196 this->RunConfigurationScript = true;
2198 cmCTestScriptHandler* ch
2199 = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
2200 // -SR is an internal argument, -SP should be ignored when it is passed
2201 if (!SRArgumentSpecified)
2203 ch->AddConfigurationScript(args[i].c_str(),false);
2207 if(this->CheckArgument(arg, "-SR", "--script-run") &&
2208 i < args.size() - 1 )
2210 SRArgumentSpecified = true;
2211 this->RunConfigurationScript = true;
2213 cmCTestScriptHandler* ch
2214 = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
2215 ch->AddConfigurationScript(args[i].c_str(),true);
2218 if(this->CheckArgument(arg, "-S", "--script") && i < args.size() - 1 )
2220 this->RunConfigurationScript = true;
2222 cmCTestScriptHandler* ch
2223 = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
2224 // -SR is an internal argument, -S should be ignored when it is passed
2225 if (!SRArgumentSpecified)
2227 ch->AddConfigurationScript(args[i].c_str(),true);
2232 //----------------------------------------------------------------------
2233 bool cmCTest::AddVariableDefinition(const std::string &arg)
2237 cmCacheManager::CacheEntryType type = cmCacheManager::UNINITIALIZED;
2239 if (cmCacheManager::ParseEntry(arg.c_str(), name, value, type))
2241 this->Definitions[name] = value;
2248 //----------------------------------------------------------------------
2249 // the main entry point of ctest, called from main
2250 int cmCTest::Run(std::vector<std::string> &args, std::string* output)
2252 this->FindRunningCMake();
2253 const char* ctestExec = "ctest";
2254 bool cmakeAndTest = false;
2255 bool executeTests = true;
2256 bool SRArgumentSpecified = false;
2258 // copy the command line
2259 for(size_t i=0; i < args.size(); ++i)
2261 this->InitialCommandLineArguments.push_back(args[i]);
2264 // process the command line arguments
2265 for(size_t i=1; i < args.size(); ++i)
2267 // handle the simple commandline arguments
2268 this->HandleCommandLineArguments(i,args);
2270 // handle the script arguments -S -SR -SP
2271 this->HandleScriptArguments(i,args,SRArgumentSpecified);
2273 // handle a request for a dashboard
2274 std::string arg = args[i];
2275 if(this->CheckArgument(arg, "-D", "--dashboard") && i < args.size() - 1 )
2277 this->ProduceXML = true;
2279 std::string targ = args[i];
2280 // AddTestsForDashboard parses the dashboard type and converts it
2281 // into the separate stages
2282 if (!this->AddTestsForDashboardType(targ))
2284 if (!this->AddVariableDefinition(targ))
2286 this->ErrorMessageUnknownDashDValue(targ);
2287 executeTests = false;
2292 // If it's not exactly -D, but it starts with -D, then try to parse out
2293 // a variable definition from it, same as CMake does. Unsuccessful
2294 // attempts are simply ignored since previous ctest versions ignore
2295 // this too. (As well as many other unknown command line args.)
2297 if(arg != "-D" && cmSystemTools::StringStartsWith(arg.c_str(), "-D"))
2299 std::string input = arg.substr(2);
2300 this->AddVariableDefinition(input);
2303 if(this->CheckArgument(arg, "-T", "--test-action") &&
2304 (i < args.size() -1) )
2306 this->ProduceXML = true;
2308 if ( !this->SetTest(args[i].c_str(), false) )
2310 executeTests = false;
2311 cmCTestLog(this, ERROR_MESSAGE,
2312 "CTest -T called with incorrect option: "
2313 << args[i].c_str() << std::endl);
2314 cmCTestLog(this, ERROR_MESSAGE, "Available options are:" << std::endl
2315 << " " << ctestExec << " -T all" << std::endl
2316 << " " << ctestExec << " -T start" << std::endl
2317 << " " << ctestExec << " -T update" << std::endl
2318 << " " << ctestExec << " -T configure" << std::endl
2319 << " " << ctestExec << " -T build" << std::endl
2320 << " " << ctestExec << " -T test" << std::endl
2321 << " " << ctestExec << " -T coverage" << std::endl
2322 << " " << ctestExec << " -T memcheck" << std::endl
2323 << " " << ctestExec << " -T notes" << std::endl
2324 << " " << ctestExec << " -T submit" << std::endl);
2328 // what type of test model
2329 if(this->CheckArgument(arg, "-M", "--test-model") &&
2330 (i < args.size() -1) )
2333 std::string const& str = args[i];
2334 if ( cmSystemTools::LowerCase(str) == "nightly" )
2336 this->SetTestModel(cmCTest::NIGHTLY);
2338 else if ( cmSystemTools::LowerCase(str) == "continuous" )
2340 this->SetTestModel(cmCTest::CONTINUOUS);
2342 else if ( cmSystemTools::LowerCase(str) == "experimental" )
2344 this->SetTestModel(cmCTest::EXPERIMENTAL);
2348 executeTests = false;
2349 cmCTestLog(this, ERROR_MESSAGE,
2350 "CTest -M called with incorrect option: " << str.c_str()
2352 cmCTestLog(this, ERROR_MESSAGE, "Available options are:" << std::endl
2353 << " " << ctestExec << " -M Continuous" << std::endl
2354 << " " << ctestExec << " -M Experimental" << std::endl
2355 << " " << ctestExec << " -M Nightly" << std::endl);
2359 if(this->CheckArgument(arg, "--extra-submit") && i < args.size() - 1)
2361 this->ProduceXML = true;
2362 this->SetTest("Submit");
2364 if ( !this->SubmitExtraFiles(args[i].c_str()) )
2370 // --build-and-test options
2371 if(this->CheckArgument(arg, "--build-and-test") && i < args.size() - 1)
2373 cmakeAndTest = true;
2376 if(this->CheckArgument(arg, "--schedule-random"))
2378 this->ScheduleType = "Random";
2381 // pass the argument to all the handlers as well, but i may no longer be
2382 // set to what it was originally so I'm not sure this is working as
2384 cmCTest::t_TestingHandlers::iterator it;
2385 for ( it = this->TestingHandlers.begin();
2386 it != this->TestingHandlers.end();
2389 if ( !it->second->ProcessCommandLineArguments(arg, i, args) )
2391 cmCTestLog(this, ERROR_MESSAGE,
2392 "Problem parsing command line arguments within a handler");
2396 } // the close of the for argument loop
2399 // now what sould cmake do? if --build-and-test was specified then
2400 // we run the build and test handler and return
2403 this->Verbose = true;
2404 cmCTestBuildAndTestHandler* handler =
2405 static_cast<cmCTestBuildAndTestHandler*>(this->GetHandler("buildtest"));
2406 int retv = handler->ProcessHandler();
2407 *output = handler->GetOutput();
2408 #ifdef CMAKE_BUILD_WITH_CMAKE
2409 cmDynamicLoader::FlushCache();
2413 cmCTestLog(this, DEBUG, "build and test failing returing: " << retv
2422 // call process directory
2423 if (this->RunConfigurationScript)
2425 if ( this->ExtraVerbose )
2427 cmCTestLog(this, OUTPUT, "* Extra verbosity turned on" << std::endl);
2429 cmCTest::t_TestingHandlers::iterator it;
2430 for ( it = this->TestingHandlers.begin();
2431 it != this->TestingHandlers.end();
2434 it->second->SetVerbose(this->ExtraVerbose);
2435 it->second->SetSubmitIndex(this->SubmitIndex);
2437 this->GetHandler("script")->SetVerbose(this->Verbose);
2438 res = this->GetHandler("script")->ProcessHandler();
2441 cmCTestLog(this, DEBUG, "running script failing returning: " << res
2448 // What is this? -V seems to be the same as -VV,
2449 // and Verbose is always on in this case
2450 this->ExtraVerbose = this->Verbose;
2451 this->Verbose = true;
2452 cmCTest::t_TestingHandlers::iterator it;
2453 for ( it = this->TestingHandlers.begin();
2454 it != this->TestingHandlers.end();
2457 it->second->SetVerbose(this->Verbose);
2458 it->second->SetSubmitIndex(this->SubmitIndex);
2460 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
2461 if(!this->Initialize(cwd.c_str(), 0))
2464 cmCTestLog(this, ERROR_MESSAGE, "Problem initializing the dashboard."
2469 res = this->ProcessTests();
2475 cmCTestLog(this, DEBUG, "Running a test(s) failed returning : " << res
2484 //----------------------------------------------------------------------
2485 void cmCTest::FindRunningCMake()
2487 // Find our own executable.
2488 this->CTestSelf = cmSystemTools::GetExecutableDirectory();
2489 this->CTestSelf += "/ctest";
2490 this->CTestSelf += cmSystemTools::GetExecutableExtension();
2491 if(!cmSystemTools::FileExists(this->CTestSelf.c_str()))
2493 cmSystemTools::Error("CTest executable cannot be found at ",
2494 this->CTestSelf.c_str());
2497 this->CMakeSelf = cmSystemTools::GetExecutableDirectory();
2498 this->CMakeSelf += "/cmake";
2499 this->CMakeSelf += cmSystemTools::GetExecutableExtension();
2500 if(!cmSystemTools::FileExists(this->CMakeSelf.c_str()))
2502 cmSystemTools::Error("CMake executable cannot be found at ",
2503 this->CMakeSelf.c_str());
2507 //----------------------------------------------------------------------
2508 void cmCTest::SetNotesFiles(const char* notes)
2514 this->NotesFiles = notes;
2517 //----------------------------------------------------------------------
2518 void cmCTest::SetStopTime(std::string time)
2520 this->StopTime = time;
2521 this->DetermineNextDayStop();
2524 //----------------------------------------------------------------------
2525 int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf)
2528 VectorOfStrings dirs;
2529 VectorOfStrings ndirs;
2530 cmCTestLog(this, DEBUG, "* Read custom CTest configuration directory: "
2531 << dir << std::endl);
2533 std::string fname = dir;
2534 fname += "/CTestCustom.cmake";
2535 cmCTestLog(this, DEBUG, "* Check for file: "
2536 << fname.c_str() << std::endl);
2537 if ( cmSystemTools::FileExists(fname.c_str()) )
2539 cmCTestLog(this, DEBUG, "* Read custom CTest configuration file: "
2540 << fname.c_str() << std::endl);
2541 bool erroroc = cmSystemTools::GetErrorOccuredFlag();
2542 cmSystemTools::ResetErrorOccuredFlag();
2544 if ( !mf->ReadListFile(0, fname.c_str()) ||
2545 cmSystemTools::GetErrorOccuredFlag() )
2547 cmCTestLog(this, ERROR_MESSAGE,
2548 "Problem reading custom configuration: "
2549 << fname.c_str() << std::endl);
2554 cmSystemTools::SetErrorOccured();
2558 std::string rexpr = dir;
2559 rexpr += "/CTestCustom.ctest";
2560 cmCTestLog(this, DEBUG, "* Check for file: "
2561 << rexpr.c_str() << std::endl);
2562 if ( !found && cmSystemTools::FileExists(rexpr.c_str()) )
2566 gl.FindFiles(rexpr);
2567 std::vector<std::string>& files = gl.GetFiles();
2568 std::vector<std::string>::iterator fileIt;
2569 for ( fileIt = files.begin(); fileIt != files.end();
2572 cmCTestLog(this, DEBUG, "* Read custom CTest configuration file: "
2573 << fileIt->c_str() << std::endl);
2574 if ( !mf->ReadListFile(0, fileIt->c_str()) ||
2575 cmSystemTools::GetErrorOccuredFlag() )
2577 cmCTestLog(this, ERROR_MESSAGE,
2578 "Problem reading custom configuration: "
2579 << fileIt->c_str() << std::endl);
2587 cmCTest::t_TestingHandlers::iterator it;
2588 for ( it = this->TestingHandlers.begin();
2589 it != this->TestingHandlers.end(); ++ it )
2591 cmCTestLog(this, DEBUG,
2592 "* Read custom CTest configuration vectors for handler: "
2593 << it->first.c_str() << " (" << it->second << ")" << std::endl);
2594 it->second->PopulateCustomVectors(mf);
2601 //----------------------------------------------------------------------
2602 void cmCTest::PopulateCustomVector(cmMakefile* mf, const char* def,
2603 VectorOfStrings& vec)
2609 const char* dval = mf->GetDefinition(def);
2614 cmCTestLog(this, DEBUG, "PopulateCustomVector: " << def << std::endl);
2615 std::vector<std::string> slist;
2616 cmSystemTools::ExpandListArgument(dval, slist);
2617 std::vector<std::string>::iterator it;
2621 for ( it = slist.begin(); it != slist.end(); ++it )
2623 cmCTestLog(this, DEBUG, " -- " << it->c_str() << std::endl);
2624 vec.push_back(it->c_str());
2628 //----------------------------------------------------------------------
2629 void cmCTest::PopulateCustomInteger(cmMakefile* mf, const char* def, int& val)
2635 const char* dval = mf->GetDefinition(def);
2643 //----------------------------------------------------------------------
2644 std::string cmCTest::GetShortPathToFile(const char* cfname)
2646 const std::string& sourceDir
2647 = cmSystemTools::CollapseFullPath(
2648 this->GetCTestConfiguration("SourceDirectory").c_str());
2649 const std::string& buildDir
2650 = cmSystemTools::CollapseFullPath(
2651 this->GetCTestConfiguration("BuildDirectory").c_str());
2652 std::string fname = cmSystemTools::CollapseFullPath(cfname);
2654 // Find relative paths to both directories
2655 std::string srcRelpath
2656 = cmSystemTools::RelativePath(sourceDir.c_str(), fname.c_str());
2657 std::string bldRelpath
2658 = cmSystemTools::RelativePath(buildDir.c_str(), fname.c_str());
2660 // If any contains "." it is not parent directory
2661 bool inSrc = srcRelpath.find("..") == srcRelpath.npos;
2662 bool inBld = bldRelpath.find("..") == bldRelpath.npos;
2663 // TODO: Handle files with .. in their name
2665 std::string* res = 0;
2667 if ( inSrc && inBld )
2669 // If both have relative path with no dots, pick the shorter one
2670 if ( srcRelpath.size() < bldRelpath.size() )
2696 cmSystemTools::ConvertToUnixSlashes(*res);
2699 if ( path[path.size()-1] == '/' )
2701 path = path.substr(0, path.size()-1);
2705 cmsys::SystemTools::ReplaceString(path, ":", "_");
2706 cmsys::SystemTools::ReplaceString(path, " ", "_");
2710 //----------------------------------------------------------------------
2711 std::string cmCTest::GetCTestConfiguration(const char *name)
2713 if ( this->CTestConfigurationOverwrites.find(name) !=
2714 this->CTestConfigurationOverwrites.end() )
2716 return this->CTestConfigurationOverwrites[name];
2718 return this->CTestConfiguration[name];
2721 //----------------------------------------------------------------------
2722 void cmCTest::EmptyCTestConfiguration()
2724 this->CTestConfiguration.clear();
2727 //----------------------------------------------------------------------
2728 void cmCTest::DetermineNextDayStop()
2731 time_t current_time = time(0);
2732 lctime = gmtime(¤t_time);
2733 int gm_hour = lctime->tm_hour;
2734 time_t gm_time = mktime(lctime);
2735 lctime = localtime(¤t_time);
2736 int local_hour = lctime->tm_hour;
2738 int tzone_offset = local_hour - gm_hour;
2739 if(gm_time > current_time && gm_hour < local_hour)
2741 // this means gm_time is on the next day
2744 else if(gm_time < current_time && gm_hour > local_hour)
2746 // this means gm_time is on the previous day
2750 tzone_offset *= 100;
2752 sprintf(buf, "%d%02d%02d %s %+05i",
2753 lctime->tm_year + 1900,
2756 this->StopTime.c_str(),
2759 time_t stop_time = curl_getdate(buf, ¤t_time);
2761 if(stop_time < current_time)
2763 this->NextDayStopTime = true;
2767 //----------------------------------------------------------------------
2768 void cmCTest::SetCTestConfiguration(const char *name, const char* value)
2770 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "SetCTestConfiguration:"
2771 << name << ":" << (value ? value : "(null)") << "\n");
2779 this->CTestConfiguration.erase(name);
2782 this->CTestConfiguration[name] = value;
2786 //----------------------------------------------------------------------
2787 std::string cmCTest::GetCurrentTag()
2789 return this->CurrentTag;
2792 //----------------------------------------------------------------------
2793 std::string cmCTest::GetBinaryDir()
2795 return this->BinaryDir;
2798 //----------------------------------------------------------------------
2799 std::string const& cmCTest::GetConfigType()
2801 return this->ConfigType;
2804 //----------------------------------------------------------------------
2805 bool cmCTest::GetShowOnly()
2807 return this->ShowOnly;
2810 //----------------------------------------------------------------------
2811 int cmCTest::GetMaxTestNameWidth() const
2813 return this->MaxTestNameWidth;
2816 //----------------------------------------------------------------------
2817 void cmCTest::SetProduceXML(bool v)
2819 this->ProduceXML = v;
2822 //----------------------------------------------------------------------
2823 bool cmCTest::GetProduceXML()
2825 return this->ProduceXML;
2828 //----------------------------------------------------------------------
2829 const char* cmCTest::GetSpecificTrack()
2831 if ( this->SpecificTrack.empty() )
2835 return this->SpecificTrack.c_str();
2838 //----------------------------------------------------------------------
2839 void cmCTest::SetSpecificTrack(const char* track)
2843 this->SpecificTrack = "";
2846 this->SpecificTrack = track;
2849 //----------------------------------------------------------------------
2850 void cmCTest::AddSubmitFile(Part part, const char* name)
2852 this->Parts[part].SubmitFiles.push_back(name);
2855 //----------------------------------------------------------------------
2856 void cmCTest::AddCTestConfigurationOverwrite(const char* encstr)
2858 std::string overStr = encstr;
2859 size_t epos = overStr.find("=");
2860 if ( epos == overStr.npos )
2862 cmCTestLog(this, ERROR_MESSAGE,
2863 "CTest configuration overwrite specified in the wrong format."
2865 << "Valid format is: --overwrite key=value" << std::endl
2866 << "The specified was: --overwrite " << overStr.c_str() << std::endl);
2869 std::string key = overStr.substr(0, epos);
2870 std::string value = overStr.substr(epos+1, overStr.npos);
2871 this->CTestConfigurationOverwrites[key] = value;
2874 //----------------------------------------------------------------------
2875 void cmCTest::SetConfigType(const char* ct)
2877 this->ConfigType = ct?ct:"";
2878 cmSystemTools::ReplaceString(this->ConfigType, ".\\", "");
2879 std::string confTypeEnv
2880 = "CMAKE_CONFIG_TYPE=" + this->ConfigType;
2881 cmSystemTools::PutEnv(confTypeEnv.c_str());
2884 //----------------------------------------------------------------------
2885 bool cmCTest::SetCTestConfigurationFromCMakeVariable(cmMakefile* mf,
2886 const char* dconfig, const char* cmake_var)
2889 ctvar = mf->GetDefinition(cmake_var);
2894 cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
2895 "SetCTestConfigurationFromCMakeVariable:"
2896 << dconfig << ":" << cmake_var << std::endl);
2897 this->SetCTestConfiguration(dconfig, ctvar);
2901 bool cmCTest::RunCommand(
2902 const char* command,
2903 std::string* stdOut,
2904 std::string* stdErr,
2909 std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);
2916 std::vector<const char*> argv;
2917 for(std::vector<cmStdString>::const_iterator a = args.begin();
2918 a != args.end(); ++a)
2920 argv.push_back(a->c_str());
2927 cmsysProcess* cp = cmsysProcess_New();
2928 cmsysProcess_SetCommand(cp, &*argv.begin());
2929 cmsysProcess_SetWorkingDirectory(cp, dir);
2930 if(cmSystemTools::GetRunCommandHideConsole())
2932 cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
2934 cmsysProcess_SetTimeout(cp, timeout);
2935 cmsysProcess_Execute(cp);
2937 std::vector<char> tempOutput;
2938 std::vector<char> tempError;
2945 res = cmsysProcess_WaitForData(cp, &data, &length, 0);
2948 case cmsysProcess_Pipe_STDOUT:
2949 tempOutput.insert(tempOutput.end(), data, data+length);
2951 case cmsysProcess_Pipe_STDERR:
2952 tempError.insert(tempError.end(), data, data+length);
2957 if ( (res == cmsysProcess_Pipe_STDOUT ||
2958 res == cmsysProcess_Pipe_STDERR) && this->ExtraVerbose )
2960 cmSystemTools::Stdout(data, length);
2964 cmsysProcess_WaitForExit(cp, 0);
2965 if ( tempOutput.size() > 0 )
2967 stdOut->append(&*tempOutput.begin(), tempOutput.size());
2969 if ( tempError.size() > 0 )
2971 stdErr->append(&*tempError.begin(), tempError.size());
2975 if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exited)
2979 *retVal = cmsysProcess_GetExitValue(cp);
2983 if ( cmsysProcess_GetExitValue(cp) != 0 )
2989 else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Exception)
2991 const char* exception_str = cmsysProcess_GetExceptionString(cp);
2992 cmCTestLog(this, ERROR_MESSAGE, exception_str << std::endl);
2993 stdErr->append(exception_str, strlen(exception_str));
2996 else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Error)
2998 const char* error_str = cmsysProcess_GetErrorString(cp);
2999 cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
3000 stdErr->append(error_str, strlen(error_str));
3003 else if(cmsysProcess_GetState(cp) == cmsysProcess_State_Expired)
3005 const char* error_str = "Process terminated due to timeout\n";
3006 cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
3007 stdErr->append(error_str, strlen(error_str));
3011 cmsysProcess_Delete(cp);
3015 //----------------------------------------------------------------------
3016 void cmCTest::SetOutputLogFileName(const char* name)
3018 if ( this->OutputLogFile)
3020 delete this->OutputLogFile;
3021 this->OutputLogFile= 0;
3025 this->OutputLogFile = new cmGeneratedFileStream(name);
3029 //----------------------------------------------------------------------
3030 static const char* cmCTestStringLogType[] =
3035 "HANDLER_VERBOSE_OUTPUT",
3041 //----------------------------------------------------------------------
3049 #define cmCTestLogOutputFileLine(stream) \
3050 if ( this->ShowLineNumbers ) \
3052 (stream) << std::endl << file << ":" << line << " "; \
3055 void cmCTest::InitStreams()
3057 // By default we write output to the process output streams.
3058 this->StreamOut = &std::cout;
3059 this->StreamErr = &std::cerr;
3062 void cmCTest::Log(int logType, const char* file, int line, const char* msg)
3064 if ( !msg || !*msg )
3068 if ( this->OutputLogFile )
3070 bool display = true;
3071 if ( logType == cmCTest::DEBUG && !this->Debug ) { display = false; }
3072 if ( logType == cmCTest::HANDLER_VERBOSE_OUTPUT && !this->Debug &&
3073 !this->ExtraVerbose ) { display = false; }
3076 cmCTestLogOutputFileLine(*this->OutputLogFile);
3077 if ( logType != this->OutputLogFileLastTag )
3079 *this->OutputLogFile << "[";
3080 if ( logType >= OTHER || logType < 0 )
3082 *this->OutputLogFile << "OTHER";
3086 *this->OutputLogFile << cmCTestStringLogType[logType];
3088 *this->OutputLogFile << "] " << std::endl << std::flush;
3090 *this->OutputLogFile << msg << std::flush;
3091 if ( logType != this->OutputLogFileLastTag )
3093 *this->OutputLogFile << std::endl << std::flush;
3094 this->OutputLogFileLastTag = logType;
3100 std::ostream& out = *this->StreamOut;
3101 std::ostream& err = *this->StreamErr;
3107 cmCTestLogOutputFileLine(out);
3112 case OUTPUT: case HANDLER_OUTPUT:
3113 if ( this->Debug || this->Verbose )
3115 cmCTestLogOutputFileLine(out);
3120 case HANDLER_VERBOSE_OUTPUT:
3121 if ( this->Debug || this->ExtraVerbose )
3123 cmCTestLogOutputFileLine(out);
3129 cmCTestLogOutputFileLine(err);
3134 cmCTestLogOutputFileLine(err);
3137 cmSystemTools::SetErrorOccured();
3140 cmCTestLogOutputFileLine(out);
3147 //-------------------------------------------------------------------------
3148 double cmCTest::GetRemainingTimeAllowed()
3150 if (!this->GetHandler("script"))
3155 cmCTestScriptHandler* ch
3156 = static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
3158 return ch->GetRemainingTimeAllowed();
3161 //----------------------------------------------------------------------
3162 void cmCTest::OutputTestErrors(std::vector<char> const &process_output)
3164 std::string test_outputs("\n*** Test Failed:\n");
3165 if(process_output.size())
3167 test_outputs.append(&*process_output.begin(), process_output.size());
3169 cmCTestLog(this, HANDLER_OUTPUT, test_outputs << std::endl << std::flush);
3172 //----------------------------------------------------------------------
3173 bool cmCTest::CompressString(std::string& str)
3178 unsigned char* in = reinterpret_cast<unsigned char*>(
3179 const_cast<char*>(str.c_str()));
3180 //zlib makes the guarantee that this is the maximum output size
3181 int outSize = static_cast<int>(
3182 static_cast<double>(str.size()) * 1.001 + 13.0);
3183 unsigned char* out = new unsigned char[outSize];
3185 strm.zalloc = Z_NULL;
3186 strm.zfree = Z_NULL;
3187 strm.opaque = Z_NULL;
3188 ret = deflateInit(&strm, -1); //default compression level
3195 strm.avail_in = static_cast<uInt>(str.size());
3197 strm.avail_out = outSize;
3198 strm.next_out = out;
3199 ret = deflate(&strm, Z_FINISH);
3201 if(ret == Z_STREAM_ERROR || ret != Z_STREAM_END)
3203 cmCTestLog(this, ERROR_MESSAGE, "Error during gzip compression."
3209 (void)deflateEnd(&strm);
3211 // Now base64 encode the resulting binary string
3212 unsigned char* base64EncodedBuffer
3213 = new unsigned char[static_cast<int>(outSize * 1.5)];
3216 = cmsysBase64_Encode(out, strm.total_out, base64EncodedBuffer, 1);
3219 str.append(reinterpret_cast<char*>(base64EncodedBuffer), rlen);
3221 delete [] base64EncodedBuffer;