diff options
author | Brad King <brad.king@kitware.com> | 2010-01-28 21:48:20 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2010-01-28 21:48:20 (GMT) |
commit | dc1d2189ae922be9d6e7f5fde698532db47e46aa (patch) | |
tree | 28ef61aac78f0bdc190a760d53b6cb89b24262cd /Source/CTest | |
parent | 612409e5b01a7e4823bb379ee9e002177793eb75 (diff) | |
download | CMake-dc1d2189ae922be9d6e7f5fde698532db47e46aa.zip CMake-dc1d2189ae922be9d6e7f5fde698532db47e46aa.tar.gz CMake-dc1d2189ae922be9d6e7f5fde698532db47e46aa.tar.bz2 |
CMake 2.8.1-rc1
Diffstat (limited to 'Source/CTest')
27 files changed, 622 insertions, 140 deletions
diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx index 3fe1c00..b984e85 100644 --- a/Source/CTest/cmCTestBuildCommand.cxx +++ b/Source/CTest/cmCTestBuildCommand.cxx @@ -23,7 +23,11 @@ cmCTestBuildCommand::cmCTestBuildCommand() { this->GlobalGenerator = 0; this->Arguments[ctb_NUMBER_ERRORS] = "NUMBER_ERRORS"; - this->Arguments[ctb_NUMBER_WARNINGS] = "NUMBER_WARNINGS"; + this->Arguments[ctb_NUMBER_WARNINGS] = "NUMBER_WARNINGS"; + this->Arguments[ctb_TARGET] = "TARGET"; + this->Arguments[ctb_CONFIGURATION] = "CONFIGURATION"; + this->Arguments[ctb_FLAGS] = "FLAGS"; + this->Arguments[ctb_PROJECT_NAME] = "PROJECT_NAME"; this->Arguments[ctb_LAST] = 0; this->Last = ctb_LAST; } @@ -49,6 +53,7 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() return 0; } this->Handler = (cmCTestBuildHandler*)handler; + const char* ctestBuildCommand = this->Makefile->GetDefinition("CTEST_BUILD_COMMAND"); if ( ctestBuildCommand && *ctestBuildCommand ) @@ -60,13 +65,33 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() const char* cmakeGeneratorName = this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR"); const char* cmakeProjectName - = this->Makefile->GetDefinition("CTEST_PROJECT_NAME"); - const char* cmakeBuildConfiguration + = (this->Values[ctb_PROJECT_NAME] && *this->Values[ctb_PROJECT_NAME]) + ? this->Values[ctb_PROJECT_NAME] + : this->Makefile->GetDefinition("CTEST_PROJECT_NAME"); + + // Build configuration is determined by: CONFIGURATION argument, + // or CTEST_BUILD_CONFIGURATION script variable, or + // CTEST_CONFIGURATION_TYPE script variable, or ctest -C command + // line argument... in that order. + // + const char* ctestBuildConfiguration = this->Makefile->GetDefinition("CTEST_BUILD_CONFIGURATION"); + const char* cmakeBuildConfiguration + = (this->Values[ctb_CONFIGURATION] && *this->Values[ctb_CONFIGURATION]) + ? this->Values[ctb_CONFIGURATION] + : ((ctestBuildConfiguration && *ctestBuildConfiguration) + ? ctestBuildConfiguration + : this->CTest->GetConfigType().c_str()); + const char* cmakeBuildAdditionalFlags - = this->Makefile->GetDefinition("CTEST_BUILD_FLAGS"); + = (this->Values[ctb_FLAGS] && *this->Values[ctb_FLAGS]) + ? this->Values[ctb_FLAGS] + : this->Makefile->GetDefinition("CTEST_BUILD_FLAGS"); const char* cmakeBuildTarget - = this->Makefile->GetDefinition("CTEST_BUILD_TARGET"); + = (this->Values[ctb_TARGET] && *this->Values[ctb_TARGET]) + ? this->Values[ctb_TARGET] + : this->Makefile->GetDefinition("CTEST_BUILD_TARGET"); + if ( cmakeGeneratorName && *cmakeGeneratorName && cmakeProjectName && *cmakeProjectName ) { @@ -104,7 +129,7 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() } cmakeBuildConfiguration = config; } - + std::string buildCommand = this->GlobalGenerator-> GenerateBuildCommand(cmakeMakeProgram, @@ -119,10 +144,17 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() else { cmOStringStream ostr; - ostr << "CTEST_BUILD_COMMAND or CTEST_CMAKE_GENERATOR not specified. " - "Please specify the CTEST_CMAKE_GENERATOR and CTEST_PROJECT_NAME if " - "this is a CMake project, or specify the CTEST_BUILD_COMMAND for " - "cmake or any other project."; + ostr << "has no project to build. If this is a " + "\"built with CMake\" project, verify that CTEST_CMAKE_GENERATOR " + "and CTEST_PROJECT_NAME are set." + "\n" + "CTEST_PROJECT_NAME is usually set in CTestConfig.cmake. Verify " + "that CTestConfig.cmake exists, or CTEST_PROJECT_NAME " + "is set in the script, or PROJECT_NAME is passed as an argument " + "to ctest_build." + "\n" + "Alternatively, set CTEST_BUILD_COMMAND to build the project " + "with a custom command line."; this->SetError(ostr.str().c_str()); return 0; } diff --git a/Source/CTest/cmCTestBuildCommand.h b/Source/CTest/cmCTestBuildCommand.h index 8122eee..228067e 100644 --- a/Source/CTest/cmCTestBuildCommand.h +++ b/Source/CTest/cmCTestBuildCommand.h @@ -82,6 +82,10 @@ protected: ctb_BUILD = ct_LAST, ctb_NUMBER_ERRORS, ctb_NUMBER_WARNINGS, + ctb_TARGET, + ctb_CONFIGURATION, + ctb_FLAGS, + ctb_PROJECT_NAME, ctb_LAST }; diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index 0095bbc..a125459 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -265,6 +265,32 @@ void cmCTestBuildHandler::PopulateCustomVectors(cmMakefile *mf) } //---------------------------------------------------------------------- +std::string cmCTestBuildHandler::GetMakeCommand() +{ + std::string makeCommand + = this->CTest->GetCTestConfiguration("MakeCommand"); + cmCTestLog(this->CTest, + HANDLER_VERBOSE_OUTPUT, "MakeCommand:" << makeCommand << + "\n"); + + std::string configType = this->CTest->GetConfigType(); + if (configType == "") + { + configType + = this->CTest->GetCTestConfiguration("DefaultCTestConfigurationType"); + } + if (configType == "") + { + configType = "Release"; + } + + cmSystemTools::ReplaceString(makeCommand, + "${CTEST_CONFIGURATION_TYPE}", configType.c_str()); + + return makeCommand; +} + +//---------------------------------------------------------------------- //clearly it would be nice if this were broken up into a few smaller //functions and commented... int cmCTestBuildHandler::ProcessHandler() @@ -300,11 +326,7 @@ int cmCTestBuildHandler::ProcessHandler() } // Determine build command and build directory - const std::string &makeCommand - = this->CTest->GetCTestConfiguration("MakeCommand"); - cmCTestLog(this->CTest, - HANDLER_VERBOSE_OUTPUT, "MakeCommand:" << makeCommand << - "\n"); + std::string makeCommand = this->GetMakeCommand(); if ( makeCommand.size() == 0 ) { cmCTestLog(this->CTest, ERROR_MESSAGE, @@ -312,6 +334,7 @@ int cmCTestBuildHandler::ProcessHandler() << std::endl); return -1; } + const std::string &buildDirectory = this->CTest->GetCTestConfiguration("BuildDirectory"); if ( buildDirectory.size() == 0 ) @@ -519,8 +542,7 @@ void cmCTestBuildHandler::GenerateXMLHeader(std::ostream& os) static_cast<unsigned int>(this->StartBuildTime) << "</StartBuildTime>\n" << "<BuildCommand>" - << cmXMLSafe( - this->CTest->GetCTestConfiguration("MakeCommand")) + << cmXMLSafe(this->GetMakeCommand()) << "</BuildCommand>" << std::endl; } diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h index 7ee50be..439efd6 100644 --- a/Source/CTest/cmCTestBuildHandler.h +++ b/Source/CTest/cmCTestBuildHandler.h @@ -46,7 +46,10 @@ public: int GetTotalErrors() { return this->TotalErrors;} int GetTotalWarnings() { return this->TotalWarnings;} + private: + std::string GetMakeCommand(); + //! Run command specialized for make and configure. Returns process status // and retVal is return value or exception. int RunMakeCommand(const char* command, diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx index 00d9ec5..147173f 100644 --- a/Source/CTest/cmCTestConfigureCommand.cxx +++ b/Source/CTest/cmCTestConfigureCommand.cxx @@ -11,6 +11,7 @@ ============================================================================*/ #include "cmCTestConfigureCommand.h" +#include "cmGlobalGenerator.h" #include "cmCTest.h" #include "cmCTestGenericHandler.h" @@ -66,6 +67,7 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() const char* ctestConfigureCommand = this->Makefile->GetDefinition("CTEST_CONFIGURE_COMMAND"); + if ( ctestConfigureCommand && *ctestConfigureCommand ) { this->CTest->SetCTestConfiguration("ConfigureCommand", @@ -86,6 +88,29 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() "variable"); return 0; } + + const std::string cmakelists_file = source_dir + "/CMakeLists.txt"; + if ( !cmSystemTools::FileExists(cmakelists_file.c_str()) ) + { + cmOStringStream e; + e << "CMakeLists.txt file does not exist [" + << cmakelists_file << "]"; + this->SetError(e.str().c_str()); + return 0; + } + + bool multiConfig = false; + bool cmakeBuildTypeInOptions = false; + + cmGlobalGenerator *gg = + this->Makefile->GetCMakeInstance()->CreateGlobalGenerator( + cmakeGeneratorName); + if(gg) + { + multiConfig = gg->IsMultiConfig(); + delete gg; + } + std::string cmakeConfigureCommand = "\""; cmakeConfigureCommand += this->CTest->GetCMakeExecutable(); cmakeConfigureCommand += "\""; @@ -95,9 +120,23 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() for (it= options.begin(); it!=options.end(); ++it) { option = *it; + cmakeConfigureCommand += " \""; cmakeConfigureCommand += option; cmakeConfigureCommand += "\""; + + if ((0 != strstr(option.c_str(), "CMAKE_BUILD_TYPE=")) || + (0 != strstr(option.c_str(), "CMAKE_BUILD_TYPE:STRING="))) + { + cmakeBuildTypeInOptions = true; + } + } + + if (!multiConfig && !cmakeBuildTypeInOptions) + { + cmakeConfigureCommand += " \"-DCMAKE_BUILD_TYPE:STRING="; + cmakeConfigureCommand += this->CTest->GetConfigType(); + cmakeConfigureCommand += "\""; } cmakeConfigureCommand += " \"-G"; @@ -113,9 +152,9 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() } else { - this->SetError("Configure command is not specified. If this is a CMake " - "project, specify CTEST_CMAKE_GENERATOR, or if this is not CMake " - "project, specify CTEST_CONFIGURE_COMMAND."); + this->SetError("Configure command is not specified. If this is a " + "\"built with CMake\" project, set CTEST_CMAKE_GENERATOR. If not, " + "set CTEST_CONFIGURE_COMMAND."); return 0; } } diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx index 5b0e8ff..8108b19 100644 --- a/Source/CTest/cmCTestGIT.cxx +++ b/Source/CTest/cmCTestGIT.cxx @@ -19,6 +19,8 @@ #include <cmsys/ios/sstream> #include <cmsys/Process.h> +#include <sys/types.h> +#include <time.h> #include <ctype.h> //---------------------------------------------------------------------------- @@ -336,16 +338,28 @@ private: Person author; this->ParsePerson(this->Line.c_str()+7, author); this->Rev.Author = author.Name; - char buf[1024]; + + // Convert the time to a human-readable format that is also easy + // to machine-parse: "CCYY-MM-DD hh:mm:ss". + time_t seconds = static_cast<time_t>(author.Time); + struct tm* t = gmtime(&seconds); + char dt[1024]; + sprintf(dt, "%04d-%02d-%02d %02d:%02d:%02d", + t->tm_year+1900, t->tm_mon+1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); + this->Rev.Date = dt; + + // Add the time-zone field "+zone" or "-zone". + char tz[32]; if(author.TimeZone >= 0) { - sprintf(buf, "%lu +%04ld", author.Time, author.TimeZone); + sprintf(tz, " +%04ld", author.TimeZone); } else { - sprintf(buf, "%lu -%04ld", author.Time, -author.TimeZone); + sprintf(tz, " -%04ld", -author.TimeZone); } - this->Rev.Date = buf; + this->Rev.Date += tz; } } diff --git a/Source/CTest/cmCTestGlobalVC.cxx b/Source/CTest/cmCTestGlobalVC.cxx index 73a36da..8c51102 100644 --- a/Source/CTest/cmCTestGlobalVC.cxx +++ b/Source/CTest/cmCTestGlobalVC.cxx @@ -107,6 +107,19 @@ void cmCTestGlobalVC::WriteXMLDirectory(std::ostream& xml, } //---------------------------------------------------------------------------- +void cmCTestGlobalVC::WriteXMLGlobal(std::ostream& xml) +{ + if(!this->NewRevision.empty()) + { + xml << "\t<Revision>" << this->NewRevision << "</Revision>\n"; + } + if(!this->OldRevision.empty() && this->OldRevision != this->NewRevision) + { + xml << "\t<PriorRevision>" << this->OldRevision << "</PriorRevision>\n"; + } +} + +//---------------------------------------------------------------------------- bool cmCTestGlobalVC::WriteXMLUpdates(std::ostream& xml) { cmCTestLog(this->CTest, HANDLER_OUTPUT, @@ -117,6 +130,8 @@ bool cmCTestGlobalVC::WriteXMLUpdates(std::ostream& xml) this->LoadModifications(); + this->WriteXMLGlobal(xml); + for(std::map<cmStdString, Directory>::const_iterator di = this->Dirs.begin(); di != this->Dirs.end(); ++di) { diff --git a/Source/CTest/cmCTestGlobalVC.h b/Source/CTest/cmCTestGlobalVC.h index d88016b..a648a59 100644 --- a/Source/CTest/cmCTestGlobalVC.h +++ b/Source/CTest/cmCTestGlobalVC.h @@ -60,6 +60,7 @@ protected: virtual void LoadModifications() = 0; virtual void LoadRevisions() = 0; + virtual void WriteXMLGlobal(std::ostream& xml); void WriteXMLDirectory(std::ostream& xml, std::string const& path, Directory const& dir); }; diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index 1c9f080..1957e04 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -59,6 +59,17 @@ bool cmCTestHandlerCommand } } + // Set the config type of this ctest to the current value of the + // CTEST_CONFIGURATION_TYPE script variable if it is defined. + // The current script value trumps the -C argument on the command + // line. + const char* ctestConfigType = + this->Makefile->GetDefinition("CTEST_CONFIGURATION_TYPE"); + if (ctestConfigType) + { + this->CTest->SetConfigType(ctestConfigType); + } + cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl;); cmCTestGenericHandler* handler = this->InitializeHandler(); if ( !handler ) diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 336303a..a79f131 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -43,8 +43,11 @@ cmCTestMultiProcessHandler::SetTests(TestMap& tests, this->TestRunningMap[i->first] = false; this->TestFinishMap[i->first] = false; } - this->ReadCostData(); - this->CreateTestCostList(); + if(!this->CTest->GetShowOnly()) + { + this->ReadCostData(); + this->CreateTestCostList(); + } } // Set the max number of tests that can be run at the same time. @@ -102,6 +105,7 @@ void cmCTestMultiProcessHandler::StartTestProcess(int test) this->RunningCount -= GetProcessorsUsed(test); testRun->EndTest(this->Completed, this->Total, false); this->Failed->push_back(this->Properties[test]->Name); + delete testRun; } cmSystemTools::ChangeDirectory(current_dir.c_str()); } @@ -412,12 +416,9 @@ void cmCTestMultiProcessHandler::CheckResume() fin.close(); } } - else + else if(cmSystemTools::FileExists(fname.c_str(), true)) { - if(cmSystemTools::FileExists(fname.c_str(), true)) - { - cmSystemTools::RemoveFile(fname.c_str()); - } + cmSystemTools::RemoveFile(fname.c_str()); } } diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 3e4757b..24d1d9f 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -15,6 +15,9 @@ #include "cmCTest.h" #include "cmSystemTools.h" +#include <cm_zlib.h> +#include <cmsys/Base64.h> + cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler) { this->CTest = handler->CTest; @@ -23,9 +26,12 @@ cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler) this->TestProcess = 0; this->TestResult.ExecutionTime =0; this->TestResult.ReturnValue = 0; - this->TestResult.Status = 0; + this->TestResult.Status = cmCTestTestHandler::NOT_RUN; this->TestResult.TestCount = 0; this->TestResult.Properties = 0; + this->ProcessOutput = ""; + this->CompressedOutput = ""; + this->CompressionRatio = 2; } cmCTestRunTest::~cmCTestRunTest() @@ -52,7 +58,7 @@ bool cmCTestRunTest::CheckOutput() { // Store this line of output. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, - this->GetIndex() << ": " << line << std::endl); + this->GetIndex() << ": " << line << std::endl); this->ProcessOutput += line; this->ProcessOutput += "\n"; } @@ -65,8 +71,73 @@ bool cmCTestRunTest::CheckOutput() } //--------------------------------------------------------- +// Streamed compression of test output. The compressed data +// is appended to this->CompressedOutput +void cmCTestRunTest::CompressOutput() +{ + int ret; + z_stream strm; + + unsigned char* in = + reinterpret_cast<unsigned char*>( + const_cast<char*>(this->ProcessOutput.c_str())); + //zlib makes the guarantee that this is the maximum output size + int outSize = static_cast<int>(this->ProcessOutput.size() * 1.001 + 13); + unsigned char* out = new unsigned char[outSize]; + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit(&strm, -1); //default compression level + if (ret != Z_OK) + { + return; + } + + strm.avail_in = static_cast<uInt>(this->ProcessOutput.size()); + strm.next_in = in; + strm.avail_out = outSize; + strm.next_out = out; + ret = deflate(&strm, Z_FINISH); + + if(ret == Z_STREAM_ERROR || ret != Z_STREAM_END) + { + cmCTestLog(this->CTest, ERROR_MESSAGE, "Error during output " + "compression. Sending uncompressed output." << std::endl); + return; + } + + (void)deflateEnd(&strm); + + unsigned char *encoded_buffer + = new unsigned char[static_cast<int>(outSize * 1.5)]; + + unsigned long rlen + = cmsysBase64_Encode(out, strm.total_out, encoded_buffer, 1); + + for(unsigned long i = 0; i < rlen; i++) + { + this->CompressedOutput += encoded_buffer[i]; + } + + if(strm.total_in) + { + this->CompressionRatio = static_cast<double>(strm.total_out) / + static_cast<double>(strm.total_in); + } + + delete [] encoded_buffer; + delete [] out; +} + +//--------------------------------------------------------- bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) { + if (this->CTest->ShouldCompressTestOutput()) + { + this->CompressOutput(); + } + //restore the old environment if (this->ModifyEnv) { @@ -146,7 +217,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) } else if ( res == cmsysProcess_State_Expired ) { - cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout"); + cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout "); this->TestResult.Status = cmCTestTestHandler::TIMEOUT; outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure; } @@ -177,10 +248,9 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) this->TestResult.Status = cmCTestTestHandler::OTHER_FAULT; } } - else // if ( res == cmsysProcess_State_Error ) + else //cmsysProcess_State_Error { - cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Bad command " << res ); - this->TestResult.Status = cmCTestTestHandler::BAD_COMMAND; + cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Not Run "); } passed = this->TestResult.Status == cmCTestTestHandler::COMPLETED; @@ -202,18 +272,11 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) // Output since that is what is parsed by cmCTestMemCheckHandler if(!this->TestHandler->MemCheck && started) { - if (this->TestResult.Status == cmCTestTestHandler::COMPLETED) - { this->TestHandler->CleanTestOutput(this->ProcessOutput, static_cast<size_t> - (this->TestHandler->CustomMaximumPassedTestOutputSize)); - } - else - { - this->TestHandler->CleanTestOutput(this->ProcessOutput, - static_cast<size_t> - (this->TestHandler->CustomMaximumFailedTestOutputSize)); - } + (this->TestResult.Status == cmCTestTestHandler::COMPLETED ? + this->TestHandler->CustomMaximumPassedTestOutputSize : + this->TestHandler->CustomMaximumFailedTestOutputSize)); } this->TestResult.Reason = reason; if (this->TestHandler->LogFile) @@ -258,16 +321,23 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) << "----------------------------------------------------------" << std::endl << std::endl; } + // if the test actually started and ran + // record the results in TestResult if(started) { - this->TestResult.Output = this->ProcessOutput; + bool compress = this->CompressionRatio < 1 && + this->CTest->ShouldCompressTestOutput(); + this->TestResult.Output = compress ? this->CompressedOutput + : this->ProcessOutput; + this->TestResult.CompressOutput = compress; this->TestResult.ReturnValue = this->TestProcess->GetExitValue(); this->TestResult.CompletionStatus = "Completed"; this->TestResult.ExecutionTime = this->TestProcess->GetTotalTime(); - this->TestHandler->TestResults.push_back(this->TestResult); - this->MemCheckPostProcess(); } + // Always push the current TestResult onto the + // TestHandler vector + this->TestHandler->TestResults.push_back(this->TestResult); delete this->TestProcess; return passed; } @@ -308,16 +378,41 @@ bool cmCTestRunTest::StartTest(size_t total) std::vector<std::string>& args = this->TestProperties->Args; this->TestResult.Properties = this->TestProperties; this->TestResult.ExecutionTime = 0; + this->TestResult.CompressOutput = false; this->TestResult.ReturnValue = -1; - this->TestResult.CompletionStatus = "Not Run"; - this->TestResult.Status = cmCTestTestHandler::NOT_RUN; + this->TestResult.CompletionStatus = "Failed to start"; + this->TestResult.Status = cmCTestTestHandler::BAD_COMMAND; this->TestResult.TestCount = this->TestProperties->Index; this->TestResult.Name = this->TestProperties->Name; this->TestResult.Path = this->TestProperties->Directory.c_str(); + // Check if all required files exist + for(std::vector<std::string>::iterator i = + this->TestProperties->RequiredFiles.begin(); + i != this->TestProperties->RequiredFiles.end(); ++i) + { + std::string file = *i; + + if(!cmSystemTools::FileExists(file.c_str())) + { + //Required file was not found + this->TestProcess = new cmProcess; + *this->TestHandler->LogFile << "Unable to find required file: " + << file.c_str() << std::endl; + cmCTestLog(this->CTest, ERROR_MESSAGE, "Unable to find required file: " + << file.c_str() << std::endl); + this->TestResult.Output = "Unable to find required file: " + file; + this->TestResult.FullCommandLine = ""; + this->TestResult.CompletionStatus = "Not Run"; + this->TestResult.Status = cmCTestTestHandler::NOT_RUN; + return false; + } + } // log and return if we did not find the executable if (this->ActualCommand == "") { + // if the command was not found create a TestResult object + // that has that information this->TestProcess = new cmProcess; *this->TestHandler->LogFile << "Unable to find executable: " << args[1].c_str() << std::endl; @@ -325,7 +420,8 @@ bool cmCTestRunTest::StartTest(size_t total) << args[1].c_str() << std::endl); this->TestResult.Output = "Unable to find executable: " + args[1]; this->TestResult.FullCommandLine = ""; - this->TestHandler->TestResults.push_back(this->TestResult); + this->TestResult.CompletionStatus = "Not Run"; + this->TestResult.Status = cmCTestTestHandler::NOT_RUN; return false; } this->StartTime = this->CTest->CurrentTime(); diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index bfeda20..1084643 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -45,6 +45,9 @@ public: // Read and store output. Returns true if it must be called again. bool CheckOutput(); + // Compresses the output, writing to CompressedOutput + void CompressOutput(); + //launch the test process, return whether it started correctly bool StartTest(size_t total); //capture and report the test results @@ -53,6 +56,7 @@ public: void ComputeArguments(); private: void DartProcessing(); + void ExeNotFound(std::string exe); bool CreateProcess(double testTimeOut, std::vector<std::string>* environment); void WriteLogOutputTop(size_t completed, size_t total); @@ -71,9 +75,15 @@ private: //flag for whether the env was modified for this run bool ModifyEnv; + + bool UsePrefixCommand; + std::string PrefixCommand; + //stores the original environment if we are modifying it std::vector<std::string> OrigEnv; std::string ProcessOutput; + std::string CompressedOutput; + double CompressionRatio; //The test results cmCTestTestHandler::cmCTestTestResult TestResult; int Index; @@ -96,5 +106,6 @@ inline int getNumWidth(size_t n) } return numWidth; } + #endif diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx index 82e5845..fab9a8c 100644 --- a/Source/CTest/cmCTestSVN.cxx +++ b/Source/CTest/cmCTestSVN.cxx @@ -440,3 +440,11 @@ void cmCTestSVN::LoadModifications() OutputLogger err(this->Log, "status-err> "); this->RunChild(svn_status, &out, &err); } + +//---------------------------------------------------------------------------- +void cmCTestSVN::WriteXMLGlobal(std::ostream& xml) +{ + this->cmCTestGlobalVC::WriteXMLGlobal(xml); + + xml << "\t<SVNPath>" << this->Base << "</SVNPath>\n"; +} diff --git a/Source/CTest/cmCTestSVN.h b/Source/CTest/cmCTestSVN.h index ff9ff0f..f72c58f 100644 --- a/Source/CTest/cmCTestSVN.h +++ b/Source/CTest/cmCTestSVN.h @@ -52,6 +52,8 @@ private: void DoRevision(Revision const& revision, std::vector<Change> const& changes); + void WriteXMLGlobal(std::ostream& xml); + // Parsing helper classes. class InfoParser; class LogParser; diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index 5983e68..fdf17e0 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -583,6 +583,10 @@ void cmCTestScriptHandler::SleepInSeconds(unsigned int secondsToWait) int cmCTestScriptHandler::RunConfigurationScript (const std::string& total_script_arg, bool pscope) { +#ifdef CMAKE_BUILD_WITH_CMAKE + cmSystemTools::SaveRestoreEnvironment sre; +#endif + int result; this->ScriptStartTime = diff --git a/Source/CTest/cmCTestStartCommand.cxx b/Source/CTest/cmCTestStartCommand.cxx index 779a38c..228a173 100644 --- a/Source/CTest/cmCTestStartCommand.cxx +++ b/Source/CTest/cmCTestStartCommand.cxx @@ -14,6 +14,13 @@ #include "cmCTest.h" #include "cmLocalGenerator.h" #include "cmGlobalGenerator.h" +#include "cmCTestVC.h" +#include "cmGeneratedFileStream.h" + +cmCTestStartCommand::cmCTestStartCommand() +{ + this->CreateNewTag = true; +} bool cmCTestStartCommand ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) @@ -42,6 +49,15 @@ bool cmCTestStartCommand } } + if (cnt < args.size()) + { + if (args[cnt] == "APPEND") + { + cnt ++; + this->CreateNewTag = false; + } + } + if ( cnt < args.size() ) { src_dir = args[cnt].c_str(); @@ -76,10 +92,11 @@ bool cmCTestStartCommand cmSystemTools::AddKeepPath(bld_dir); this->CTest->EmptyCTestConfiguration(); - this->CTest->SetCTestConfiguration("SourceDirectory", - cmSystemTools::CollapseFullPath(src_dir).c_str()); - this->CTest->SetCTestConfiguration("BuildDirectory", - cmSystemTools::CollapseFullPath(bld_dir).c_str()); + + std::string sourceDir = cmSystemTools::CollapseFullPath(src_dir); + std::string binaryDir = cmSystemTools::CollapseFullPath(bld_dir); + this->CTest->SetCTestConfiguration("SourceDirectory", sourceDir.c_str()); + this->CTest->SetCTestConfiguration("BuildDirectory", binaryDir.c_str()); cmCTestLog(this->CTest, HANDLER_OUTPUT, "Run dashboard with model " << smodel << std::endl @@ -92,13 +109,62 @@ bool cmCTestStartCommand " Track: " << track << std::endl); } + // Log startup actions. + std::string startLogFile = binaryDir + "/Testing/Temporary/LastStart.log"; + cmGeneratedFileStream ofs(startLogFile.c_str()); + if(!ofs) + { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Cannot create log file: LastStart.log" << std::endl); + return false; + } + + // Make sure the source directory exists. + if(!this->InitialCheckout(ofs, sourceDir)) + { + return false; + } + if(!cmSystemTools::FileIsDirectory(sourceDir.c_str())) + { + cmOStringStream e; + e << "given source path\n" + << " " << sourceDir << "\n" + << "which is not an existing directory. " + << "Set CTEST_CHECKOUT_COMMAND to a command line to create it."; + this->SetError(e.str().c_str()); + return false; + } + this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", "OFF"); this->CTest->SetSuppressUpdatingCTestConfiguration(true); int model = this->CTest->GetTestModelFromString(smodel); this->CTest->SetTestModel(model); this->CTest->SetProduceXML(true); - return this->CTest->InitializeFromCommand(this, true); + return this->CTest->InitializeFromCommand(this); } - +//---------------------------------------------------------------------------- +bool cmCTestStartCommand::InitialCheckout( + std::ostream& ofs, std::string const& sourceDir) +{ + // Use the user-provided command to create the source tree. + const char* initialCheckoutCommand + = this->Makefile->GetDefinition("CTEST_CHECKOUT_COMMAND"); + if(!initialCheckoutCommand) + { + initialCheckoutCommand = + this->Makefile->GetDefinition("CTEST_CVS_CHECKOUT"); + } + if(initialCheckoutCommand) + { + // Use a generic VC object to run and log the command. + cmCTestVC vc(this->CTest, ofs); + vc.SetSourceDirectory(sourceDir.c_str()); + if(!vc.InitialCheckout(initialCheckoutCommand)) + { + return false; + } + } + return true; +} diff --git a/Source/CTest/cmCTestStartCommand.h b/Source/CTest/cmCTestStartCommand.h index 84f7631..afbc77b 100644 --- a/Source/CTest/cmCTestStartCommand.h +++ b/Source/CTest/cmCTestStartCommand.h @@ -23,7 +23,7 @@ class cmCTestStartCommand : public cmCTestCommand { public: - cmCTestStartCommand() {} + cmCTestStartCommand(); /** * This is a virtual constructor for the command. @@ -33,6 +33,7 @@ public: cmCTestStartCommand* ni = new cmCTestStartCommand; ni->CTest = this->CTest; ni->CTestScriptHandler = this->CTestScriptHandler; + ni->CreateNewTag = this->CreateNewTag; return ni; } @@ -44,6 +45,14 @@ public: cmExecutionStatus &status); /** + * Will this invocation of ctest_start create a new TAG file? + */ + bool ShouldCreateNewTag() + { + return this->CreateNewTag; + } + + /** * The name of the command as specified in CMakeList.txt. */ virtual const char* GetName() { return "ctest_start";} @@ -62,16 +71,21 @@ public: virtual const char* GetFullDocumentation() { return - " ctest_start(Model [TRACK <track>] [source [binary]])\n" + " ctest_start(Model [TRACK <track>] [APPEND] [source [binary]])\n" "Starts the testing for a given model. The command should be called " "after the binary directory is initialized. If the 'source' and " "'binary' directory are not specified, it reads the " "CTEST_SOURCE_DIRECTORY and CTEST_BINARY_DIRECTORY. If the track is " - "specified, the submissions will go to the specified track."; + "specified, the submissions will go to the specified track. " + "If APPEND is used, the existing TAG is used rather than " + "creating a new one based on the current time stamp."; } cmTypeMacro(cmCTestStartCommand, cmCTestCommand); +private: + bool InitialCheckout(std::ostream& ofs, std::string const& sourceDir); + bool CreateNewTag; }; diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index cbef1f1..7b4f38b 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -72,6 +72,8 @@ void cmCTestSubmitHandler::Initialize() this->SubmitPart[p] = true; } this->CDash = false; + this->HasWarnings = false; + this->HasErrors = false; this->Superclass::Initialize(); this->HTTPProxy = ""; this->HTTPProxyType = 0; @@ -309,7 +311,12 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix, } } } - + if(this->CTest->ShouldUseHTTP10()) + { + curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + } + // enable HTTP ERROR parsing + curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); /* enable uploading */ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1); @@ -409,6 +416,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix, cmCTestLog(this->CTest, DEBUG, "CURL output: [" << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]" << std::endl); + this->ParseResponse(chunk); } if ( chunkDebug.size() > 0 ) { @@ -455,6 +463,36 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix, } //---------------------------------------------------------------------------- +void cmCTestSubmitHandler +::ParseResponse(cmCTestSubmitHandlerVectorOfChar chunk) +{ + std::string output = ""; + + for(cmCTestSubmitHandlerVectorOfChar::iterator i = chunk.begin(); + i != chunk.end(); ++i) + { + output += *i; + } + output = cmSystemTools::UpperCase(output); + + if(output.find("WARNING") != std::string::npos) + { + this->HasWarnings = true; + } + if(output.find("ERROR") != std::string::npos) + { + this->HasErrors = true; + } + + if(this->HasWarnings || this->HasErrors) + { + cmCTestLog(this->CTest, HANDLER_OUTPUT, " Server Response:\n" << + cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "\n"); + } + +} + +//---------------------------------------------------------------------------- bool cmCTestSubmitHandler::TriggerUsingHTTP( const std::set<cmStdString>& files, const cmStdString& remoteprefix, @@ -1149,9 +1187,20 @@ int cmCTestSubmitHandler::ProcessHandler() return -1; } } - cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful" - << std::endl); - ofs << " Submission successful" << std::endl; + if(this->HasErrors) + { + cmCTestLog(this->CTest, HANDLER_OUTPUT, " Errors occurred during " + "submission." << std::endl); + ofs << " Errors occurred during submission. " << std::endl; + } + else + { + cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful" << + (this->HasWarnings ? ", with warnings." : "") << std::endl); + ofs << " Submission successful" << + (this->HasWarnings ? ", with warnings." : "") << std::endl; + } + return 0; } else if ( dropMethod == "xmlrpc" ) diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h index d93f94d..8b011ea 100644 --- a/Source/CTest/cmCTestSubmitHandler.h +++ b/Source/CTest/cmCTestSubmitHandler.h @@ -75,6 +75,8 @@ private: const cmStdString& remoteprefix, const cmStdString& url); + void ParseResponse(std::vector<char>); + std::string GetSubmitResultsPrefix(); cmStdString HTTPProxy; @@ -85,6 +87,8 @@ private: std::ostream* LogFile; bool SubmitPart[cmCTest::PartCount]; bool CDash; + bool HasWarnings; + bool HasErrors; cmCTest::SetOfStrings Files; }; diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx index a719b09..b0adf22 100644 --- a/Source/CTest/cmCTestTestCommand.cxx +++ b/Source/CTest/cmCTestTestCommand.cxx @@ -24,6 +24,7 @@ cmCTestTestCommand::cmCTestTestCommand() this->Arguments[ctt_EXCLUDE_LABEL] = "EXCLUDE_LABEL"; this->Arguments[ctt_INCLUDE_LABEL] = "INCLUDE_LABEL"; this->Arguments[ctt_PARALLEL_LEVEL] = "PARALLEL_LEVEL"; + this->Arguments[ctt_SCHEDULE_RANDOM] = "SCHEDULE_RANDOM"; this->Arguments[ctt_LAST] = 0; this->Last = ctt_LAST; } @@ -32,6 +33,7 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() { const char* ctestTimeout = this->Makefile->GetDefinition("CTEST_TEST_TIMEOUT"); + double timeout = this->CTest->GetTimeOut(); if ( ctestTimeout ) { @@ -91,6 +93,11 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() handler->SetOption("ParallelLevel", this->Values[ctt_PARALLEL_LEVEL]); } + if(this->Values[ctt_SCHEDULE_RANDOM]) + { + handler->SetOption("ScheduleRandom", + this->Values[ctt_SCHEDULE_RANDOM]); + } return handler; } @@ -98,4 +105,3 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeActualHandler() { return this->CTest->GetInitializedHandler("test"); } - diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h index 73ce913..12314df 100644 --- a/Source/CTest/cmCTestTestCommand.h +++ b/Source/CTest/cmCTestTestCommand.h @@ -61,7 +61,8 @@ public: " [INCLUDE include regex] [RETURN_VALUE res] \n" " [EXCLUDE_LABEL exclude regex] \n" " [INCLUDE_LABEL label regex] \n" - " [PARALLEL_LEVEL level]) \n" + " [PARALLEL_LEVEL level] \n" + " [SCHEDULE_RANDOM on]) \n" "Tests the given build directory and stores results in Test.xml. The " "second argument is a variable that will hold value. Optionally, " "you can specify the starting test number START, the ending test number " @@ -70,7 +71,9 @@ public: "to not run EXCLUDE. EXCLUDE_LABEL and INCLUDE_LABEL are regular " "expression for test to be included or excluded by the test " "property LABEL. PARALLEL_LEVEL should be set to a positive number " - "representing the number of tests to be run in parallel." + "representing the number of tests to be run in parallel. " + "SCHEDULE_RANDOM will launch tests in a random order, and is " + "typically used to detect implicit test dependencies." "\n" CTEST_COMMAND_APPEND_OPTION_DOCS; } @@ -92,6 +95,7 @@ protected: ctt_EXCLUDE_LABEL, ctt_INCLUDE_LABEL, ctt_PARALLEL_LEVEL, + ctt_SCHEDULE_RANDOM, ctt_LAST }; }; diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 2491d19..78f2c30 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -500,11 +500,16 @@ int cmCTestTestHandler::ProcessHandler() { // Update internal data structure from generic one this->SetTestsToRunInformation(this->GetOption("TestsToRunInformation")); - this->SetUseUnion(cmSystemTools::IsOn(this->GetOption("UseUnion"))); + this->SetUseUnion(cmSystemTools::IsOn(this->GetOption("UseUnion"))); + if(cmSystemTools::IsOn(this->GetOption("ScheduleRandom"))) + { + this->CTest->SetScheduleType("Random"); + } if(this->GetOption("ParallelLevel")) { this->CTest->SetParallelLevel(atoi(this->GetOption("ParallelLevel"))); } + const char* val; val = this->GetOption("LabelRegularExpression"); if ( val ) @@ -684,13 +689,12 @@ void cmCTestTestHandler::PrintLabelSummary() } } } - it = this->TestList.begin(); ri = this->TestResults.begin(); // fill maps - for(; it != this->TestList.end(); ++it, ++ri) + for(; ri != this->TestResults.end(); ++ri) { - cmCTestTestProperties& p = *it; - cmCTestTestResult &result = *ri; + cmCTestTestResult &result = *ri; + cmCTestTestProperties& p = *result.Properties; if(p.Labels.size() != 0) { for(std::vector<std::string>::iterator l = p.Labels.begin(); @@ -1030,12 +1034,28 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed, cmCTestMultiProcessHandler::TestMap tests; cmCTestMultiProcessHandler::PropertiesMap properties; + bool randomSchedule = this->CTest->GetScheduleType() == "Random"; + if(randomSchedule) + { + srand((unsigned)time(0)); + } + for (ListOfTests::iterator it = this->TestList.begin(); it != this->TestList.end(); ++it) { cmCTestTestProperties& p = *it; cmCTestMultiProcessHandler::TestSet depends; + if(randomSchedule) + { + p.Cost = rand(); + } + + if(p.Timeout == 0 && this->CTest->GetGlobalTimeout() != 0) + { + p.Timeout = this->CTest->GetGlobalTimeout(); + } + if(p.Depends.size()) { for(std::vector<std::string>::iterator i = p.Depends.begin(); @@ -1166,12 +1186,17 @@ void cmCTestTestHandler::GenerateDartOutput(std::ostream& os) } os << "\t\t\t<Measurement>\n" - << "\t\t\t\t<Value>"; + << "\t\t\t\t<Value" + << (result->CompressOutput ? + " encoding=\"base64\" compression=\"gzip\">" + : ">"); os << cmXMLSafe(result->Output); os << "</Value>\n" << "\t\t\t</Measurement>\n" << "\t\t</Results>\n"; + + this->AttachFiles(os, result); this->WriteTestResultFooter(os, result); } @@ -1234,6 +1259,73 @@ void cmCTestTestHandler::WriteTestResultFooter(std::ostream& os, } //---------------------------------------------------------------------- +void cmCTestTestHandler::AttachFiles(std::ostream& os, + cmCTestTestResult* result) +{ + if(result->Status != cmCTestTestHandler::COMPLETED + && result->Properties->AttachOnFail.size()) + { + result->Properties->AttachedFiles.insert( + result->Properties->AttachedFiles.end(), + result->Properties->AttachOnFail.begin(), + result->Properties->AttachOnFail.end()); + } + for(std::vector<std::string>::const_iterator file = + result->Properties->AttachedFiles.begin(); + file != result->Properties->AttachedFiles.end(); ++file) + { + std::string base64 = this->EncodeFile(*file); + std::string fname = cmSystemTools::GetFilenameName(*file); + os << "\t\t<NamedMeasurement name=\"Attached File\" encoding=\"base64\" " + "compression=\"tar/gzip\" filename=\"" << fname << "\" type=\"file\">" + "\n\t\t\t<Value>\n\t\t\t" + << base64 + << "\n\t\t\t</Value>\n\t\t</NamedMeasurement>\n"; + } +} + +//---------------------------------------------------------------------- +std::string cmCTestTestHandler::EncodeFile(std::string file) +{ + std::string tarFile = file + "_temp.tar.gz"; + std::vector<cmStdString> files; + files.push_back(file); + + if(!cmSystemTools::CreateTar(tarFile.c_str(), files, true, false)) + { + cmCTestLog(this->CTest, ERROR_MESSAGE, "Error creating tar while " + "attaching file: " << file << std::endl); + return ""; + } + long len = cmSystemTools::FileLength(tarFile.c_str()); + std::ifstream ifs(tarFile.c_str(), std::ios::in +#ifdef _WIN32 + | std::ios::binary +#endif + ); + unsigned char *file_buffer = new unsigned char [ len + 1 ]; + ifs.read(reinterpret_cast<char*>(file_buffer), len); + ifs.close(); + cmSystemTools::RemoveFile(tarFile.c_str()); + + unsigned char *encoded_buffer + = new unsigned char [ static_cast<int>(len * 1.5 + 5) ]; + + unsigned long rlen + = cmsysBase64_Encode(file_buffer, len, encoded_buffer, 1); + + std::string base64 = ""; + for(unsigned long i = 0; i < rlen; i++) + { + base64 += encoded_buffer[i]; + } + delete [] file_buffer; + delete [] encoded_buffer; + + return base64; +} + +//---------------------------------------------------------------------- int cmCTestTestHandler::ExecuteCommands(std::vector<cmStdString>& vec) { std::vector<cmStdString>::iterator it; @@ -1274,7 +1366,7 @@ void cmCTestTestHandler std::vector<std::string> &attemptedConfigs, std::string filepath, std::string &filename) -{ +{ std::string tempPath; if (filepath.size() && @@ -1985,6 +2077,28 @@ bool cmCTestTestHandler::SetTestsProperties( { rtit->WillFail = cmSystemTools::IsOn(val.c_str()); } + if ( key == "ATTACHED_FILES" ) + { + std::vector<std::string> lval; + cmSystemTools::ExpandListArgument(val.c_str(), lval); + + for(std::vector<std::string>::iterator f = lval.begin(); + f != lval.end(); ++f) + { + rtit->AttachedFiles.push_back(*f); + } + } + if ( key == "ATTACHED_FILES_ON_FAIL" ) + { + std::vector<std::string> lval; + cmSystemTools::ExpandListArgument(val.c_str(), lval); + + for(std::vector<std::string>::iterator f = lval.begin(); + f != lval.end(); ++f) + { + rtit->AttachOnFail.push_back(*f); + } + } if ( key == "TIMEOUT" ) { rtit->Timeout = atof(val.c_str()); @@ -1993,6 +2107,17 @@ bool cmCTestTestHandler::SetTestsProperties( { rtit->Cost = static_cast<float>(atof(val.c_str())); } + if ( key == "REQUIRED_FILES" ) + { + std::vector<std::string> lval; + cmSystemTools::ExpandListArgument(val.c_str(), lval); + + for(std::vector<std::string>::iterator f = lval.begin(); + f != lval.end(); ++f) + { + rtit->RequiredFiles.push_back(*f); + } + } if ( key == "RUN_SERIAL" ) { rtit->RunSerial = cmSystemTools::IsOn(val.c_str()); @@ -2088,6 +2213,7 @@ bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args) { const std::string& testname = args[0]; cmCTestLog(this->CTest, DEBUG, "Add test: " << args[0] << std::endl); + if (this->UseExcludeRegExpFlag && this->UseExcludeRegExpFirst && this->ExcludeTestsRegularExpression.find(testname.c_str())) diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index ceb5020..1513410 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -84,7 +84,10 @@ public: cmStdString Name; cmStdString Directory; std::vector<std::string> Args; + std::vector<std::string> RequiredFiles; std::vector<std::string> Depends; + std::vector<std::string> AttachedFiles; + std::vector<std::string> AttachOnFail; std::vector<std::pair<cmsys::RegularExpression, std::string> > ErrorRegularExpressions; std::vector<std::pair<cmsys::RegularExpression, @@ -111,6 +114,7 @@ public: double ExecutionTime; int ReturnValue; int Status; + bool CompressOutput; std::string CompletionStatus; std::string Output; std::string RegressionImages; @@ -142,6 +146,10 @@ protected: void WriteTestResultHeader(std::ostream& os, cmCTestTestResult* result); void WriteTestResultFooter(std::ostream& os, cmCTestTestResult* result); + // Write attached test files into the xml + void AttachFiles(std::ostream& os, cmCTestTestResult* result); + // Helper function to encode attached test files + std::string EncodeFile(std::string file); //! Clean test output to specified length bool CleanTestOutput(std::string& output, size_t length); diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx index 6dbe815..571745d 100644 --- a/Source/CTest/cmCTestUpdateCommand.cxx +++ b/Source/CTest/cmCTestUpdateCommand.cxx @@ -56,14 +56,6 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler() this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile, "HGUpdateOptions", "CTEST_HG_UPDATE_OPTIONS"); - const char* initialCheckoutCommand - = this->Makefile->GetDefinition("CTEST_CHECKOUT_COMMAND"); - if ( !initialCheckoutCommand ) - { - initialCheckoutCommand = - this->Makefile->GetDefinition("CTEST_CVS_CHECKOUT"); - } - cmCTestGenericHandler* handler = this->CTest->GetInitializedHandler("update"); if ( !handler ) @@ -78,24 +70,6 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler() return 0; } handler->SetOption("SourceDirectory", source_dir.c_str()); - if ( initialCheckoutCommand ) - { - handler->SetOption("InitialCheckout", initialCheckoutCommand); - } - if ( (!cmSystemTools::FileExists(source_dir.c_str()) || - !cmSystemTools::FileIsDirectory(source_dir.c_str())) - && !initialCheckoutCommand ) - { - cmOStringStream str; - str << "cannot find source directory: " << source_dir.c_str() << "."; - if ( !cmSystemTools::FileExists(source_dir.c_str()) ) - { - str << " Looks like it is not checked out yet. Please specify " - "CTEST_CHECKOUT_COMMAND."; - } - this->SetError(str.str().c_str()); - return 0; - } return handler; } diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx index cd2f661..f87b37c 100644 --- a/Source/CTest/cmCTestUpdateHandler.cxx +++ b/Source/CTest/cmCTestUpdateHandler.cxx @@ -201,15 +201,6 @@ int cmCTestUpdateHandler::ProcessHandler() this->StartLogFile("Update", ofs); } - cmCTestLog(this->CTest, HANDLER_OUTPUT, - "Updating the repository" << std::endl); - - // Make sure the source directory exists. - if(!this->InitialCheckout(ofs)) - { - return -1; - } - cmCTestLog(this->CTest, HANDLER_OUTPUT, " Updating the repository: " << sourceDirectory << std::endl); @@ -267,7 +258,8 @@ int cmCTestUpdateHandler::ProcessHandler() << this->CTest->GetTestModelString() << "</BuildStamp>" << std::endl; os << "\t<StartDateTime>" << start_time << "</StartDateTime>\n" << "\t<StartTime>" << start_time_time << "</StartTime>\n" - << "\t<UpdateCommand>" << cmXMLSafe(vc->GetUpdateCommandLine()) + << "\t<UpdateCommand>" + << cmXMLSafe(vc->GetUpdateCommandLine()).Quotes(false) << "</UpdateCommand>\n" << "\t<UpdateType>" << cmXMLSafe( cmCTestUpdateHandlerUpdateToString(this->UpdateType)) @@ -323,32 +315,6 @@ int cmCTestUpdateHandler::ProcessHandler() } //---------------------------------------------------------------------- -bool cmCTestUpdateHandler::InitialCheckout(std::ostream& ofs) -{ - // Use the user-provided command to create the source tree. - if(const char* command = this->GetOption("InitialCheckout")) - { - // Use a generic VC object to run and log the command. - cmCTestVC vc(this->CTest, ofs); - vc.SetSourceDirectory(this->GetOption("SourceDirectory")); - if(!vc.InitialCheckout(command)) - { - return false; - } - - if(!this->CTest->InitializeFromCommand(this->Command)) - { - cmCTestLog(this->CTest, HANDLER_OUTPUT, - " Fatal Error in initialize: " - << std::endl); - cmSystemTools::SetFatalErrorOccured(); - return false; - } - } - return true; -} - -//---------------------------------------------------------------------- int cmCTestUpdateHandler::DetectVCS(const char* dir) { std::string sourceDirectory = dir; diff --git a/Source/CTest/cmCTestUpdateHandler.h b/Source/CTest/cmCTestUpdateHandler.h index 78426ea..55ec974 100644 --- a/Source/CTest/cmCTestUpdateHandler.h +++ b/Source/CTest/cmCTestUpdateHandler.h @@ -65,7 +65,6 @@ private: std::string UpdateCommand; int UpdateType; - bool InitialCheckout(std::ostream& ofs); int DetectVCS(const char* dir); bool SelectVCS(); }; diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 1895066..b028cc0 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -79,7 +79,10 @@ bool cmProcess::Buffer::GetLine(std::string& line) // Extract the range first..last as a line. const char* text = &*this->begin() + this->First; size_type length = this->Last - this->First; - length -= (length && text[length-1] == '\r')? 1:0; + while(length && text[length-1] == '\r') + { + length --; + } line.assign(text, length); // Start a new range for the next line. |