| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- /*=========================================================================
- 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 "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(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", "-d<now", 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;
- }
|