diff options
-rw-r--r-- | Source/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Source/CTest/cmCTestConfigureHandler.cxx | 114 | ||||
-rw-r--r-- | Source/CTest/cmCTestConfigureHandler.h | 53 | ||||
-rw-r--r-- | Source/CTest/cmCTestScriptHandler.cxx | 66 | ||||
-rw-r--r-- | Source/CTest/cmCTestScriptHandler.h | 5 | ||||
-rw-r--r-- | Source/CTest/cmCTestUpdateHandler.cxx | 407 | ||||
-rw-r--r-- | Source/CTest/cmCTestUpdateHandler.h | 59 | ||||
-rw-r--r-- | Source/cmCTest.cxx | 473 | ||||
-rw-r--r-- | Source/cmCTest.h | 92 |
9 files changed, 774 insertions, 497 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index aae17c1..d7372ac 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -111,6 +111,8 @@ ADD_EXECUTABLE(DumpDocumentation cmDumpDocumentation) SET(CMTEST_SRCS ctest.cxx cmCTest.cxx CTest/cmCTestScriptHandler.cxx + CTest/cmCTestUpdateHandler.cxx + CTest/cmCTestConfigureHandler.cxx ) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/Source/CTest) diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx new file mode 100644 index 0000000..65950a7 --- /dev/null +++ b/Source/CTest/cmCTestConfigureHandler.cxx @@ -0,0 +1,114 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "cmCTestConfigureHandler.h" + +#include "cmCTest.h" +#include "cmake.h" +#include <cmsys/Process.h> + + +//---------------------------------------------------------------------- +cmCTestConfigureHandler::cmCTestConfigureHandler() +{ + m_Verbose = false; + m_CTest = 0; +} + + +//---------------------------------------------------------------------- +//clearly it would be nice if this were broken up into a few smaller +//functions and commented... +int cmCTestConfigureHandler::ConfigureDirectory(cmCTest *ctest_inst) +{ + m_CTest = ctest_inst; + + std::cout << "Configure project" << std::endl; + std::string cCommand = m_CTest->GetDartConfiguration("ConfigureCommand"); + if ( cCommand.size() == 0 ) + { + std::cerr << "Cannot find ConfigureCommand key in the DartConfiguration.tcl" + << std::endl; + return 1; + } + + std::string buildDirectory = m_CTest->GetDartConfiguration("BuildDirectory"); + if ( buildDirectory.size() == 0 ) + { + std::cerr << "Cannot find BuildDirectory key in the DartConfiguration.tcl" << std::endl; + return 1; + } + + double elapsed_time_start = cmSystemTools::GetTime(); + std::string output; + int retVal = 0; + int res = 0; + if ( !m_CTest->GetShowOnly() ) + { + std::ofstream os; + if ( !m_CTest->OpenOutputFile(m_CTest->GetCurrentTag(), "Configure.xml", os) ) + { + std::cerr << "Cannot open configure file" << std::endl; + return 1; + } + std::string start_time = m_CTest->CurrentTime(); + + std::ofstream ofs; + m_CTest->OpenOutputFile("Temporary", "LastConfigure.log", ofs); + res = m_CTest->RunMakeCommand(cCommand.c_str(), &output, + &retVal, buildDirectory.c_str(), + m_Verbose, 0, ofs); + + if ( ofs ) + { + ofs.close(); + } + + if ( os ) + { + m_CTest->StartXML(os); + os << "<Configure>\n" + << "\t<StartDateTime>" << start_time << "</StartDateTime>" << std::endl; + if ( res == cmsysProcess_State_Exited && retVal ) + { + os << retVal; + } + os << "<ConfigureCommand>" << cCommand.c_str() << "</ConfigureCommand>" << std::endl; + //std::cout << "End" << std::endl; + os << "<Log>" << cmCTest::MakeXMLSafe(output) << "</Log>" << std::endl; + std::string end_time = m_CTest->CurrentTime(); + os << "\t<ConfigureStatus>" << retVal << "</ConfigureStatus>\n" + << "\t<EndDateTime>" << end_time << "</EndDateTime>\n" + << "<ElapsedMinutes>" + << static_cast<int>( + (cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0 + << "</ElapsedMinutes>" + << "</Configure>" << std::endl; + m_CTest->EndXML(os); + } + } + else + { + std::cout << "Configure with command: " << cCommand << std::endl; + } + if (! res || retVal ) + { + std::cerr << "Error(s) when updating the project" << std::endl; + return 1; + } + return 0; +} diff --git a/Source/CTest/cmCTestConfigureHandler.h b/Source/CTest/cmCTestConfigureHandler.h new file mode 100644 index 0000000..5a66c1a --- /dev/null +++ b/Source/CTest/cmCTestConfigureHandler.h @@ -0,0 +1,53 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef cmCTestConfigureHandler_h +#define cmCTestConfigureHandler_h + + +#include "cmStandardIncludes.h" +#include "cmListFileCache.h" + +class cmCTest; + +/** \class cmCTestConfigureHandler + * \brief A class that handles ctest -S invocations + * + */ +class cmCTestConfigureHandler +{ +public: + + /* + * The main entry point for this class + */ + int ConfigureDirectory(cmCTest *); + + /* + * If verbose then more informaiton is printed out + */ + void SetVerbose(bool val) { m_Verbose = val; } + + cmCTestConfigureHandler(); + +private: + bool m_Verbose; + cmCTest *m_CTest; + +}; + +#endif diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index 04c414a..2d35f97 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -48,7 +48,9 @@ cmCTestScriptHandler::cmCTestScriptHandler() m_Backup = false; m_Makefile = 0; m_LocalGenerator = 0; - + m_CMake = 0; + m_GlobalGenerator = 0; + // the *60 is becuase the settings are in minutes but GetTime is seconds m_MinimumInterval = 30*60; } @@ -57,16 +59,23 @@ cmCTestScriptHandler::cmCTestScriptHandler() //---------------------------------------------------------------------- cmCTestScriptHandler::~cmCTestScriptHandler() { - if (m_Makefile) - { - delete m_Makefile; - } + // local generator owns the makefile m_Makefile = 0; if (m_LocalGenerator) { delete m_LocalGenerator; } m_LocalGenerator = 0; + if (m_GlobalGenerator) + { + delete m_GlobalGenerator; + } + m_GlobalGenerator = 0; + if (m_CMake) + { + delete m_CMake; + } + m_CMake = 0; } @@ -121,18 +130,20 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg) } // create a cmake instance to read the configuration script - cmake cm; - cmGlobalGenerator gg; - gg.SetCMakeInstance(&cm); - // read in the list file to fill the cache - if (m_LocalGenerator) + if (m_CMake) { + delete m_CMake; + delete m_GlobalGenerator; delete m_LocalGenerator; } - m_LocalGenerator = gg.CreateLocalGenerator(); - m_LocalGenerator->SetGlobalGenerator(&gg); + m_CMake = new cmake; + m_GlobalGenerator = new cmGlobalGenerator; + m_GlobalGenerator->SetCMakeInstance(m_CMake); + m_LocalGenerator = m_GlobalGenerator->CreateLocalGenerator(); + m_LocalGenerator->SetGlobalGenerator(m_GlobalGenerator); + // set a variable with the path to the current script m_LocalGenerator->GetMakefile()->AddDefinition("CTEST_SCRIPT_DIRECTORY", cmSystemTools::GetFilenamePath( @@ -163,14 +174,31 @@ int cmCTestScriptHandler::ExtractVariables() { // get some info that should be set m_Makefile = m_LocalGenerator->GetMakefile(); + + m_SourceDir.clear(); + m_BinaryDir.clear(); + m_CTestCmd.clear(); - m_SourceDir = m_Makefile->GetDefinition("CTEST_SOURCE_DIRECTORY"); - m_BinaryDir = m_Makefile->GetDefinition("CTEST_BINARY_DIRECTORY"); - m_CTestCmd = m_Makefile->GetDefinition("CTEST_COMMAND"); + if (m_Makefile->GetDefinition("CTEST_SOURCE_DIRECTORY")) + { + m_SourceDir = m_Makefile->GetDefinition("CTEST_SOURCE_DIRECTORY"); + } + if (m_Makefile->GetDefinition("CTEST_BINARY_DIRECTORY")) + { + m_BinaryDir = m_Makefile->GetDefinition("CTEST_BINARY_DIRECTORY"); + } + if (m_Makefile->GetDefinition("CTEST_COMMAND")) + { + m_CTestCmd = m_Makefile->GetDefinition("CTEST_COMMAND"); + } m_Backup = m_Makefile->IsOn("CTEST_BACKUP_AND_RESTORE"); // in order to backup and restore we also must have the cvs root - m_CVSCheckOut = m_Makefile->GetDefinition("CTEST_CVS_CHECKOUT"); + m_CVSCheckOut.clear(); + if (m_Makefile->GetDefinition("CTEST_CVS_CHECKOUT")) + { + m_CVSCheckOut = m_Makefile->GetDefinition("CTEST_CVS_CHECKOUT"); + } if (m_Backup && m_CVSCheckOut.empty()) { cmSystemTools::Error( @@ -213,7 +241,11 @@ int cmCTestScriptHandler::ExtractVariables() atof(m_Makefile->GetDefinition("CTEST_CONTINUOUS_MINIMUM_INTERVAL")); } - m_CVSCmd = m_Makefile->GetDefinition("CTEST_CVS_COMMAND"); + m_CVSCmd.clear(); + if (m_Makefile->GetDefinition("CTEST_CVS_COMMAND")) + { + m_CVSCmd = m_Makefile->GetDefinition("CTEST_CVS_COMMAND"); + } return 0; } diff --git a/Source/CTest/cmCTestScriptHandler.h b/Source/CTest/cmCTestScriptHandler.h index 4a904f7..acddad2 100644 --- a/Source/CTest/cmCTestScriptHandler.h +++ b/Source/CTest/cmCTestScriptHandler.h @@ -24,6 +24,8 @@ class cmMakefile; class cmLocalGenerator; +class cmGlobalGenerator; +class cmake; /** \class cmCTestScriptHandler * \brief A class that handles ctest -S invocations @@ -91,6 +93,9 @@ private: cmMakefile *m_Makefile; cmLocalGenerator *m_LocalGenerator; + cmGlobalGenerator *m_GlobalGenerator; + cmake *m_CMake; + }; #endif diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx new file mode 100644 index 0000000..139f7d2 --- /dev/null +++ b/Source/CTest/cmCTestUpdateHandler.cxx @@ -0,0 +1,407 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "cmCTestUpdateHandler.h" + +#include "cmCTest.h" +#include "cmake.h" +#include "cmMakefile.h" +#include "cmLocalGenerator.h" +#include "cmGlobalGenerator.h" + +//#include <cmsys/RegularExpression.hxx> +#include <cmsys/Process.h> + +// used for sleep +#ifdef _WIN32 +#include "windows.h" +#endif + +#include <stdlib.h> +#include <time.h> +#include <math.h> +#include <float.h> + + +//---------------------------------------------------------------------- +cmCTestUpdateHandler::cmCTestUpdateHandler() +{ + m_Verbose = false; + m_CTest = 0; +} + + +//---------------------------------------------------------------------- +//clearly it would be nice if this were broken up into a few smaller +//functions and commented... +int cmCTestUpdateHandler::UpdateDirectory(cmCTest *ctest_inst) +{ + m_CTest = ctest_inst; + + int count = 0; + std::string::size_type cc, kk; + std::string cvsCommand = m_CTest->GetDartConfiguration("CVSCommand"); + if ( cvsCommand.size() == 0 ) + { + std::cerr << "Cannot find CVSCommand key in the DartConfiguration.tcl" << std::endl; + return -1; + } + std::string cvsOptions = m_CTest->GetDartConfiguration("CVSUpdateOptions"); + if ( cvsOptions.size() == 0 ) + { + std::cerr << "Cannot find CVSUpdateOptions key in the DartConfiguration.tcl" << std::endl; + return -1; + } + + std::string sourceDirectory = m_CTest->GetDartConfiguration("SourceDirectory"); + if ( sourceDirectory.size() == 0 ) + { + std::cerr << "Cannot find SourceDirectory key in the DartConfiguration.tcl" << std::endl; + return -1; + } + + std::string extra_update_opts; + if ( m_CTest->GetTestModel() == cmCTest::NIGHTLY ) + { + struct tm* t = cmCTest::GetNightlyTime(m_CTest->GetDartConfiguration("NightlyStartTime"), + m_Verbose, m_CTest->GetTomorrowTag()); + char current_time[1024]; + sprintf(current_time, "%04d-%02d-%02d %02d:%02d:%02d UTC", + t->tm_year + 1900, + t->tm_mon + 1, + t->tm_mday, + t->tm_hour, + t->tm_min, + t->tm_sec); + std::string today_update_date = current_time; + + extra_update_opts += "-D \"" + today_update_date +"\""; + //std::cout << "Update: " << extra_update_opts << std::endl; + } + + std::string command = cvsCommand + " -z3 update " + cvsOptions + + " " + extra_update_opts; + std::ofstream os; + if ( !m_CTest->OpenOutputFile(m_CTest->GetCurrentTag(), "Update.xml", os) ) + { + std::cerr << "Cannot open log file" << std::endl; + } + std::string start_time = m_CTest->CurrentTime(); + double elapsed_time_start = cmSystemTools::GetTime(); + + std::string goutput; + int retVal = 0; + bool res = true; + std::ofstream ofs; + if ( !m_CTest->GetShowOnly() ) + { + res = cmSystemTools::RunSingleCommand(command.c_str(), &goutput, + &retVal, sourceDirectory.c_str(), + m_Verbose, 0 /*m_TimeOut*/); + if ( m_CTest->OpenOutputFile("Temporary", "LastUpdate.log", ofs) ) + { + ofs << goutput << std::endl;; + } + } + else + { + std::cout << "Update with command: " << command << std::endl; + } + + os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + << "<Update mode=\"Client\" Generator=\"ctest-" << CMake_VERSION_FULL << "\">\n" + << "\t<Site>" << m_CTest->GetDartConfiguration("Site") << "</Site>\n" + << "\t<BuildName>" << m_CTest->GetDartConfiguration("BuildName") + << "</BuildName>\n" + << "\t<BuildStamp>" << m_CTest->GetCurrentTag() << "-" + << m_CTest->GetTestModelString() << "</BuildStamp>" << std::endl; + os << "\t<StartDateTime>" << start_time << "</StartDateTime>\n" + << "\t<UpdateCommand>" << m_CTest->MakeXMLSafe(command) + << "</UpdateCommand>\n" + << "\t<UpdateReturnStatus>"; + int failed = 0; + if ( !res || retVal ) + { + os << "Update error: "; + os << m_CTest->MakeXMLSafe(goutput); + std::cerr << "Update with command: " << command << " failed" << std::endl; + failed = 1; + } + os << "</UpdateReturnStatus>" << std::endl; + if ( !failed ) + { + + std::vector<cmStdString> lines; + cmSystemTools::Split(goutput.c_str(), lines); + std::cout << "Updated; gathering version information" << std::endl; + cmsys::RegularExpression date_author("^date: +([^;]+); +author: +([^;]+); +state: +[^;]+;"); + cmsys::RegularExpression revision("^revision +([^ ]*) *$"); + cmsys::RegularExpression end_of_file("^=============================================================================$"); + cmsys::RegularExpression end_of_comment("^----------------------------$"); + std::string current_path = "<no-path>"; + bool first_file = true; + + cmCTestUpdateHandler::AuthorsToUpdatesMap authors_files_map; + int num_updated = 0; + int num_modified = 0; + int num_conflicting = 0; + for ( cc= 0 ; cc < lines.size(); cc ++ ) + { + const char* line = lines[cc].c_str(); + char mod = line[0]; + if ( line[1] == ' ' && mod != '?' ) + { + if ( mod != 'M' && mod != 'C' ) + { + count ++; + } + const char* file = line + 2; + //std::cout << "Line" << cc << ": " << mod << " - " << file << std::endl; + std::string logcommand = cvsCommand + " -z3 log -N " + file; + //std::cout << "Do log: " << logcommand << std::endl; + std::string output; + res = cmSystemTools::RunSingleCommand(logcommand.c_str(), &output, + &retVal, sourceDirectory.c_str(), + m_Verbose, 0 /*m_TimeOut*/); + if ( ofs ) + { + ofs << output << std::endl; + } + if ( res && retVal == 0) + { + //std::cout << output << std::endl; + std::vector<cmStdString> ulines; + cmSystemTools::Split(output.c_str(), ulines); + std::string::size_type sline = 0; + std::string srevision1 = "Unknown"; + std::string sdate1 = "Unknown"; + std::string sauthor1 = "Unknown"; + std::string semail1 = "Unknown"; + std::string comment1 = ""; + std::string srevision2 = "Unknown"; + std::string sdate2 = "Unknown"; + std::string sauthor2 = "Unknown"; + std::string comment2 = ""; + std::string semail2 = "Unknown"; + bool have_first = false; + bool have_second = false; + for ( kk = 0; kk < ulines.size(); kk ++ ) + { + const char* clp = ulines[kk].c_str(); + if ( !have_second && !sline && revision.find(clp) ) + { + if ( !have_first ) + { + srevision1 = revision.match(1); + } + else + { + srevision2 = revision.match(1); + } + } + else if ( !have_second && !sline && date_author.find(clp) ) + { + sline = kk + 1; + if ( !have_first ) + { + sdate1 = date_author.match(1); + sauthor1 = date_author.match(2); + } + else + { + sdate2 = date_author.match(1); + sauthor2 = date_author.match(2); + } + } + else if ( sline && end_of_comment.find(clp) || end_of_file.find(clp)) + { + if ( !have_first ) + { + have_first = true; + } + else if ( !have_second ) + { + have_second = true; + } + sline = 0; + } + else if ( sline ) + { + if ( !have_first ) + { + comment1 += clp; + comment1 += "\n"; + } + else + { + comment2 += clp; + comment2 += "\n"; + } + } + } + if ( mod == 'M' ) + { + comment1 = "Locally modified file\n"; + } + if ( mod == 'C' ) + { + comment1 = "Conflict while updating\n"; + } + std::string path = cmSystemTools::GetFilenamePath(file); + std::string fname = cmSystemTools::GetFilenameName(file); + if ( path != current_path ) + { + if ( !first_file ) + { + os << "\t</Directory>" << std::endl; + } + else + { + first_file = false; + } + os << "\t<Directory>\n" + << "\t\t<Name>" << path << "</Name>" << std::endl; + } + if ( mod == 'C' ) + { + num_conflicting ++; + os << "\t<Conflicting>" << std::endl; + } + else if ( mod == 'M' ) + { + num_modified ++; + os << "\t<Modified>" << std::endl; + } + else + { + num_updated ++; + os << "\t<Updated>" << std::endl; + } + if ( srevision2 == "Unknown" ) + { + srevision2 = srevision1; + } + os << "\t\t<File Directory=\"" << path << "\">" << fname + << "</File>\n" + << "\t\t<Directory>" << path << "</Directory>\n" + << "\t\t<FullName>" << file << "</FullName>\n" + << "\t\t<CheckinDate>" << sdate1 << "</CheckinDate>\n" + << "\t\t<Author>" << sauthor1 << "</Author>\n" + << "\t\t<Email>" << semail1 << "</Email>\n" + << "\t\t<Log>" << cmCTest::MakeXMLSafe(comment1) << "</Log>\n" + << "\t\t<Revision>" << srevision1 << "</Revision>\n" + << "\t\t<PriorRevision>" << srevision2 << "</PriorRevision>" + << std::endl; + if ( srevision2 != srevision1 ) + { + os + << "\t\t<Revisions>\n" + << "\t\t\t<Revision>" << srevision1 << "</Revision>\n" + << "\t\t\t<PreviousRevision>" << srevision2 << "</PreviousRevision>\n" + << "\t\t\t<Author>" << sauthor1<< "</Author>\n" + << "\t\t\t<Date>" << sdate1 << "</Date>\n" + << "\t\t\t<Comment>" << cmCTest::MakeXMLSafe(comment1) << "</Comment>\n" + << "\t\t\t<Email>" << semail1 << "</Email>\n" + << "\t\t</Revisions>\n" + << "\t\t<Revisions>\n" + << "\t\t\t<Revision>" << srevision2 << "</Revision>\n" + << "\t\t\t<PreviousRevision>" << srevision2 << "</PreviousRevision>\n" + << "\t\t\t<Author>" << sauthor2<< "</Author>\n" + << "\t\t\t<Date>" << sdate2 << "</Date>\n" + << "\t\t\t<Comment>" << cmCTest::MakeXMLSafe(comment2) << "</Comment>\n" + << "\t\t\t<Email>" << semail2 << "</Email>\n" + << "\t\t</Revisions>" << std::endl; + } + if ( mod == 'C' ) + { + os << "\t</Conflicting>" << std::endl; + } + else if ( mod == 'M' ) + { + os << "\t</Modified>" << std::endl; + } + else + { + os << "\t</Updated>" << std::endl; + } + cmCTestUpdateHandler::UpdateFiles *u = &authors_files_map[sauthor1]; + cmCTestUpdateHandler::StringPair p; + p.first = path; + p.second = fname; + u->push_back(p); + + current_path = path; + } + } + } + if ( num_updated ) + { + std::cout << "Found " << num_updated << " updated files" << std::endl; + } + if ( num_modified ) + { + std::cout << "Found " << num_modified << " locally modified files" + << std::endl; + } + if ( num_conflicting ) + { + std::cout << "Found " << num_conflicting << " conflicting files" + << std::endl; + } + if ( !first_file ) + { + os << "\t</Directory>" << std::endl; + } + + cmCTestUpdateHandler::AuthorsToUpdatesMap::iterator it; + for ( it = authors_files_map.begin(); + it != authors_files_map.end(); + it ++ ) + { + os << "\t<Author>\n" + << "\t\t<Name>" << it->first << "</Name>" << std::endl; + cmCTestUpdateHandler::UpdateFiles *u = &(it->second); + for ( cc = 0; cc < u->size(); cc ++ ) + { + os << "\t\t<File Directory=\"" << (*u)[cc].first << "\">" + << (*u)[cc].second << "</File>" << std::endl; + } + os << "\t</Author>" << std::endl; + } + } + + //std::cout << "End" << std::endl; + std::string end_time = m_CTest->CurrentTime(); + os << "\t<EndDateTime>" << end_time << "</EndDateTime>\n" + << "<ElapsedMinutes>" << + static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0 + << "</ElapsedMinutes>" + << "</Update>" << std::endl; + + if ( ofs ) + { + ofs.close(); + } + + if (! res || retVal ) + { + std::cerr << "Error(s) when updating the project" << std::endl; + std::cerr << "Output: " << goutput << std::endl; + return -1; + } + return count; +} diff --git a/Source/CTest/cmCTestUpdateHandler.h b/Source/CTest/cmCTestUpdateHandler.h new file mode 100644 index 0000000..14ef61c --- /dev/null +++ b/Source/CTest/cmCTestUpdateHandler.h @@ -0,0 +1,59 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef cmCTestUpdateHandler_h +#define cmCTestUpdateHandler_h + + +#include "cmStandardIncludes.h" +#include "cmListFileCache.h" + +class cmCTest; + +/** \class cmCTestUpdateHandler + * \brief A class that handles ctest -S invocations + * + */ +class cmCTestUpdateHandler +{ +public: + + /* + * The main entry point for this class + */ + int UpdateDirectory(cmCTest *); + + /* + * If verbose then more informaiton is printed out + */ + void SetVerbose(bool val) { m_Verbose = val; } + + cmCTestUpdateHandler(); + +private: + bool m_Verbose; + cmCTest *m_CTest; + + // Some structures needed for cvs update + struct StringPair : + public std::pair<std::string, std::string>{}; + struct UpdateFiles : public std::vector<StringPair>{}; + struct AuthorsToUpdatesMap : + public std::map<std::string, UpdateFiles>{}; +}; + +#endif diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 28c50c5..1f721ed 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -23,7 +23,10 @@ #include "cmGlob.h" #include "cmDynamicLoader.h" -#include "cmCTestScriptHandler.h" +#include "cmcTestScriptHandler.h" +#include "cmcTestUpdateHandler.h" +#include "cmcTestConfigureHandler.h" + #include "cmCTestSubmit.h" #include "curl/curl.h" @@ -42,7 +45,9 @@ #define DEBUGOUT std::cout << __LINE__ << " "; std::cout #define DEBUGERR std::cerr << __LINE__ << " "; std::cerr -static struct tm* GetNightlyTime(std::string str, bool verbose, bool tomorrowtag) +struct tm* cmCTest::GetNightlyTime(std::string str, + bool verbose, + bool tomorrowtag) { struct tm* lctime; time_t tctime = time(0); @@ -137,7 +142,7 @@ std::string cmCTest::CurrentTime() strftime(current_time, 1000, "%a %b %d %H:%M:%S %Z %Y", t); } //std::cout << "Current_Time: " << current_time << std::endl; - return this->MakeXMLSafe(::CleanString(current_time)); + return cmCTest::MakeXMLSafe(::CleanString(current_time)); } static const char* cmCTestErrorMatches[] = { @@ -410,11 +415,15 @@ cmCTest::cmCTest() m_MaximumFailedTestResultSize = 200 * 1024; this->ScriptHandler = new cmCTestScriptHandler; + this->UpdateHandler = new cmCTestUpdateHandler; + this->ConfigureHandler = new cmCTestConfigureHandler; } cmCTest::~cmCTest() { delete this->ScriptHandler; + delete this->UpdateHandler; + delete this->ConfigureHandler; } int cmCTest::Initialize() @@ -492,7 +501,7 @@ int cmCTest::Initialize() //std::cout << "TestModel: " << m_TestModel << std::endl; if ( m_TestModel == cmCTest::NIGHTLY ) { - lctime = ::GetNightlyTime(m_DartConfiguration["NightlyStartTime"], + lctime = cmCTest::GetNightlyTime(m_DartConfiguration["NightlyStartTime"], m_Verbose, m_TomorrowTag); } @@ -710,440 +719,6 @@ std::string cmCTest::FindTheExecutable(const char *exe) return fullPath; } -int cmCTest::UpdateDirectory() -{ - int count = 0; - std::string::size_type cc, kk; - std::string cvsCommand = m_DartConfiguration["CVSCommand"]; - if ( cvsCommand.size() == 0 ) - { - std::cerr << "Cannot find CVSCommand key in the DartConfiguration.tcl" << std::endl; - return -1; - } - std::string cvsOptions = m_DartConfiguration["CVSUpdateOptions"]; - if ( cvsOptions.size() == 0 ) - { - std::cerr << "Cannot find CVSUpdateOptions key in the DartConfiguration.tcl" << std::endl; - return -1; - } - - std::string sourceDirectory = m_DartConfiguration["SourceDirectory"]; - if ( sourceDirectory.size() == 0 ) - { - std::cerr << "Cannot find SourceDirectory key in the DartConfiguration.tcl" << std::endl; - return -1; - } - - std::string extra_update_opts; - if ( m_TestModel == cmCTest::NIGHTLY ) - { - struct tm* t = ::GetNightlyTime(m_DartConfiguration["NightlyStartTime"], - m_Verbose, - m_TomorrowTag); - char current_time[1024]; - sprintf(current_time, "%04d-%02d-%02d %02d:%02d:%02d UTC", - t->tm_year + 1900, - t->tm_mon + 1, - t->tm_mday, - t->tm_hour, - t->tm_min, - t->tm_sec); - std::string today_update_date = current_time; - - extra_update_opts += "-D \"" + today_update_date +"\""; - //std::cout << "Update: " << extra_update_opts << std::endl; - } - - std::string command = cvsCommand + " -z3 update " + cvsOptions + - " " + extra_update_opts; - std::ofstream os; - if ( !this->OpenOutputFile(m_CurrentTag, "Update.xml", os) ) - { - std::cerr << "Cannot open log file" << std::endl; - } - std::string start_time = this->CurrentTime(); - double elapsed_time_start = cmSystemTools::GetTime(); - - std::string goutput; - int retVal = 0; - bool res = true; - std::ofstream ofs; - if ( !m_ShowOnly ) - { - res = cmSystemTools::RunSingleCommand(command.c_str(), &goutput, - &retVal, sourceDirectory.c_str(), - m_Verbose, 0 /*m_TimeOut*/); - if ( this->OpenOutputFile("Temporary", "LastUpdate.log", ofs) ) - { - ofs << goutput << std::endl;; - } - } - else - { - std::cout << "Update with command: " << command << std::endl; - } - - os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" - << "<Update mode=\"Client\" Generator=\"ctest-" << CMake_VERSION_FULL << "\">\n" - << "\t<Site>" << m_DartConfiguration["Site"] << "</Site>\n" - << "\t<BuildName>" << m_DartConfiguration["BuildName"] - << "</BuildName>\n" - << "\t<BuildStamp>" << m_CurrentTag << "-" - << this->GetTestModelString() << "</BuildStamp>" << std::endl; - os << "\t<StartDateTime>" << start_time << "</StartDateTime>\n" - << "\t<UpdateCommand>" << this->MakeXMLSafe(command) - << "</UpdateCommand>\n" - << "\t<UpdateReturnStatus>"; - int failed = 0; - if ( !res || retVal ) - { - os << "Update error: "; - os << this->MakeXMLSafe(goutput); - std::cerr << "Update with command: " << command << " failed" << std::endl; - failed = 1; - } - os << "</UpdateReturnStatus>" << std::endl; - if ( !failed ) - { - - std::vector<cmStdString> lines; - cmSystemTools::Split(goutput.c_str(), lines); - std::cout << "Updated; gathering version information" << std::endl; - cmsys::RegularExpression date_author("^date: +([^;]+); +author: +([^;]+); +state: +[^;]+;"); - cmsys::RegularExpression revision("^revision +([^ ]*) *$"); - cmsys::RegularExpression end_of_file("^=============================================================================$"); - cmsys::RegularExpression end_of_comment("^----------------------------$"); - std::string current_path = "<no-path>"; - bool first_file = true; - - cmCTest::AuthorsToUpdatesMap authors_files_map; - int num_updated = 0; - int num_modified = 0; - int num_conflicting = 0; - for ( cc= 0 ; cc < lines.size(); cc ++ ) - { - const char* line = lines[cc].c_str(); - char mod = line[0]; - if ( line[1] == ' ' && mod != '?' ) - { - if ( mod != 'M' && mod != 'C' ) - { - count ++; - } - const char* file = line + 2; - //std::cout << "Line" << cc << ": " << mod << " - " << file << std::endl; - std::string logcommand = cvsCommand + " -z3 log -N " + file; - //std::cout << "Do log: " << logcommand << std::endl; - std::string output; - res = cmSystemTools::RunSingleCommand(logcommand.c_str(), &output, - &retVal, sourceDirectory.c_str(), - m_Verbose, 0 /*m_TimeOut*/); - if ( ofs ) - { - ofs << output << std::endl; - } - if ( res && retVal == 0) - { - //std::cout << output << std::endl; - std::vector<cmStdString> ulines; - cmSystemTools::Split(output.c_str(), ulines); - std::string::size_type sline = 0; - std::string srevision1 = "Unknown"; - std::string sdate1 = "Unknown"; - std::string sauthor1 = "Unknown"; - std::string semail1 = "Unknown"; - std::string comment1 = ""; - std::string srevision2 = "Unknown"; - std::string sdate2 = "Unknown"; - std::string sauthor2 = "Unknown"; - std::string comment2 = ""; - std::string semail2 = "Unknown"; - bool have_first = false; - bool have_second = false; - for ( kk = 0; kk < ulines.size(); kk ++ ) - { - const char* clp = ulines[kk].c_str(); - if ( !have_second && !sline && revision.find(clp) ) - { - if ( !have_first ) - { - srevision1 = revision.match(1); - } - else - { - srevision2 = revision.match(1); - } - } - else if ( !have_second && !sline && date_author.find(clp) ) - { - sline = kk + 1; - if ( !have_first ) - { - sdate1 = date_author.match(1); - sauthor1 = date_author.match(2); - } - else - { - sdate2 = date_author.match(1); - sauthor2 = date_author.match(2); - } - } - else if ( sline && end_of_comment.find(clp) || end_of_file.find(clp)) - { - if ( !have_first ) - { - have_first = true; - } - else if ( !have_second ) - { - have_second = true; - } - sline = 0; - } - else if ( sline ) - { - if ( !have_first ) - { - comment1 += clp; - comment1 += "\n"; - } - else - { - comment2 += clp; - comment2 += "\n"; - } - } - } - if ( mod == 'M' ) - { - comment1 = "Locally modified file\n"; - } - if ( mod == 'C' ) - { - comment1 = "Conflict while updating\n"; - } - std::string path = cmSystemTools::GetFilenamePath(file); - std::string fname = cmSystemTools::GetFilenameName(file); - if ( path != current_path ) - { - if ( !first_file ) - { - os << "\t</Directory>" << std::endl; - } - else - { - first_file = false; - } - os << "\t<Directory>\n" - << "\t\t<Name>" << path << "</Name>" << std::endl; - } - if ( mod == 'C' ) - { - num_conflicting ++; - os << "\t<Conflicting>" << std::endl; - } - else if ( mod == 'M' ) - { - num_modified ++; - os << "\t<Modified>" << std::endl; - } - else - { - num_updated ++; - os << "\t<Updated>" << std::endl; - } - if ( srevision2 == "Unknown" ) - { - srevision2 = srevision1; - } - os << "\t\t<File Directory=\"" << path << "\">" << fname - << "</File>\n" - << "\t\t<Directory>" << path << "</Directory>\n" - << "\t\t<FullName>" << file << "</FullName>\n" - << "\t\t<CheckinDate>" << sdate1 << "</CheckinDate>\n" - << "\t\t<Author>" << sauthor1 << "</Author>\n" - << "\t\t<Email>" << semail1 << "</Email>\n" - << "\t\t<Log>" << this->MakeXMLSafe(comment1) << "</Log>\n" - << "\t\t<Revision>" << srevision1 << "</Revision>\n" - << "\t\t<PriorRevision>" << srevision2 << "</PriorRevision>" - << std::endl; - if ( srevision2 != srevision1 ) - { - os - << "\t\t<Revisions>\n" - << "\t\t\t<Revision>" << srevision1 << "</Revision>\n" - << "\t\t\t<PreviousRevision>" << srevision2 << "</PreviousRevision>\n" - << "\t\t\t<Author>" << sauthor1<< "</Author>\n" - << "\t\t\t<Date>" << sdate1 << "</Date>\n" - << "\t\t\t<Comment>" << this->MakeXMLSafe(comment1) << "</Comment>\n" - << "\t\t\t<Email>" << semail1 << "</Email>\n" - << "\t\t</Revisions>\n" - << "\t\t<Revisions>\n" - << "\t\t\t<Revision>" << srevision2 << "</Revision>\n" - << "\t\t\t<PreviousRevision>" << srevision2 << "</PreviousRevision>\n" - << "\t\t\t<Author>" << sauthor2<< "</Author>\n" - << "\t\t\t<Date>" << sdate2 << "</Date>\n" - << "\t\t\t<Comment>" << this->MakeXMLSafe(comment2) << "</Comment>\n" - << "\t\t\t<Email>" << semail2 << "</Email>\n" - << "\t\t</Revisions>" << std::endl; - } - if ( mod == 'C' ) - { - os << "\t</Conflicting>" << std::endl; - } - else if ( mod == 'M' ) - { - os << "\t</Modified>" << std::endl; - } - else - { - os << "\t</Updated>" << std::endl; - } - cmCTest::UpdateFiles *u = &authors_files_map[sauthor1]; - cmCTest::StringPair p; - p.first = path; - p.second = fname; - u->push_back(p); - - current_path = path; - } - } - } - if ( num_updated ) - { - std::cout << "Found " << num_updated << " updated files" << std::endl; - } - if ( num_modified ) - { - std::cout << "Found " << num_modified << " locally modified files" - << std::endl; - } - if ( num_conflicting ) - { - std::cout << "Found " << num_conflicting << " conflicting files" - << std::endl; - } - if ( !first_file ) - { - os << "\t</Directory>" << std::endl; - } - - cmCTest::AuthorsToUpdatesMap::iterator it; - for ( it = authors_files_map.begin(); - it != authors_files_map.end(); - it ++ ) - { - os << "\t<Author>\n" - << "\t\t<Name>" << it->first << "</Name>" << std::endl; - cmCTest::UpdateFiles *u = &(it->second); - for ( cc = 0; cc < u->size(); cc ++ ) - { - os << "\t\t<File Directory=\"" << (*u)[cc].first << "\">" - << (*u)[cc].second << "</File>" << std::endl; - } - os << "\t</Author>" << std::endl; - } - } - - //std::cout << "End" << std::endl; - std::string end_time = this->CurrentTime(); - os << "\t<EndDateTime>" << end_time << "</EndDateTime>\n" - << "<ElapsedMinutes>" << - static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0 - << "</ElapsedMinutes>" - << "</Update>" << std::endl; - - if ( ofs ) - { - ofs.close(); - } - - if (! res || retVal ) - { - std::cerr << "Error(s) when updating the project" << std::endl; - std::cerr << "Output: " << goutput << std::endl; - return -1; - } - return count; -} - -int cmCTest::ConfigureDirectory() -{ - std::cout << "Configure project" << std::endl; - std::string cCommand = m_DartConfiguration["ConfigureCommand"]; - if ( cCommand.size() == 0 ) - { - std::cerr << "Cannot find ConfigureCommand key in the DartConfiguration.tcl" - << std::endl; - return 1; - } - - std::string buildDirectory = m_DartConfiguration["BuildDirectory"]; - if ( buildDirectory.size() == 0 ) - { - std::cerr << "Cannot find BuildDirectory key in the DartConfiguration.tcl" << std::endl; - return 1; - } - - double elapsed_time_start = cmSystemTools::GetTime(); - std::string output; - int retVal = 0; - int res = 0; - if ( !m_ShowOnly ) - { - std::ofstream os; - if ( !this->OpenOutputFile(m_CurrentTag, "Configure.xml", os) ) - { - std::cerr << "Cannot open configure file" << std::endl; - return 1; - } - std::string start_time = this->CurrentTime(); - - std::ofstream ofs; - this->OpenOutputFile("Temporary", "LastConfigure.log", ofs); - res = this->RunMakeCommand(cCommand.c_str(), &output, - &retVal, buildDirectory.c_str(), - m_Verbose, 0, ofs); - - if ( ofs ) - { - ofs.close(); - } - - if ( os ) - { - this->StartXML(os); - os << "<Configure>\n" - << "\t<StartDateTime>" << start_time << "</StartDateTime>" << std::endl; - if ( res == cmsysProcess_State_Exited && retVal ) - { - os << retVal; - } - os << "<ConfigureCommand>" << cCommand.c_str() << "</ConfigureCommand>" << std::endl; - //std::cout << "End" << std::endl; - os << "<Log>" << this->MakeXMLSafe(output) << "</Log>" << std::endl; - std::string end_time = this->CurrentTime(); - os << "\t<ConfigureStatus>" << retVal << "</ConfigureStatus>\n" - << "\t<EndDateTime>" << end_time << "</EndDateTime>\n" - << "<ElapsedMinutes>" - << static_cast<int>( - (cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0 - << "</ElapsedMinutes>" - << "</Configure>" << std::endl; - this->EndXML(os); - } - } - else - { - std::cout << "Configure with command: " << cCommand << std::endl; - } - if (! res || retVal ) - { - std::cerr << "Error(s) when updating the project" << std::endl; - return 1; - } - return 0; -} int cmCTest::BuildDirectory() { @@ -3074,7 +2649,7 @@ int cmCTest::ProcessTests() } if ( m_Tests[UPDATE_TEST] || m_Tests[ALL_TEST] ) { - update_count = this->UpdateDirectory(); + update_count = this->UpdateHandler->UpdateDirectory(this); if ( update_count < 0 ) { res |= cmCTest::UPDATE_ERRORS; @@ -3086,7 +2661,7 @@ int cmCTest::ProcessTests() } if ( m_Tests[CONFIGURE_TEST] || m_Tests[ALL_TEST] ) { - if (this->ConfigureDirectory()) + if (this->ConfigureHandler->ConfigureDirectory(this)) { res |= cmCTest::CONFIGURE_ERRORS; } @@ -3885,6 +3460,8 @@ int cmCTest::Run(std::vector<std::string>const& args, std::string* output) { this->m_Verbose = true; this->ScriptHandler->SetVerbose(this->m_Verbose); + this->UpdateHandler->SetVerbose(this->m_Verbose); + this->ConfigureHandler->SetVerbose(this->m_Verbose); } if( arg.find("-N",0) == 0 || arg.find("--show-only",0) == 0 ) @@ -5060,3 +4637,19 @@ void cmCTest::ExpandTestsToRunInformation(int numTests) } std::cout << "\n"; } + +std::string cmCTest::GetDartConfiguration(const char *name) +{ + return m_DartConfiguration[name]; +} + + +std::string cmCTest::GetCurrentTag() +{ + return m_CurrentTag; +} + +bool cmCTest::GetShowOnly() +{ + return m_ShowOnly; +} diff --git a/Source/cmCTest.h b/Source/cmCTest.h index 845a6a7..07d6bfb 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -24,6 +24,8 @@ class cmMakefile; class cmCTestScriptHandler; +class cmCTestUpdateHandler; +class cmCTestConfigureHandler; class cmCTest { @@ -52,6 +54,18 @@ public: */ int ProcessTests(); + /* + * A utility function that returns the nightly time + */ + static struct tm* cmCTest::GetNightlyTime(std::string str, + bool verbose, + bool tomorrowtag); + + /* + * Is the tomorrow tag set? + */ + bool GetTomorrowTag() { return m_TomorrowTag; }; + /** * Try to build the project */ @@ -68,16 +82,6 @@ public: int CoverageDirectory(); /** - * Do revision control update of directory - */ - int UpdateDirectory(); - - /** - * Do configure the project - */ - int ConfigureDirectory(); - - /** * Do submit testing results */ int SubmitResults(); @@ -109,10 +113,13 @@ public: * Set the cmake test mode (experimental, nightly, continuous). */ void SetTestModel(int mode); - + int GetTestModel() { return m_TestModel; }; + std::string GetTestModelString(); static int GetTestModelFromString(const char* str); + std::string GetDartConfiguration(const char *name); + /** * constructor and destructor */ @@ -132,7 +139,6 @@ public: std::string m_ConfigType; bool m_Verbose; bool m_DartMode; - bool m_ShowOnly; bool m_ForceNewCTestProcess; @@ -155,14 +161,46 @@ public: int GenerateNotesFile(const char* files); + bool OpenOutputFile(const std::string& path, + const std::string& name, std::ofstream& stream); + static std::string MakeXMLSafe(const std::string&); + static std::string MakeURLSafe(const std::string&); + + /* + * return the current tag + */ + std::string GetCurrentTag(); + + ///! Get the current time as string + std::string CurrentTime(); + + ///! Should we only show what we would do? + bool GetShowOnly(); + + //! Start CTest XML output file + void StartXML(std::ostream& ostr); + + //! End CTest XML output file + void EndXML(std::ostream& ostr); + + //! Run command specialized for make and configure. Returns process status + // and retVal is return value or exception. + int RunMakeCommand(const char* command, std::string* output, + int* retVal, const char* dir, bool verbose, int timeout, + std::ofstream& ofs); + private: - // this is a helper class than handles running test scripts - cmCTestScriptHandler *ScriptHandler; + // these are helper classes + cmCTestScriptHandler *ScriptHandler; + cmCTestUpdateHandler *UpdateHandler; + cmCTestConfigureHandler *ConfigureHandler; void SetTestsToRunInformation(const char*); void ExpandTestsToRunInformation(int numPossibleTests); std::string TestsToRunString; + bool m_ShowOnly; + enum { FIRST_TEST = 0, UPDATE_TEST = 1, @@ -260,12 +298,6 @@ private: typedef std::vector<cmCTestTestProperties> tm_ListOfTests; - // Some structures needed for cvs update - struct StringPair : - public std::pair<std::string, std::string>{}; - struct UpdateFiles : public std::vector<StringPair>{}; - struct AuthorsToUpdatesMap : - public std::map<std::string, UpdateFiles>{}; struct cmCTestCoverage { @@ -381,17 +413,6 @@ private: std::vector<cmCTestBuildErrorWarning>, double elapsed_time); - bool OpenOutputFile(const std::string& path, - const std::string& name, std::ofstream& stream); - std::string MakeXMLSafe(const std::string&); - std::string MakeURLSafe(const std::string&); - - //! Run command specialized for make and configure. Returns process status - // and retVal is return value or exception. - int RunMakeCommand(const char* command, std::string* output, - int* retVal, const char* dir, bool verbose, int timeout, - std::ofstream& ofs); - //! Run command specialized for tests. Returns process status and retVal is // return value or exception. int RunTest(std::vector<const char*> args, std::string* output, int *retVal, @@ -400,12 +421,6 @@ private: std::string GenerateRegressionImages(const std::string& xml); const char* GetTestStatus(int status); - //! Start CTest XML output file - void StartXML(std::ostream& ostr); - - //! End CTest XML output file - void EndXML(std::ostream& ostr); - //! Create not from files. int GenerateDartNotesOutput(std::ostream& os, const tm_VectorOfStrings& files); @@ -422,9 +437,6 @@ private: ///! Find the running cmake void FindRunningCMake(const char* arg0); - ///! Get the current time as string - std::string CurrentTime(); - ///! Maximum size of testing string std::string::size_type m_MaximumPassedTestResultSize; std::string::size_type m_MaximumFailedTestResultSize; |