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.
This commit is contained in:
parent
c0e8c0f5aa
commit
d4d467dbd5
@ -80,6 +80,7 @@ IF(BUILD_TESTING)
|
|||||||
"Options passed to the cvs update command.")
|
"Options passed to the cvs update command.")
|
||||||
FIND_PROGRAM(SVNCOMMAND svn)
|
FIND_PROGRAM(SVNCOMMAND svn)
|
||||||
FIND_PROGRAM(BZRCOMMAND bzr)
|
FIND_PROGRAM(BZRCOMMAND bzr)
|
||||||
|
FIND_PROGRAM(HGCOMMAND hg)
|
||||||
|
|
||||||
IF(NOT UPDATE_TYPE)
|
IF(NOT UPDATE_TYPE)
|
||||||
IF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CVS")
|
IF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CVS")
|
||||||
@ -90,6 +91,10 @@ IF(BUILD_TESTING)
|
|||||||
ELSE(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.svn")
|
ELSE(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.svn")
|
||||||
IF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.bzr")
|
IF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.bzr")
|
||||||
SET(UPDATE_TYPE 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}/.bzr")
|
||||||
ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.svn")
|
ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.svn")
|
||||||
ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CVS")
|
ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CVS")
|
||||||
@ -114,6 +119,11 @@ IF(BUILD_TESTING)
|
|||||||
IF("${_update_type}" STREQUAL "bzr")
|
IF("${_update_type}" STREQUAL "bzr")
|
||||||
SET(UPDATE_COMMAND "${BZRCOMMAND}")
|
SET(UPDATE_COMMAND "${BZRCOMMAND}")
|
||||||
SET(UPDATE_OPTIONS "${BZR_UPDATE_OPTIONS}")
|
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 "bzr")
|
||||||
ENDIF("${_update_type}" STREQUAL "svn")
|
ENDIF("${_update_type}" STREQUAL "svn")
|
||||||
ENDIF("${_update_type}" STREQUAL "cvs")
|
ENDIF("${_update_type}" STREQUAL "cvs")
|
||||||
@ -193,6 +203,7 @@ IF(BUILD_TESTING)
|
|||||||
CVSCOMMAND
|
CVSCOMMAND
|
||||||
SVNCOMMAND
|
SVNCOMMAND
|
||||||
BZRCOMMAND
|
BZRCOMMAND
|
||||||
|
HGCOMMAND
|
||||||
CVS_UPDATE_OPTIONS
|
CVS_UPDATE_OPTIONS
|
||||||
SVN_UPDATE_OPTIONS
|
SVN_UPDATE_OPTIONS
|
||||||
BZR_UPDATE_OPTIONS
|
BZR_UPDATE_OPTIONS
|
||||||
|
@ -373,6 +373,8 @@ SET(CTEST_SRCS cmCTest.cxx
|
|||||||
CTest/cmCTestBZR.h
|
CTest/cmCTestBZR.h
|
||||||
CTest/cmCTestGIT.cxx
|
CTest/cmCTestGIT.cxx
|
||||||
CTest/cmCTestGIT.h
|
CTest/cmCTestGIT.h
|
||||||
|
CTest/cmCTestHG.cxx
|
||||||
|
CTest/cmCTestHG.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# Build CTestLib
|
# Build CTestLib
|
||||||
|
343
Source/CTest/cmCTestHG.cxx
Normal file
343
Source/CTest/cmCTestHG.cxx
Normal file
@ -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 <cmsys/RegularExpression.hxx>
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
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<char const*> 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<cmStdString> args = cmSystemTools::ParseArguments(opts.c_str());
|
||||||
|
for(std::vector<cmStdString>::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<Change> Changes;
|
||||||
|
Change CurChange;
|
||||||
|
std::vector<char> 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<std::string> 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<std::string> SplitCData()
|
||||||
|
{
|
||||||
|
std::vector<std::string> 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 =
|
||||||
|
"<logentry\n"
|
||||||
|
" revision=\"{node|short}\">\n"
|
||||||
|
" <author>{author|person}</author>\n"
|
||||||
|
" <email>{author|email}</email>\n"
|
||||||
|
" <date>{date|isodate}</date>\n"
|
||||||
|
" <msg>{desc}</msg>\n"
|
||||||
|
" <files>{files}</files>\n"
|
||||||
|
" <file_adds>{file_adds}</file_adds>\n"
|
||||||
|
" <file_dels>{file_dels}</file_dels>\n"
|
||||||
|
"</logentry>\n";
|
||||||
|
const char* hg_log[] = {hg, "log","--removed", "-r", range.c_str(),
|
||||||
|
"--template", hgXMLTemplate, 0};
|
||||||
|
|
||||||
|
LogParser out(this, "log-out> ");
|
||||||
|
out.Process("<?xml version=\"1.0\"?>\n"
|
||||||
|
"<log>\n");
|
||||||
|
OutputLogger err(this->Log, "log-err> ");
|
||||||
|
this->RunChild(hg_log, &out, &err);
|
||||||
|
out.Process("</log>\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);
|
||||||
|
}
|
52
Source/CTest/cmCTestHG.h
Normal file
52
Source/CTest/cmCTestHG.h
Normal file
@ -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
|
@ -56,6 +56,10 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler()
|
|||||||
"GITCommand", "CTEST_GIT_COMMAND");
|
"GITCommand", "CTEST_GIT_COMMAND");
|
||||||
this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
|
this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
|
||||||
"GITUpdateOptions", "CTEST_GIT_UPDATE_OPTIONS");
|
"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
|
const char* initialCheckoutCommand
|
||||||
= this->Makefile->GetDefinition("CTEST_CHECKOUT_COMMAND");
|
= this->Makefile->GetDefinition("CTEST_CHECKOUT_COMMAND");
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "cmCTestSVN.h"
|
#include "cmCTestSVN.h"
|
||||||
#include "cmCTestBZR.h"
|
#include "cmCTestBZR.h"
|
||||||
#include "cmCTestGIT.h"
|
#include "cmCTestGIT.h"
|
||||||
|
#include "cmCTestHG.h"
|
||||||
|
|
||||||
#include <cmsys/auto_ptr.hxx>
|
#include <cmsys/auto_ptr.hxx>
|
||||||
|
|
||||||
@ -54,7 +55,8 @@ static const char* cmCTestUpdateHandlerUpdateStrings[] =
|
|||||||
"CVS",
|
"CVS",
|
||||||
"SVN",
|
"SVN",
|
||||||
"BZR",
|
"BZR",
|
||||||
"GIT"
|
"GIT",
|
||||||
|
"HG"
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* cmCTestUpdateHandlerUpdateToString(int type)
|
static const char* cmCTestUpdateHandlerUpdateToString(int type)
|
||||||
@ -145,6 +147,10 @@ int cmCTestUpdateHandler::DetermineType(const char* cmd, const char* type)
|
|||||||
{
|
{
|
||||||
return cmCTestUpdateHandler::e_GIT;
|
return cmCTestUpdateHandler::e_GIT;
|
||||||
}
|
}
|
||||||
|
if ( stype.find("hg") != std::string::npos )
|
||||||
|
{
|
||||||
|
return cmCTestUpdateHandler::e_HG;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -167,6 +173,10 @@ int cmCTestUpdateHandler::DetermineType(const char* cmd, const char* type)
|
|||||||
{
|
{
|
||||||
return cmCTestUpdateHandler::e_GIT;
|
return cmCTestUpdateHandler::e_GIT;
|
||||||
}
|
}
|
||||||
|
if ( stype.find("hg") != std::string::npos )
|
||||||
|
{
|
||||||
|
return cmCTestUpdateHandler::e_HG;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return cmCTestUpdateHandler::e_UNKNOWN;
|
return cmCTestUpdateHandler::e_UNKNOWN;
|
||||||
}
|
}
|
||||||
@ -226,6 +236,7 @@ int cmCTestUpdateHandler::ProcessHandler()
|
|||||||
case e_SVN: vc.reset(new cmCTestSVN(this->CTest, ofs)); break;
|
case e_SVN: vc.reset(new cmCTestSVN(this->CTest, ofs)); break;
|
||||||
case e_BZR: vc.reset(new cmCTestBZR(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_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;
|
default: vc.reset(new cmCTestVC(this->CTest, ofs)); break;
|
||||||
}
|
}
|
||||||
vc->SetCommandLineTool(this->UpdateCommand);
|
vc->SetCommandLineTool(this->UpdateCommand);
|
||||||
@ -371,6 +382,12 @@ int cmCTestUpdateHandler::DetectVCS(const char* dir)
|
|||||||
{
|
{
|
||||||
return cmCTestUpdateHandler::e_GIT;
|
return cmCTestUpdateHandler::e_GIT;
|
||||||
}
|
}
|
||||||
|
sourceDirectory = dir;
|
||||||
|
sourceDirectory += "/.hg";
|
||||||
|
if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
|
||||||
|
{
|
||||||
|
return cmCTestUpdateHandler::e_HG;
|
||||||
|
}
|
||||||
return cmCTestUpdateHandler::e_UNKNOWN;
|
return cmCTestUpdateHandler::e_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,6 +417,7 @@ bool cmCTestUpdateHandler::SelectVCS()
|
|||||||
case e_SVN: key = "SVNCommand"; break;
|
case e_SVN: key = "SVNCommand"; break;
|
||||||
case e_BZR: key = "BZRCommand"; break;
|
case e_BZR: key = "BZRCommand"; break;
|
||||||
case e_GIT: key = "GITCommand"; break;
|
case e_GIT: key = "GITCommand"; break;
|
||||||
|
case e_HG: key = "HGCommand"; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
if (key)
|
if (key)
|
||||||
|
@ -48,6 +48,7 @@ public:
|
|||||||
e_SVN,
|
e_SVN,
|
||||||
e_BZR,
|
e_BZR,
|
||||||
e_GIT,
|
e_GIT,
|
||||||
|
e_HG,
|
||||||
e_LAST
|
e_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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}")
|
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateGIT_DIR}")
|
||||||
ENDIF(CTEST_TEST_UPDATE_GIT)
|
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)
|
ENDIF(CTEST_TEST_UPDATE)
|
||||||
|
|
||||||
IF (CTEST_TEST_CTEST AND CMAKE_RUN_LONG_TESTS)
|
IF (CTEST_TEST_CTEST AND CMAKE_RUN_LONG_TESTS)
|
||||||
|
163
Tests/CTestUpdateHG.cmake.in
Normal file
163
Tests/CTestUpdateHG.cmake.in
Normal file
@ -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 <testauthor@cmake.org>"
|
||||||
|
)
|
||||||
|
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 <testauthor@cmake.org>"
|
||||||
|
)
|
||||||
|
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 <testauthor@cmake.org>"
|
||||||
|
)
|
||||||
|
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)
|
Loading…
x
Reference in New Issue
Block a user