mirror of
https://github.com/reactos/CMake.git
synced 2024-11-30 23:10:26 +00:00
96afb12087
This converts the CMake license to a pure 3-clause OSI-approved BSD License. We drop the previous license clause requiring modified versions to be plainly marked. We also update the CMake copyright to cover the full development time range.
320 lines
10 KiB
C++
320 lines
10 KiB
C++
/*============================================================================
|
|
CMake - Cross Platform Makefile Generator
|
|
Copyright 2000-2009 Kitware, Inc.
|
|
|
|
Distributed under the OSI-approved BSD License (the "License");
|
|
see accompanying file Copyright.txt for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even the
|
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
See the License for more information.
|
|
============================================================================*/
|
|
#include "cmCTestCVS.h"
|
|
|
|
#include "cmCTest.h"
|
|
#include "cmSystemTools.h"
|
|
#include "cmXMLSafe.h"
|
|
|
|
#include <cmsys/RegularExpression.hxx>
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmCTestCVS::cmCTestCVS(cmCTest* ct, std::ostream& log): cmCTestVC(ct, log)
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmCTestCVS::~cmCTestCVS()
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
class cmCTestCVS::UpdateParser: public cmCTestVC::LineParser
|
|
{
|
|
public:
|
|
UpdateParser(cmCTestCVS* cvs, const char* prefix): CVS(cvs)
|
|
{
|
|
this->SetLog(&cvs->Log, prefix);
|
|
// See "man cvs", section "update output".
|
|
this->RegexFileUpdated.compile("^([UP]) *(.*)");
|
|
this->RegexFileModified.compile("^([MRA]) *(.*)");
|
|
this->RegexFileConflicting.compile("^([C]) *(.*)");
|
|
this->RegexFileRemoved1.compile(
|
|
"cvs[^ ]* update: `?([^']*)'? is no longer in the repository");
|
|
this->RegexFileRemoved2.compile(
|
|
"cvs[^ ]* update: "
|
|
"warning: `?([^']*)'? is not \\(any longer\\) pertinent");
|
|
}
|
|
private:
|
|
cmCTestCVS* CVS;
|
|
cmsys::RegularExpression RegexFileUpdated;
|
|
cmsys::RegularExpression RegexFileModified;
|
|
cmsys::RegularExpression RegexFileConflicting;
|
|
cmsys::RegularExpression RegexFileRemoved1;
|
|
cmsys::RegularExpression RegexFileRemoved2;
|
|
|
|
virtual bool ProcessLine()
|
|
{
|
|
if(this->RegexFileUpdated.find(this->Line))
|
|
{
|
|
this->DoFile(PathUpdated, this->RegexFileUpdated.match(2));
|
|
}
|
|
else if(this->RegexFileModified.find(this->Line))
|
|
{
|
|
this->DoFile(PathModified, this->RegexFileModified.match(2));
|
|
}
|
|
else if(this->RegexFileConflicting.find(this->Line))
|
|
{
|
|
this->DoFile(PathConflicting, this->RegexFileConflicting.match(2));
|
|
}
|
|
else if(this->RegexFileRemoved1.find(this->Line))
|
|
{
|
|
this->DoFile(PathUpdated, this->RegexFileRemoved1.match(1));
|
|
}
|
|
else if(this->RegexFileRemoved2.find(this->Line))
|
|
{
|
|
this->DoFile(PathUpdated, this->RegexFileRemoved2.match(1));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void DoFile(PathStatus status, std::string const& file)
|
|
{
|
|
std::string dir = cmSystemTools::GetFilenamePath(file);
|
|
std::string name = cmSystemTools::GetFilenameName(file);
|
|
this->CVS->Dirs[dir][name] = status;
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool cmCTestCVS::UpdateImpl()
|
|
{
|
|
// Get user-specified update options.
|
|
std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
|
|
if(opts.empty())
|
|
{
|
|
opts = this->CTest->GetCTestConfiguration("CVSUpdateOptions");
|
|
if(opts.empty())
|
|
{
|
|
opts = "-dP";
|
|
}
|
|
}
|
|
std::vector<cmStdString> args = cmSystemTools::ParseArguments(opts.c_str());
|
|
|
|
// Specify the start time for nightly testing.
|
|
if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
|
|
{
|
|
args.push_back("-D" + this->GetNightlyTime() + " UTC");
|
|
}
|
|
|
|
// Run "cvs update" to update the work tree.
|
|
std::vector<char const*> cvs_update;
|
|
cvs_update.push_back(this->CommandLineTool.c_str());
|
|
cvs_update.push_back("-z3");
|
|
cvs_update.push_back("update");
|
|
for(std::vector<cmStdString>::const_iterator ai = args.begin();
|
|
ai != args.end(); ++ai)
|
|
{
|
|
cvs_update.push_back(ai->c_str());
|
|
}
|
|
cvs_update.push_back(0);
|
|
|
|
UpdateParser out(this, "up-out> ");
|
|
UpdateParser err(this, "up-err> ");
|
|
return this->RunUpdateCommand(&cvs_update[0], &out, &err);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
class cmCTestCVS::LogParser: public cmCTestVC::LineParser
|
|
{
|
|
public:
|
|
typedef cmCTestCVS::Revision Revision;
|
|
LogParser(cmCTestCVS* cvs, const char* prefix, std::vector<Revision>& revs):
|
|
CVS(cvs), Revisions(revs), Section(SectionHeader)
|
|
{
|
|
this->SetLog(&cvs->Log, prefix),
|
|
this->RegexRevision.compile("^revision +([^ ]*) *$");
|
|
this->RegexBranches.compile("^branches: .*$");
|
|
this->RegexPerson.compile("^date: +([^;]+); +author: +([^;]+);");
|
|
}
|
|
private:
|
|
cmCTestCVS* CVS;
|
|
std::vector<Revision>& Revisions;
|
|
cmsys::RegularExpression RegexRevision;
|
|
cmsys::RegularExpression RegexBranches;
|
|
cmsys::RegularExpression RegexPerson;
|
|
enum SectionType { SectionHeader, SectionRevisions, SectionEnd };
|
|
SectionType Section;
|
|
Revision Rev;
|
|
|
|
virtual bool ProcessLine()
|
|
{
|
|
if(this->Line == ("======================================="
|
|
"======================================"))
|
|
{
|
|
// This line ends the revision list.
|
|
if(this->Section == SectionRevisions)
|
|
{
|
|
this->FinishRevision();
|
|
}
|
|
this->Section = SectionEnd;
|
|
}
|
|
else if(this->Line == "----------------------------")
|
|
{
|
|
// This line divides revisions from the header and each other.
|
|
if(this->Section == SectionHeader)
|
|
{
|
|
this->Section = SectionRevisions;
|
|
}
|
|
else if(this->Section == SectionRevisions)
|
|
{
|
|
this->FinishRevision();
|
|
}
|
|
}
|
|
else if(this->Section == SectionRevisions)
|
|
{
|
|
if(!this->Rev.Log.empty())
|
|
{
|
|
// Continue the existing log.
|
|
this->Rev.Log += this->Line;
|
|
this->Rev.Log += "\n";
|
|
}
|
|
else if(this->Rev.Rev.empty() && this->RegexRevision.find(this->Line))
|
|
{
|
|
this->Rev.Rev = this->RegexRevision.match(1);
|
|
}
|
|
else if(this->Rev.Date.empty() && this->RegexPerson.find(this->Line))
|
|
{
|
|
this->Rev.Date = this->RegexPerson.match(1);
|
|
this->Rev.Author = this->RegexPerson.match(2);
|
|
}
|
|
else if(!this->RegexBranches.find(this->Line))
|
|
{
|
|
// Start the log.
|
|
this->Rev.Log += this->Line;
|
|
this->Rev.Log += "\n";
|
|
}
|
|
}
|
|
return this->Section != SectionEnd;
|
|
}
|
|
|
|
void FinishRevision()
|
|
{
|
|
if(!this->Rev.Rev.empty())
|
|
{
|
|
// Record this revision.
|
|
this->CVS->Log << "Found revision " << this->Rev.Rev << "\n"
|
|
<< " author = " << this->Rev.Author << "\n"
|
|
<< " date = " << this->Rev.Date << "\n";
|
|
this->Revisions.push_back(this->Rev);
|
|
|
|
// We only need two revisions.
|
|
if(this->Revisions.size() >= 2)
|
|
{
|
|
this->Section = SectionEnd;
|
|
}
|
|
}
|
|
this->Rev = Revision();
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::string cmCTestCVS::ComputeBranchFlag(std::string const& dir)
|
|
{
|
|
// Compute the tag file location for this directory.
|
|
std::string tagFile = this->SourceDirectory;
|
|
if(!dir.empty())
|
|
{
|
|
tagFile += "/";
|
|
tagFile += dir;
|
|
}
|
|
tagFile += "/CVS/Tag";
|
|
|
|
// Lookup the branch in the tag file, if any.
|
|
std::string tagLine;
|
|
std::ifstream tagStream(tagFile.c_str());
|
|
if(tagStream && cmSystemTools::GetLineFromStream(tagStream, tagLine) &&
|
|
tagLine.size() > 1 && tagLine[0] == 'T')
|
|
{
|
|
// Use the branch specified in the tag file.
|
|
std::string flag = "-r";
|
|
flag += tagLine.substr(1);
|
|
return flag;
|
|
}
|
|
else
|
|
{
|
|
// Use the default branch.
|
|
return "-b";
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmCTestCVS::LoadRevisions(std::string const& file,
|
|
const char* branchFlag,
|
|
std::vector<Revision>& revisions)
|
|
{
|
|
cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
|
|
|
|
// Run "cvs log" to get revisions of this file on this branch.
|
|
const char* cvs = this->CommandLineTool.c_str();
|
|
const char* cvs_log[] =
|
|
{cvs, "log", "-N", branchFlag, file.c_str(), 0};
|
|
|
|
LogParser out(this, "log-out> ", revisions);
|
|
OutputLogger err(this->Log, "log-err> ");
|
|
this->RunChild(cvs_log, &out, &err);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmCTestCVS::WriteXMLDirectory(std::ostream& xml,
|
|
std::string const& path,
|
|
Directory const& dir)
|
|
{
|
|
const char* slash = path.empty()? "":"/";
|
|
xml << "\t<Directory>\n"
|
|
<< "\t\t<Name>" << cmXMLSafe(path) << "</Name>\n";
|
|
|
|
// Lookup the branch checked out in the working tree.
|
|
std::string branchFlag = this->ComputeBranchFlag(path);
|
|
|
|
// Load revisions and write an entry for each file in this directory.
|
|
std::vector<Revision> revisions;
|
|
for(Directory::const_iterator fi = dir.begin(); fi != dir.end(); ++fi)
|
|
{
|
|
std::string full = path + slash + fi->first;
|
|
|
|
// Load two real or unknown revisions.
|
|
revisions.clear();
|
|
if(fi->second != PathUpdated)
|
|
{
|
|
// For local modifications the current rev is unknown and the
|
|
// prior rev is the latest from cvs.
|
|
revisions.push_back(this->Unknown);
|
|
}
|
|
this->LoadRevisions(full, branchFlag.c_str(), revisions);
|
|
revisions.resize(2, this->Unknown);
|
|
|
|
// Write the entry for this file with these revisions.
|
|
File f(fi->second, &revisions[0], &revisions[1]);
|
|
this->WriteXMLEntry(xml, path, fi->first, full, f);
|
|
}
|
|
xml << "\t</Directory>\n";
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool cmCTestCVS::WriteXMLUpdates(std::ostream& xml)
|
|
{
|
|
cmCTestLog(this->CTest, HANDLER_OUTPUT,
|
|
" Gathering version information (one . per updated file):\n"
|
|
" " << std::flush);
|
|
|
|
for(std::map<cmStdString, Directory>::const_iterator
|
|
di = this->Dirs.begin(); di != this->Dirs.end(); ++di)
|
|
{
|
|
this->WriteXMLDirectory(xml, di->first, di->second);
|
|
}
|
|
|
|
cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
|
|
|
|
return true;
|
|
}
|