cmCTestSVN: Use the SVNInfo structure

- Suppress the URL, Root, Base fields from the cmCTestSVN class
- Update the code to use RootInfo instead
- LoadInfo(), GuessBase(), and a new LoadRevision() functions work on a given SVNInfo
- Use the implementation from the base class for LocalPath(), correct path is built by SVNInfo::BuildLocalPath() instead
This commit is contained in:
Xavier Besseron 2012-09-03 10:50:07 +02:00 committed by Brad King
parent fb6d513692
commit 41f0f83542
2 changed files with 90 additions and 75 deletions

View File

@ -49,8 +49,11 @@ void cmCTestSVN::CleanupImpl()
class cmCTestSVN::InfoParser: public cmCTestVC::LineParser class cmCTestSVN::InfoParser: public cmCTestVC::LineParser
{ {
public: public:
InfoParser(cmCTestSVN* svn, const char* prefix, std::string& rev): InfoParser(cmCTestSVN* svn,
SVN(svn), Rev(rev) const char* prefix,
std::string& rev,
SVNInfo& svninfo):
Rev(rev), SVNRepo(svninfo)
{ {
this->SetLog(&svn->Log, prefix); this->SetLog(&svn->Log, prefix);
this->RegexRev.compile("^Revision: ([0-9]+)"); this->RegexRev.compile("^Revision: ([0-9]+)");
@ -58,8 +61,8 @@ public:
this->RegexRoot.compile("^Repository Root: +([^ ]+) *$"); this->RegexRoot.compile("^Repository Root: +([^ ]+) *$");
} }
private: private:
cmCTestSVN* SVN;
std::string& Rev; std::string& Rev;
cmCTestSVN::SVNInfo& SVNRepo;
cmsys::RegularExpression RegexRev; cmsys::RegularExpression RegexRev;
cmsys::RegularExpression RegexURL; cmsys::RegularExpression RegexURL;
cmsys::RegularExpression RegexRoot; cmsys::RegularExpression RegexRoot;
@ -71,11 +74,11 @@ private:
} }
else if(this->RegexURL.find(this->Line)) else if(this->RegexURL.find(this->Line))
{ {
this->SVN->URL = this->RegexURL.match(1); this->SVNRepo.URL = this->RegexURL.match(1);
} }
else if(this->RegexRoot.find(this->Line)) else if(this->RegexRoot.find(this->Line))
{ {
this->SVN->Root = this->RegexRoot.match(1); this->SVNRepo.Root = this->RegexRoot.match(1);
} }
return true; return true;
} }
@ -100,13 +103,13 @@ static bool cmCTestSVNPathStarts(std::string const& p1, std::string const& p2)
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
std::string cmCTestSVN::LoadInfo() std::string cmCTestSVN::LoadInfo(SVNInfo& svninfo)
{ {
// Run "svn info" to get the repository info from the work tree. // Run "svn info" to get the repository info from the work tree.
const char* svn = this->CommandLineTool.c_str(); const char* svn = this->CommandLineTool.c_str();
const char* svn_info[] = {svn, "info", 0}; const char* svn_info[] = {svn, "info", svninfo.LocalPath.c_str(), 0};
std::string rev; std::string rev;
InfoParser out(this, "info-out> ", rev); InfoParser out(this, "info-out> ", rev, svninfo);
OutputLogger err(this->Log, "info-err> "); OutputLogger err(this->Log, "info-err> ");
this->RunChild(svn_info, &out, &err); this->RunChild(svn_info, &out, &err);
return rev; return rev;
@ -118,55 +121,78 @@ void cmCTestSVN::NoteOldRevision()
// Info for root repository // Info for root repository
this->Repositories.push_back( SVNInfo("") ); this->Repositories.push_back( SVNInfo("") );
this->RootInfo = &(this->Repositories.back()); this->RootInfo = &(this->Repositories.back());
this->OldRevision = this->LoadInfo();
this->Log << "Revision before update: " << this->OldRevision << "\n"; // Get info for the root repositiry
cmCTestLog(this->CTest, HANDLER_OUTPUT, " Old revision of repository is: " SVNInfo& svninfo = *RootInfo;
<< this->OldRevision << "\n"); svninfo.OldRevision = this->LoadInfo(svninfo);
this->Log << "Revision for repository '" << svninfo.LocalPath
<< "' before update: " << svninfo.OldRevision << "\n";
cmCTestLog(this->CTest, HANDLER_OUTPUT,
" Old revision of external repository '"
<< svninfo.LocalPath << "' is: "
<< svninfo.OldRevision << "\n");
// Set the global old revision to the one of the root
this->OldRevision = this->RootInfo->OldRevision;
this->PriorRev.Rev = this->OldRevision; this->PriorRev.Rev = this->OldRevision;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmCTestSVN::NoteNewRevision() void cmCTestSVN::NoteNewRevision()
{ {
this->NewRevision = this->LoadInfo(); // Get info for the root repository
this->Log << "Revision after update: " << this->NewRevision << "\n"; SVNInfo& svninfo = *RootInfo;
cmCTestLog(this->CTest, HANDLER_OUTPUT, " New revision of repository is: " svninfo.NewRevision = this->LoadInfo(svninfo);
<< this->NewRevision << "\n"); this->Log << "Revision for repository '" << svninfo.LocalPath
<< "' after update: " << svninfo.NewRevision << "\n";
cmCTestLog(this->CTest, HANDLER_OUTPUT,
" New revision of external repository '"
<< svninfo.LocalPath << "' is: "
<< svninfo.NewRevision << "\n");
// this->Root = ""; // uncomment to test GuessBase // svninfo.Root = ""; // uncomment to test GuessBase
this->Log << "URL = " << this->URL << "\n"; this->Log << "Repository '" << svninfo.LocalPath
this->Log << "Root = " << this->Root << "\n"; << "' URL = " << svninfo.URL << "\n";
this->Log << "Repository '" << svninfo.LocalPath
<< "' Root = " << svninfo.Root << "\n";
// Compute the base path the working tree has checked out under // Compute the base path the working tree has checked out under
// the repository root. // the repository root.
if(!this->Root.empty() && cmCTestSVNPathStarts(this->URL, this->Root)) if(!svninfo.Root.empty()
{ && cmCTestSVNPathStarts(svninfo.URL, svninfo.Root))
this->Base = cmCTest::DecodeURL(this->URL.substr(this->Root.size())); {
this->Base += "/"; svninfo.Base = cmCTest::DecodeURL(
} svninfo.URL.substr(svninfo.Root.size()));
this->Log << "Base = " << this->Base << "\n"; svninfo.Base += "/";
}
this->Log << "Repository '" << svninfo.LocalPath
<< "' Base = " << svninfo.Base << "\n";
// Set the global new revision to the one of the root
this->NewRevision = this->RootInfo->NewRevision;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmCTestSVN::GuessBase(std::vector<Change> const& changes) void cmCTestSVN::GuessBase(SVNInfo& svninfo,
std::vector<Change> const& changes)
{ {
// Subversion did not give us a good repository root so we need to // Subversion did not give us a good repository root so we need to
// guess the base path from the URL and the paths in a revision with // guess the base path from the URL and the paths in a revision with
// changes under it. // changes under it.
// Consider each possible URL suffix from longest to shortest. // Consider each possible URL suffix from longest to shortest.
for(std::string::size_type slash = this->URL.find('/'); for(std::string::size_type slash = svninfo.URL.find('/');
this->Base.empty() && slash != std::string::npos; svninfo.Base.empty() && slash != std::string::npos;
slash = this->URL.find('/', slash+1)) slash = svninfo.URL.find('/', slash+1))
{ {
// If the URL suffix is a prefix of at least one path then it is the base. // If the URL suffix is a prefix of at least one path then it is the base.
std::string base = cmCTest::DecodeURL(this->URL.substr(slash)); std::string base = cmCTest::DecodeURL(svninfo.URL.substr(slash));
for(std::vector<Change>::const_iterator ci = changes.begin(); for(std::vector<Change>::const_iterator ci = changes.begin();
this->Base.empty() && ci != changes.end(); ++ci) svninfo.Base.empty() && ci != changes.end(); ++ci)
{ {
if(cmCTestSVNPathStarts(ci->Path, base)) if(cmCTestSVNPathStarts(ci->Path, base))
{ {
this->Base = base; svninfo.Base = base;
} }
} }
} }
@ -175,25 +201,9 @@ void cmCTestSVN::GuessBase(std::vector<Change> const& changes)
// base lie under its path. If no base was found then the working // base lie under its path. If no base was found then the working
// tree must be a checkout of the entire repo and this will match // tree must be a checkout of the entire repo and this will match
// the leading slash in all paths. // the leading slash in all paths.
this->Base += "/"; svninfo.Base += "/";
this->Log << "Guessed Base = " << this->Base << "\n"; this->Log << "Guessed Base = " << svninfo.Base << "\n";
}
//----------------------------------------------------------------------------
const char* cmCTestSVN::LocalPath(std::string const& path)
{
if(path.size() > this->Base.size() &&
strncmp(path.c_str(), this->Base.c_str(), this->Base.size()) == 0)
{
// This path lies under the base, so return a relative path.
return path.c_str() + this->Base.size();
}
else
{
// This path does not lie under the base, so ignore it.
return 0;
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -282,11 +292,13 @@ class cmCTestSVN::LogParser: public cmCTestVC::OutputLogger,
private cmXMLParser private cmXMLParser
{ {
public: public:
LogParser(cmCTestSVN* svn, const char* prefix): LogParser(cmCTestSVN* svn, const char* prefix, SVNInfo& svninfo):
OutputLogger(svn->Log, prefix), SVN(svn) { this->InitializeParser(); } OutputLogger(svn->Log, prefix), SVN(svn), SVNRepo(svninfo)
{ this->InitializeParser(); }
~LogParser() { this->CleanupParser(); } ~LogParser() { this->CleanupParser(); }
private: private:
cmCTestSVN* SVN; cmCTestSVN* SVN;
cmCTestSVN::SVNInfo& SVNRepo;
typedef cmCTestSVN::Revision Revision; typedef cmCTestSVN::Revision Revision;
typedef cmCTestSVN::Change Change; typedef cmCTestSVN::Change Change;
@ -308,6 +320,7 @@ private:
if(strcmp(name, "logentry") == 0) if(strcmp(name, "logentry") == 0)
{ {
this->Rev = Revision(); this->Rev = Revision();
this->Rev.SVNInfo = &SVNRepo;
if(const char* rev = this->FindAttribute(atts, "revision")) if(const char* rev = this->FindAttribute(atts, "revision"))
{ {
this->Rev.Rev = rev; this->Rev.Rev = rev;
@ -337,7 +350,9 @@ private:
} }
else if(strcmp(name, "path") == 0 && !this->CData.empty()) else if(strcmp(name, "path") == 0 && !this->CData.empty())
{ {
this->CurChange.Path.assign(&this->CData[0], this->CData.size()); std::string orig_path(&this->CData[0], this->CData.size());
std::string new_path = SVNRepo.BuildLocalPath( orig_path );
this->CurChange.Path.assign(new_path);
this->Changes.push_back(this->CurChange); this->Changes.push_back(this->CurChange);
} }
else if(strcmp(name, "author") == 0 && !this->CData.empty()) else if(strcmp(name, "author") == 0 && !this->CData.empty())
@ -363,23 +378,32 @@ private:
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmCTestSVN::LoadRevisions() void cmCTestSVN::LoadRevisions()
{
// Get revision of the root repository
SVNInfo& svninfo = *RootInfo;
LoadRevisions(svninfo);
}
//----------------------------------------------------------------------------
void cmCTestSVN::LoadRevisions(SVNInfo &svninfo)
{ {
// We are interested in every revision included in the update. // We are interested in every revision included in the update.
std::string revs; std::string revs;
if(atoi(this->OldRevision.c_str()) < atoi(this->NewRevision.c_str())) if(atoi(svninfo.OldRevision.c_str()) < atoi(svninfo.NewRevision.c_str()))
{ {
revs = "-r" + this->OldRevision + ":" + this->NewRevision; revs = "-r" + svninfo.OldRevision + ":" + svninfo.NewRevision;
} }
else else
{ {
revs = "-r" + this->NewRevision; revs = "-r" + svninfo.NewRevision;
} }
// Run "svn log" to get all global revisions of interest. // Run "svn log" to get all global revisions of interest.
const char* svn = this->CommandLineTool.c_str(); const char* svn = this->CommandLineTool.c_str();
const char* svn_log[] = {svn, "log", "--xml", "-v", revs.c_str(), 0}; const char* svn_log[] = {svn, "log", "--xml", "-v", revs.c_str(),
svninfo.LocalPath.c_str(), 0};
{ {
LogParser out(this, "log-out> "); LogParser out(this, "log-out> ", svninfo);
OutputLogger err(this->Log, "log-err> "); OutputLogger err(this->Log, "log-err> ");
this->RunChild(svn_log, &out, &err); this->RunChild(svn_log, &out, &err);
} }
@ -390,9 +414,9 @@ void cmCTestSVN::DoRevisionSVN(Revision const& revision,
std::vector<Change> const& changes) std::vector<Change> const& changes)
{ {
// Guess the base checkout path from the changes if necessary. // Guess the base checkout path from the changes if necessary.
if(this->Base.empty() && !changes.empty()) if(this->RootInfo->Base.empty() && !changes.empty())
{ {
this->GuessBase(changes); this->GuessBase(*this->RootInfo, changes);
} }
this->cmCTestGlobalVC::DoRevision(revision, changes); this->cmCTestGlobalVC::DoRevision(revision, changes);
} }
@ -454,7 +478,7 @@ void cmCTestSVN::WriteXMLGlobal(std::ostream& xml)
{ {
this->cmCTestGlobalVC::WriteXMLGlobal(xml); this->cmCTestGlobalVC::WriteXMLGlobal(xml);
xml << "\t<SVNPath>" << this->Base << "</SVNPath>\n"; xml << "\t<SVNPath>" << this->RootInfo->Base << "</SVNPath>\n";
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------

View File

@ -33,15 +33,6 @@ private:
virtual void NoteNewRevision(); virtual void NoteNewRevision();
virtual bool UpdateImpl(); virtual bool UpdateImpl();
// URL of repository directory checked out in the working tree.
std::string URL;
// URL of repository root directory.
std::string Root;
// Directory under repository root checked out in working tree.
std::string Base;
// Information about an SVN repository (root repository or external) // Information about an SVN repository (root repository or external)
struct SVNInfo { struct SVNInfo {
@ -76,12 +67,12 @@ private:
// Pointer to the infos of the root repository. // Pointer to the infos of the root repository.
SVNInfo* RootInfo; SVNInfo* RootInfo;
std::string LoadInfo(); std::string LoadInfo(SVNInfo& svninfo);
void LoadModifications(); void LoadModifications();
void LoadRevisions(); void LoadRevisions();
void LoadRevisions(SVNInfo& svninfo);
void GuessBase(std::vector<Change> const& changes); void GuessBase(SVNInfo &svninfo, std::vector<Change> const& changes);
const char* LocalPath(std::string const& path);
void DoRevisionSVN(Revision const& revision, void DoRevisionSVN(Revision const& revision,
std::vector<Change> const& changes); std::vector<Change> const& changes);