From d4d467dbd5c4a1590333eeeb3082ad46dc9698df Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 10 Jul 2009 11:08:05 -0400 Subject: ENH: Teach CTest to handle Mercurial repositories This creates cmCTestHG to drive CTest Update handling on hg-based work trees. Currently we always update to the head of the remote tracking branch (hg pull), so the nightly start time is ignored for Nightly builds. A later change will address this. See issue #7879. Patch from Emmanuel Christophe. I modified the patch slightly for code style, to finish up some parsing details, and to fix the test. --- Modules/CTest.cmake | 11 ++ Source/CMakeLists.txt | 2 + Source/CTest/cmCTestHG.cxx | 343 ++++++++++++++++++++++++++++++++++ Source/CTest/cmCTestHG.h | 52 ++++++ Source/CTest/cmCTestUpdateCommand.cxx | 4 + Source/CTest/cmCTestUpdateHandler.cxx | 20 +- Source/CTest/cmCTestUpdateHandler.h | 1 + Tests/CMakeLists.txt | 18 ++ Tests/CTestUpdateHG.cmake.in | 163 ++++++++++++++++ 9 files changed, 613 insertions(+), 1 deletion(-) create mode 100644 Source/CTest/cmCTestHG.cxx create mode 100644 Source/CTest/cmCTestHG.h create mode 100644 Tests/CTestUpdateHG.cmake.in diff --git a/Modules/CTest.cmake b/Modules/CTest.cmake index 19f872a..b3871db 100644 --- a/Modules/CTest.cmake +++ b/Modules/CTest.cmake @@ -80,6 +80,7 @@ IF(BUILD_TESTING) "Options passed to the cvs update command.") FIND_PROGRAM(SVNCOMMAND svn) FIND_PROGRAM(BZRCOMMAND bzr) + FIND_PROGRAM(HGCOMMAND hg) IF(NOT UPDATE_TYPE) IF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CVS") @@ -90,6 +91,10 @@ IF(BUILD_TESTING) ELSE(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.svn") IF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.bzr") SET(UPDATE_TYPE bzr) + ELSE(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.bzr") + IF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.hg") + SET(UPDATE_TYPE hg) + ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.hg") ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.bzr") ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.svn") ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CVS") @@ -114,6 +119,11 @@ IF(BUILD_TESTING) IF("${_update_type}" STREQUAL "bzr") SET(UPDATE_COMMAND "${BZRCOMMAND}") SET(UPDATE_OPTIONS "${BZR_UPDATE_OPTIONS}") + ELSE("${_update_type}" STREQUAL "bzr") + IF("${_update_type}" STREQUAL "hg") + SET(UPDATE_COMMAND "${HGCOMMAND}") + SET(UPDATE_OPTIONS "${HG_UPDATE_OPTIONS}") + ENDIF("${_update_type}" STREQUAL "hg") ENDIF("${_update_type}" STREQUAL "bzr") ENDIF("${_update_type}" STREQUAL "svn") ENDIF("${_update_type}" STREQUAL "cvs") @@ -193,6 +203,7 @@ IF(BUILD_TESTING) CVSCOMMAND SVNCOMMAND BZRCOMMAND + HGCOMMAND CVS_UPDATE_OPTIONS SVN_UPDATE_OPTIONS BZR_UPDATE_OPTIONS diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 33c0dc4..090f840 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -373,6 +373,8 @@ SET(CTEST_SRCS cmCTest.cxx CTest/cmCTestBZR.h CTest/cmCTestGIT.cxx CTest/cmCTestGIT.h + CTest/cmCTestHG.cxx + CTest/cmCTestHG.h ) # Build CTestLib diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx new file mode 100644 index 0000000..268fe77 --- /dev/null +++ b/Source/CTest/cmCTestHG.cxx @@ -0,0 +1,343 @@ +/*========================================================================= + + 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. + +=========================================================================*/ +#include "cmCTestHG.h" + +#include "cmCTest.h" +#include "cmSystemTools.h" +#include "cmXMLParser.h" + +#include + +//---------------------------------------------------------------------------- +cmCTestHG::cmCTestHG(cmCTest* ct, std::ostream& log): + cmCTestGlobalVC(ct, log) +{ + this->PriorRev = this->Unknown; +} + +//---------------------------------------------------------------------------- +cmCTestHG::~cmCTestHG() +{ +} + +//---------------------------------------------------------------------------- +class cmCTestHG::IdentifyParser: public cmCTestVC::LineParser +{ +public: + IdentifyParser(cmCTestHG* hg, const char* prefix, + std::string& rev): Rev(rev) + { + this->SetLog(&hg->Log, prefix); + this->RegexIdentify.compile("^([0-9a-f]+)"); + } +private: + std::string& Rev; + cmsys::RegularExpression RegexIdentify; + + bool ProcessLine() + { + if(this->RegexIdentify.find(this->Line)) + { + this->Rev = this->RegexIdentify.match(1); + return false; + } + return true; + } +}; + +//---------------------------------------------------------------------------- +class cmCTestHG::StatusParser: public cmCTestVC::LineParser +{ +public: + StatusParser(cmCTestHG* hg, const char* prefix): HG(hg) + { + this->SetLog(&hg->Log, prefix); + this->RegexStatus.compile("([MARC!?I]) (.*)"); + } + +private: + cmCTestHG* HG; + cmsys::RegularExpression RegexStatus; + + bool ProcessLine() + { + if(this->RegexStatus.find(this->Line)) + { + this->DoPath(this->RegexStatus.match(1)[0], + this->RegexStatus.match(2)); + } + return true; + } + + void DoPath(char status, std::string const& path) + { + if(path.empty()) return; + + // See "hg help status". Note that there is no 'conflict' status. + switch(status) + { + case 'M': case 'A': case '!': case 'R': + this->HG->DoModification(PathModified, path); + break; + case 'I': case '?': case 'C': case ' ': default: + break; + } + } +}; + +//---------------------------------------------------------------------------- +std::string cmCTestHG::GetWorkingRevision() +{ + // Run plumbing "hg identify" to get work tree revision. + const char* hg = this->CommandLineTool.c_str(); + const char* hg_identify[] = {hg, "identify","-i", 0}; + std::string rev; + IdentifyParser out(this, "rev-out> ", rev); + OutputLogger err(this->Log, "rev-err> "); + this->RunChild(hg_identify, &out, &err); + return rev; +} + +//---------------------------------------------------------------------------- +void cmCTestHG::NoteOldRevision() +{ + this->OldRevision = this->GetWorkingRevision(); + cmCTestLog(this->CTest, HANDLER_OUTPUT, " Old revision of repository is: " + << this->OldRevision << "\n"); + this->PriorRev.Rev = this->OldRevision; +} + +//---------------------------------------------------------------------------- +void cmCTestHG::NoteNewRevision() +{ + this->NewRevision = this->GetWorkingRevision(); + cmCTestLog(this->CTest, HANDLER_OUTPUT, " New revision of repository is: " + << this->NewRevision << "\n"); +} + +//---------------------------------------------------------------------------- +bool cmCTestHG::UpdateImpl() +{ + // Use "hg pull" followed by "hg update" to update the working tree. + { + const char* hg = this->CommandLineTool.c_str(); + const char* hg_pull[] = {hg, "pull","-v", 0}; + OutputLogger out(this->Log, "pull-out> "); + OutputLogger err(this->Log, "pull-err> "); + this->RunChild(&hg_pull[0], &out, &err); + } + + // TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY) + + std::vector hg_update; + hg_update.push_back(this->CommandLineTool.c_str()); + hg_update.push_back("update"); + hg_update.push_back("-v"); + + // Add user-specified update options. + std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions"); + if(opts.empty()) + { + opts = this->CTest->GetCTestConfiguration("HGUpdateOptions"); + } + std::vector args = cmSystemTools::ParseArguments(opts.c_str()); + for(std::vector::const_iterator ai = args.begin(); + ai != args.end(); ++ai) + { + hg_update.push_back(ai->c_str()); + } + + // Sentinel argument. + hg_update.push_back(0); + + OutputLogger out(this->Log, "update-out> "); + OutputLogger err(this->Log, "update-err> "); + return this->RunUpdateCommand(&hg_update[0], &out, &err); +} + +//---------------------------------------------------------------------------- +class cmCTestHG::LogParser: public cmCTestVC::OutputLogger, + private cmXMLParser +{ +public: + LogParser(cmCTestHG* hg, const char* prefix): + OutputLogger(hg->Log, prefix), HG(hg) { this->InitializeParser(); } + ~LogParser() { this->CleanupParser(); } +private: + cmCTestHG* HG; + + typedef cmCTestHG::Revision Revision; + typedef cmCTestHG::Change Change; + Revision Rev; + std::vector Changes; + Change CurChange; + std::vector CData; + + virtual bool ProcessChunk(const char* data, int length) + { + this->OutputLogger::ProcessChunk(data, length); + this->ParseChunk(data, length); + return true; + } + + virtual void StartElement(const char* name, const char** atts) + { + this->CData.clear(); + if(strcmp(name, "logentry") == 0) + { + this->Rev = Revision(); + if(const char* rev = this->FindAttribute(atts, "revision")) + { + this->Rev.Rev = rev; + } + this->Changes.clear(); + } + } + + virtual void CharacterDataHandler(const char* data, int length) + { + this->CData.insert(this->CData.end(), data, data+length); + } + + virtual void EndElement(const char* name) + { + if(strcmp(name, "logentry") == 0) + { + this->HG->DoRevision(this->Rev, this->Changes); + } + else if(strcmp(name, "author") == 0 && !this->CData.empty()) + { + this->Rev.Author.assign(&this->CData[0], this->CData.size()); + } + else if ( strcmp(name, "email") == 0 && !this->CData.empty()) + { + // this->Rev.Email.assign(&this->CData[0], this->CData.size()); + } + else if(strcmp(name, "date") == 0 && !this->CData.empty()) + { + this->Rev.Date.assign(&this->CData[0], this->CData.size()); + } + else if(strcmp(name, "msg") == 0 && !this->CData.empty()) + { + this->Rev.Log.assign(&this->CData[0], this->CData.size()); + } + else if(strcmp(name, "files") == 0 && !this->CData.empty()) + { + std::vector paths = this->SplitCData(); + for(unsigned int i = 0; i < paths.size(); ++i) + { + // Updated by default, will be modified using file_adds and + // file_dels. + this->CurChange = Change('U'); + this->CurChange.Path = paths[i]; + this->Changes.push_back(this->CurChange); + } + } + else if(strcmp(name, "file_adds") == 0 && !this->CData.empty()) + { + std::string added_paths(this->CData.begin(), this->CData.end()); + for(unsigned int i = 0; i < this->Changes.size(); ++i) + { + if(added_paths.find(this->Changes[i].Path) != std::string::npos) + { + this->Changes[i].Action = 'A'; + } + } + } + else if(strcmp(name, "file_dels") == 0 && !this->CData.empty()) + { + std::string added_paths(this->CData.begin(), this->CData.end()); + for(unsigned int i = 0; i < this->Changes.size(); ++i) + { + if(added_paths.find(this->Changes[i].Path) != std::string::npos) + { + this->Changes[i].Action = 'D'; + } + } + } + this->CData.clear(); + } + + std::vector SplitCData() + { + std::vector output; + std::string currPath; + for(unsigned int i=0; i < this->CData.size(); ++i) + { + if(this->CData[i] != ' ') + { + currPath.push_back(this->CData[i]); + } + else + { + output.push_back(currPath); + currPath.erase(); + } + } + output.push_back(currPath); + return output; + } + + virtual void ReportError(int, int, const char* msg) + { + this->HG->Log << "Error parsing hg log xml: " << msg << "\n"; + } +}; + +//---------------------------------------------------------------------------- +void cmCTestHG::LoadRevisions() +{ + // Use 'hg log' to get revisions in a xml format. + // + // TODO: This should use plumbing or python code to be more precise. + // The "list of strings" templates like {files} will not work when + // the project has spaces in the path. Also, they may not have + // proper XML escapes. + std::string range = this->OldRevision + ":" + this->NewRevision; + const char* hg = this->CommandLineTool.c_str(); + const char* hgXMLTemplate = + "\n" + " {author|person}\n" + " {author|email}\n" + " {date|isodate}\n" + " {desc}\n" + " {files}\n" + " {file_adds}\n" + " {file_dels}\n" + "\n"; + const char* hg_log[] = {hg, "log","--removed", "-r", range.c_str(), + "--template", hgXMLTemplate, 0}; + + LogParser out(this, "log-out> "); + out.Process("\n" + "\n"); + OutputLogger err(this->Log, "log-err> "); + this->RunChild(hg_log, &out, &err); + out.Process("\n"); +} + +//---------------------------------------------------------------------------- +void cmCTestHG::LoadModifications() +{ + // Use 'hg status' to get modified files. + const char* hg = this->CommandLineTool.c_str(); + const char* hg_status[] = {hg, "status", 0}; + StatusParser out(this, "status-out> "); + OutputLogger err(this->Log, "status-err> "); + this->RunChild(hg_status, &out, &err); +} diff --git a/Source/CTest/cmCTestHG.h b/Source/CTest/cmCTestHG.h new file mode 100644 index 0000000..aafa0e1 --- /dev/null +++ b/Source/CTest/cmCTestHG.h @@ -0,0 +1,52 @@ +/*========================================================================= + + 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 cmCTestHG_h +#define cmCTestHG_h + +#include "cmCTestGlobalVC.h" + +/** \class cmCTestHG + * \brief Interaction with Mercurial command-line tool + * + */ +class cmCTestHG: public cmCTestGlobalVC +{ +public: + /** Construct with a CTest instance and update log stream. */ + cmCTestHG(cmCTest* ctest, std::ostream& log); + + virtual ~cmCTestHG(); + +private: + std::string GetWorkingRevision(); + virtual void NoteOldRevision(); + virtual void NoteNewRevision(); + virtual bool UpdateImpl(); + + void LoadRevisions(); + void LoadModifications(); + + // Parsing helper classes. + class IdentifyParser; + class StatusParser; + class LogParser; + friend class IdentifyParser; + friend class StatusParser; + friend class LogParser; +}; + +#endif diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx index 73c1f40..3dc5cf6 100644 --- a/Source/CTest/cmCTestUpdateCommand.cxx +++ b/Source/CTest/cmCTestUpdateCommand.cxx @@ -56,6 +56,10 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler() "GITCommand", "CTEST_GIT_COMMAND"); this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile, "GITUpdateOptions", "CTEST_GIT_UPDATE_OPTIONS"); + this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile, + "HGCommand", "CTEST_HG_COMMAND"); + this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile, + "HGUpdateOptions", "CTEST_HG_UPDATE_OPTIONS"); const char* initialCheckoutCommand = this->Makefile->GetDefinition("CTEST_CHECKOUT_COMMAND"); diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx index d3930d7..749daa5 100644 --- a/Source/CTest/cmCTestUpdateHandler.cxx +++ b/Source/CTest/cmCTestUpdateHandler.cxx @@ -32,6 +32,7 @@ #include "cmCTestSVN.h" #include "cmCTestBZR.h" #include "cmCTestGIT.h" +#include "cmCTestHG.h" #include @@ -54,7 +55,8 @@ static const char* cmCTestUpdateHandlerUpdateStrings[] = "CVS", "SVN", "BZR", - "GIT" + "GIT", + "HG" }; static const char* cmCTestUpdateHandlerUpdateToString(int type) @@ -145,6 +147,10 @@ int cmCTestUpdateHandler::DetermineType(const char* cmd, const char* type) { return cmCTestUpdateHandler::e_GIT; } + if ( stype.find("hg") != std::string::npos ) + { + return cmCTestUpdateHandler::e_HG; + } } else { @@ -167,6 +173,10 @@ int cmCTestUpdateHandler::DetermineType(const char* cmd, const char* type) { return cmCTestUpdateHandler::e_GIT; } + if ( stype.find("hg") != std::string::npos ) + { + return cmCTestUpdateHandler::e_HG; + } } return cmCTestUpdateHandler::e_UNKNOWN; } @@ -226,6 +236,7 @@ int cmCTestUpdateHandler::ProcessHandler() case e_SVN: vc.reset(new cmCTestSVN(this->CTest, ofs)); break; case e_BZR: vc.reset(new cmCTestBZR(this->CTest, ofs)); break; case e_GIT: vc.reset(new cmCTestGIT(this->CTest, ofs)); break; + case e_HG: vc.reset(new cmCTestHG(this->CTest, ofs)); break; default: vc.reset(new cmCTestVC(this->CTest, ofs)); break; } vc->SetCommandLineTool(this->UpdateCommand); @@ -371,6 +382,12 @@ int cmCTestUpdateHandler::DetectVCS(const char* dir) { return cmCTestUpdateHandler::e_GIT; } + sourceDirectory = dir; + sourceDirectory += "/.hg"; + if ( cmSystemTools::FileExists(sourceDirectory.c_str()) ) + { + return cmCTestUpdateHandler::e_HG; + } return cmCTestUpdateHandler::e_UNKNOWN; } @@ -400,6 +417,7 @@ bool cmCTestUpdateHandler::SelectVCS() case e_SVN: key = "SVNCommand"; break; case e_BZR: key = "BZRCommand"; break; case e_GIT: key = "GITCommand"; break; + case e_HG: key = "HGCommand"; break; default: break; } if (key) diff --git a/Source/CTest/cmCTestUpdateHandler.h b/Source/CTest/cmCTestUpdateHandler.h index 139ceed..f1e76f8 100644 --- a/Source/CTest/cmCTestUpdateHandler.h +++ b/Source/CTest/cmCTestUpdateHandler.h @@ -48,6 +48,7 @@ public: e_SVN, e_BZR, e_GIT, + e_HG, e_LAST }; diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 69c731d..cc0013b 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -976,6 +976,24 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=CVS -P ${CMake_SOURCE_DIR}/Utilities/Rel LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateGIT_DIR}") ENDIF(CTEST_TEST_UPDATE_GIT) + # Test CTest Update with HG + FIND_PROGRAM(HG_EXECUTABLE NAMES hg) + MARK_AS_ADVANCED(HG_EXECUTABLE) + SET(CTEST_TEST_UPDATE_HG 0) + IF(HG_EXECUTABLE) + IF(NOT "${CVS_EXECUTABLE}" MATCHES "cygwin" OR UNIX) + SET(CTEST_TEST_UPDATE_HG 1) + ENDIF(NOT "${CVS_EXECUTABLE}" MATCHES "cygwin" OR UNIX) + ENDIF(HG_EXECUTABLE) + IF(CTEST_TEST_UPDATE_HG) + SET(CTestUpdateHG_DIR "CTest UpdateHG") + CONFIGURE_FILE("${CMake_SOURCE_DIR}/Tests/CTestUpdateHG.cmake.in" + "${CMake_BINARY_DIR}/Tests/CTestUpdateHG.cmake" @ONLY) + ADD_TEST(CTest.UpdateHG ${CMAKE_CMAKE_COMMAND} + -P "${CMake_BINARY_DIR}/Tests/CTestUpdateHG.cmake" + ) + LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateHG_DIR}") + ENDIF(CTEST_TEST_UPDATE_HG) ENDIF(CTEST_TEST_UPDATE) IF (CTEST_TEST_CTEST AND CMAKE_RUN_LONG_TESTS) diff --git a/Tests/CTestUpdateHG.cmake.in b/Tests/CTestUpdateHG.cmake.in new file mode 100644 index 0000000..f2e5f83 --- /dev/null +++ b/Tests/CTestUpdateHG.cmake.in @@ -0,0 +1,163 @@ +# This script drives creation of a Mercurial repository and checks +# that CTest can update from it. + +#----------------------------------------------------------------------------- +# Test in a directory next to this script. +get_filename_component(TOP "${CMAKE_CURRENT_LIST_FILE}" PATH) +set(TOP "${TOP}/@CTestUpdateHG_DIR@") + +# Include code common to all update tests. +include("@CMAKE_CURRENT_SOURCE_DIR@/CTestUpdateCommon.cmake") + +#----------------------------------------------------------------------------- +# Report hg tools in use. +message("Using HG tools:") +set(HG "@HG_EXECUTABLE@") +message(" hg = ${HG}") + +#----------------------------------------------------------------------------- +# Initialize the testing directory. +message("Creating test directory...") +init_testing() + +#----------------------------------------------------------------------------- +# Create the repository. +message("Creating repository...") +file(MAKE_DIRECTORY ${TOP}/repo.hg) +run_child( + WORKING_DIRECTORY ${TOP}/repo.hg + COMMAND ${HG} init + ) +set(REPO file://${TOP}/repo.hg) + +#----------------------------------------------------------------------------- +# Import initial content into the repository. +message("Importing content...") +create_content(import) + +# Import the content into the repository. +run_child(WORKING_DIRECTORY ${TOP}/import + COMMAND ${HG} init + ) +run_child(WORKING_DIRECTORY ${TOP}/import + COMMAND ${HG} add . + ) +run_child(WORKING_DIRECTORY ${TOP}/import + COMMAND ${HG} commit -m "Initial content" + -u "Test Author " + ) +run_child(WORKING_DIRECTORY ${TOP}/import + COMMAND ${HG} push "${REPO}" + ) + +#----------------------------------------------------------------------------- +# Create a working tree. +message("Checking out first revision...") +run_child( + WORKING_DIRECTORY ${TOP} + COMMAND ${HG} clone ${REPO} user-source + ) + +#----------------------------------------------------------------------------- +# Make changes in the working tree. +message("Changing content...") +update_content(user-source files_added files_removed dirs_added) +if(dirs_added) + run_child( + WORKING_DIRECTORY ${TOP}/user-source + COMMAND ${HG} add ${dirs_added} + ) +endif(dirs_added) +run_child( + WORKING_DIRECTORY ${TOP}/user-source + COMMAND ${HG} add ${files_added} + ) +run_child( + WORKING_DIRECTORY ${TOP}/user-source + COMMAND ${HG} rm ${files_removed} + ) +run_child( + WORKING_DIRECTORY ${TOP}/user-source + COMMAND ${HG} add + ) + +#----------------------------------------------------------------------------- +# Commit the changes to the repository. +message("Committing revision 2...") +run_child( + WORKING_DIRECTORY ${TOP}/user-source + COMMAND ${HG} commit -m "Changed content" + -u "Test Author " + ) +run_child( + WORKING_DIRECTORY ${TOP}/user-source + COMMAND ${HG} push + ) + +#----------------------------------------------------------------------------- +# Make changes in the working tree. +message("Changing content again...") +change_content(user-source) +run_child( + WORKING_DIRECTORY ${TOP}/user-source + COMMAND ${HG} add + ) + +#----------------------------------------------------------------------------- +# Commit the changes to the repository. +message("Committing revision 3...") +run_child( + WORKING_DIRECTORY ${TOP}/user-source + COMMAND ${HG} commit -m "Changed content again" + -u "Test Author " + ) +run_child( + WORKING_DIRECTORY ${TOP}/user-source + COMMAND ${HG} push + ) + +#----------------------------------------------------------------------------- +# Go back to before the changes so we can test updating. +message("Backing up to first revision...") +run_child( + WORKING_DIRECTORY ${TOP}/user-source + COMMAND ${HG} update -C -r 0 + ) + +# Create a modified file. +modify_content(user-source) + +#----------------------------------------------------------------------------- +# Test updating the user work directory with the command-line interface. +message("Running CTest Dashboard Command Line...") + +# Create the user build tree. +create_build_tree(user-source user-binary) +file(APPEND ${TOP}/user-binary/CTestConfiguration.ini + "# HG command configuration +UpdateCommand: ${HG} +") + +# Run the dashboard command line interface. +run_dashboard_command_line(user-binary) + +#----------------------------------------------------------------------------- +# Test initial checkout and update with a dashboard script. +message("Running CTest Dashboard Script...") + +create_dashboard_script(dashboard.cmake + "# hg command configuration +set(CTEST_HG_COMMAND \"${HG}\") +set(CTEST_HG_UPDATE_OPTIONS) +execute_process( + WORKING_DIRECTORY \"${TOP}\" + COMMAND \"${HG}\" clone \"${REPO}\" dash-source + ) +execute_process( + WORKING_DIRECTORY \"${TOP}/dash-source\" + COMMAND \"${HG}\" update -C -r 0 + ) +") + +# Run the dashboard script with CTest. +run_dashboard_script(dashboard.cmake) -- cgit v0.12