summaryrefslogtreecommitdiffstats
path: root/Source/CTest
diff options
context:
space:
mode:
Diffstat (limited to 'Source/CTest')
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.cxx34
-rw-r--r--Source/CTest/cmCTestBuildCommand.cxx9
-rw-r--r--Source/CTest/cmCTestBuildCommand.h26
-rw-r--r--Source/CTest/cmCTestBuildHandler.cxx11
-rw-r--r--Source/CTest/cmCTestBuildHandler.h4
-rw-r--r--Source/CTest/cmCTestCVS.cxx3
-rw-r--r--Source/CTest/cmCTestConfigureCommand.cxx2
-rw-r--r--Source/CTest/cmCTestConfigureCommand.h28
-rw-r--r--Source/CTest/cmCTestCoverageCommand.h26
-rw-r--r--Source/CTest/cmCTestCoverageHandler.cxx54
-rw-r--r--Source/CTest/cmCTestCoverageHandler.h6
-rw-r--r--Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h20
-rw-r--r--Source/CTest/cmCTestGIT.cxx9
-rw-r--r--Source/CTest/cmCTestLaunch.cxx34
-rw-r--r--Source/CTest/cmCTestLaunch.h1
-rw-r--r--Source/CTest/cmCTestMemCheckCommand.h34
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.cxx5
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.cxx233
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.h7
-rw-r--r--Source/CTest/cmCTestP4.cxx559
-rw-r--r--Source/CTest/cmCTestP4.h71
-rw-r--r--Source/CTest/cmCTestReadCustomFilesCommand.h19
-rw-r--r--Source/CTest/cmCTestRunScriptCommand.h24
-rw-r--r--Source/CTest/cmCTestRunTest.cxx8
-rw-r--r--Source/CTest/cmCTestScriptHandler.cxx77
-rw-r--r--Source/CTest/cmCTestScriptHandler.h4
-rw-r--r--Source/CTest/cmCTestSleepCommand.h20
-rw-r--r--Source/CTest/cmCTestStartCommand.h24
-rw-r--r--Source/CTest/cmCTestSubmitCommand.h38
-rw-r--r--Source/CTest/cmCTestSubmitHandler.cxx8
-rw-r--r--Source/CTest/cmCTestTestCommand.h39
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx180
-rw-r--r--Source/CTest/cmCTestTestHandler.h27
-rw-r--r--Source/CTest/cmCTestUpdateCommand.cxx8
-rw-r--r--Source/CTest/cmCTestUpdateCommand.h22
-rw-r--r--Source/CTest/cmCTestUpdateHandler.cxx26
-rw-r--r--Source/CTest/cmCTestUpdateHandler.h1
-rw-r--r--Source/CTest/cmCTestUploadCommand.h19
-rw-r--r--Source/CTest/cmParseCacheCoverage.cxx3
-rw-r--r--Source/CTest/cmParseGTMCoverage.cxx5
-rw-r--r--Source/CTest/cmParseMumpsCoverage.cxx5
-rw-r--r--Source/CTest/cmParsePHPCoverage.cxx13
-rw-r--r--Source/CTest/cmParsePHPCoverage.h10
-rw-r--r--Source/CTest/cmParsePythonCoverage.cxx113
-rw-r--r--Source/CTest/cmParsePythonCoverage.h48
45 files changed, 1391 insertions, 526 deletions
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index 4fa3c53..0fac136 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -18,6 +18,7 @@
#include "cmGlobalGenerator.h"
#include <cmsys/Process.h>
#include "cmCTestTestHandler.h"
+#include "cmCacheManager.h"
//----------------------------------------------------------------------
cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler()
@@ -59,7 +60,7 @@ int cmCTestBuildAndTestHandler::RunCMake(std::string* outstring,
{
unsigned int k;
std::vector<std::string> args;
- args.push_back(this->CTest->GetCMakeExecutable());
+ args.push_back(cmSystemTools::GetCMakeCommand());
args.push_back(this->SourceDir);
if(this->BuildGenerator.size())
{
@@ -184,14 +185,14 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
cmOStringStream out;
// if the generator and make program are not specified then it is an error
- if (!this->BuildGenerator.size() || !this->BuildMakeProgram.size())
+ if (!this->BuildGenerator.size())
{
if(outstring)
{
*outstring =
- "--build-and-test requires that both the generator and makeprogram "
- "be provided using the --build-generator and --build-makeprogram "
- "command line options. ";
+ "--build-and-test requires that the generator "
+ "be provided using the --build-generator "
+ "command line option. ";
}
return 1;
}
@@ -238,9 +239,13 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
if(this->BuildNoCMake)
{
+ // Make the generator available for the Build call below.
cm.SetGlobalGenerator(cm.CreateGlobalGenerator(
this->BuildGenerator.c_str()));
cm.SetGeneratorToolset(this->BuildGeneratorToolset);
+
+ // Load the cache to make CMAKE_MAKE_PROGRAM available.
+ cm.GetCacheManager()->LoadCache(this->BinaryDir.c_str());
}
else
{
@@ -508,23 +513,14 @@ int cmCTestBuildAndTestHandler::ProcessCommandLineArguments(
{
this->BuildNoClean = true;
}
- if(currentArg.find("--build-options",0) == 0 && idx < allArgs.size() - 1)
+ if(currentArg.find("--build-options",0) == 0)
{
- ++idx;
- bool done = false;
- while(idx < allArgs.size() && !done)
+ while(idx+1 < allArgs.size() &&
+ allArgs[idx+1] != "--build-target" &&
+ allArgs[idx+1] != "--test-command")
{
+ ++idx;
this->BuildOptions.push_back(allArgs[idx]);
- if(idx+1 < allArgs.size()
- && (allArgs[idx+1] == "--build-target" ||
- allArgs[idx+1] == "--test-command"))
- {
- done = true;
- }
- else
- {
- ++idx;
- }
}
}
if(currentArg.find("--test-command",0) == 0 && idx < allArgs.size() - 1)
diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx
index 1f63185..12ff718 100644
--- a/Source/CTest/cmCTestBuildCommand.cxx
+++ b/Source/CTest/cmCTestBuildCommand.cxx
@@ -114,9 +114,6 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
this->Makefile->GetCMakeInstance()->CreateGlobalGenerator(
cmakeGeneratorName);
}
- this->GlobalGenerator->FindMakeProgram(this->Makefile);
- const char* cmakeMakeProgram
- = this->Makefile->GetDefinition("CMAKE_MAKE_PROGRAM");
if(strlen(cmakeBuildConfiguration) == 0)
{
const char* config = 0;
@@ -133,10 +130,8 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
std::string dir = this->CTest->GetCTestConfiguration("BuildDirectory");
std::string buildCommand
= this->GlobalGenerator->
- GenerateBuildCommand(cmakeMakeProgram,
- cmakeProjectName, dir.c_str(),
- cmakeBuildAdditionalFlags, cmakeBuildTarget,
- cmakeBuildConfiguration, true, false);
+ GenerateCMakeBuildCommand(cmakeBuildTarget, cmakeBuildConfiguration,
+ cmakeBuildAdditionalFlags, true);
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"SetMakeCommand:"
<< buildCommand.c_str() << "\n");
diff --git a/Source/CTest/cmCTestBuildCommand.h b/Source/CTest/cmCTestBuildCommand.h
index cabc39b..08887fe 100644
--- a/Source/CTest/cmCTestBuildCommand.h
+++ b/Source/CTest/cmCTestBuildCommand.h
@@ -45,34 +45,8 @@ public:
*/
virtual const char* GetName() const { return "ctest_build";}
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "Build the project.";
- }
virtual bool InitialPass(std::vector<std::string> const& args,
cmExecutionStatus &status);
- /**
- * More documentation.
- */
- virtual const char* GetFullDocumentation() const
- {
- return
- " ctest_build([BUILD build_dir] [TARGET target] [RETURN_VALUE res]\n"
- " [APPEND][NUMBER_ERRORS val] [NUMBER_WARNINGS val])\n"
- "Builds the given build directory and stores results in Build.xml. "
- "If no BUILD is given, the CTEST_BINARY_DIRECTORY variable is used.\n"
- "The TARGET variable can be used to specify a build target. If none "
- "is specified, the \"all\" target will be built.\n"
- "The RETURN_VALUE option specifies a variable in which to store the "
- "return value of the native build tool. "
- "The NUMBER_ERRORS and NUMBER_WARNINGS options specify variables in "
- "which to store the number of build errors and warnings detected."
- "\n"
- CTEST_COMMAND_APPEND_OPTION_DOCS;
- }
cmTypeMacro(cmCTestBuildCommand, cmCTestHandlerCommand);
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index 39eeb70..c5deb96 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -24,6 +24,7 @@
//#include <cmsys/RegularExpression.hxx>
#include <cmsys/Process.h>
#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
// used for sleep
#ifdef _WIN32
@@ -751,7 +752,7 @@ void cmCTestBuildHandler::GenerateXMLFooter(std::ostream& os,
void cmCTestBuildHandler::GenerateXMLLaunchedFragment(std::ostream& os,
const char* fname)
{
- std::ifstream fin(fname, std::ios::in | std::ios::binary);
+ cmsys::ifstream fin(fname, std::ios::in | std::ios::binary);
std::string line;
while(cmSystemTools::GetLineFromStream(fin, line))
{
@@ -763,7 +764,7 @@ void cmCTestBuildHandler::GenerateXMLLaunchedFragment(std::ostream& os,
bool cmCTestBuildHandler::IsLaunchedErrorFile(const char* fname)
{
// error-{hash}.xml
- return (strncmp(fname, "error-", 6) == 0 &&
+ return (cmHasLiteralPrefix(fname, "error-") &&
strcmp(fname+strlen(fname)-4, ".xml") == 0);
}
@@ -771,7 +772,7 @@ bool cmCTestBuildHandler::IsLaunchedErrorFile(const char* fname)
bool cmCTestBuildHandler::IsLaunchedWarningFile(const char* fname)
{
// warning-{hash}.xml
- return (strncmp(fname, "warning-", 8) == 0 &&
+ return (cmHasLiteralPrefix(fname, "warning-") &&
strcmp(fname+strlen(fname)-4, ".xml") == 0);
}
@@ -885,7 +886,7 @@ cmCTestBuildHandler::LaunchHelper
//----------------------------------------------------------------------
int cmCTestBuildHandler::RunMakeCommand(const char* command,
- int* retVal, const char* dir, int timeout, std::ofstream& ofs)
+ int* retVal, const char* dir, int timeout, std::ostream& ofs)
{
// First generate the command and arguments
std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);
@@ -1049,7 +1050,7 @@ int cmCTestBuildHandler::RunMakeCommand(const char* command,
//----------------------------------------------------------------------
void cmCTestBuildHandler::ProcessBuffer(const char* data, int length,
- size_t& tick, size_t tick_len, std::ofstream& ofs,
+ size_t& tick, size_t tick_len, std::ostream& ofs,
t_BuildProcessingQueueType* queue)
{
const std::string::size_type tick_line_len = 50;
diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h
index 439efd6..ff7cfd6 100644
--- a/Source/CTest/cmCTestBuildHandler.h
+++ b/Source/CTest/cmCTestBuildHandler.h
@@ -54,7 +54,7 @@ private:
// and retVal is return value or exception.
int RunMakeCommand(const char* command,
int* retVal, const char* dir, int timeout,
- std::ofstream& ofs);
+ std::ostream& ofs);
enum {
b_REGULAR_LINE,
@@ -113,7 +113,7 @@ private:
typedef std::deque<char> t_BuildProcessingQueueType;
void ProcessBuffer(const char* data, int length, size_t& tick,
- size_t tick_len, std::ofstream& ofs, t_BuildProcessingQueueType* queue);
+ size_t tick_len, std::ostream& ofs, t_BuildProcessingQueueType* queue);
int ProcessSingleLine(const char* data);
t_BuildProcessingQueueType BuildProcessingQueue;
diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx
index 7269507..17dbb55 100644
--- a/Source/CTest/cmCTestCVS.cxx
+++ b/Source/CTest/cmCTestCVS.cxx
@@ -16,6 +16,7 @@
#include "cmXMLSafe.h"
#include <cmsys/RegularExpression.hxx>
+#include <cmsys/FStream.hxx>
//----------------------------------------------------------------------------
cmCTestCVS::cmCTestCVS(cmCTest* ct, std::ostream& log): cmCTestVC(ct, log)
@@ -231,7 +232,7 @@ std::string cmCTestCVS::ComputeBranchFlag(std::string const& dir)
// Lookup the branch in the tag file, if any.
std::string tagLine;
- std::ifstream tagStream(tagFile.c_str());
+ cmsys::ifstream tagStream(tagFile.c_str());
if(tagStream && cmSystemTools::GetLineFromStream(tagStream, tagLine) &&
tagLine.size() > 1 && tagLine[0] == 'T')
{
diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx
index db33cb6..5eed409 100644
--- a/Source/CTest/cmCTestConfigureCommand.cxx
+++ b/Source/CTest/cmCTestConfigureCommand.cxx
@@ -86,7 +86,7 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
}
std::string cmakeConfigureCommand = "\"";
- cmakeConfigureCommand += this->CTest->GetCMakeExecutable();
+ cmakeConfigureCommand += cmSystemTools::GetCMakeCommand();
cmakeConfigureCommand += "\"";
std::vector<std::string>::const_iterator it;
diff --git a/Source/CTest/cmCTestConfigureCommand.h b/Source/CTest/cmCTestConfigureCommand.h
index b343fc1..b592c5a 100644
--- a/Source/CTest/cmCTestConfigureCommand.h
+++ b/Source/CTest/cmCTestConfigureCommand.h
@@ -40,34 +40,6 @@ public:
*/
virtual const char* GetName() const { return "ctest_configure";}
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "Configure the project build tree.";
- }
-
- /**
- * More documentation.
- */
- virtual const char* GetFullDocumentation() const
- {
- return
- " ctest_configure([BUILD build_dir] [SOURCE source_dir] [APPEND]\n"
- " [OPTIONS options] [RETURN_VALUE res])\n"
- "Configures the given build directory and stores results in "
- "Configure.xml. "
- "If no BUILD is given, the CTEST_BINARY_DIRECTORY variable is used. "
- "If no SOURCE is given, the CTEST_SOURCE_DIRECTORY variable is used. "
- "The OPTIONS argument specifies command line arguments to pass to "
- "the configuration tool. "
- "The RETURN_VALUE option specifies a variable in which to store the "
- "return value of the native build tool."
- "\n"
- CTEST_COMMAND_APPEND_OPTION_DOCS;
- }
-
cmTypeMacro(cmCTestConfigureCommand, cmCTestHandlerCommand);
protected:
diff --git a/Source/CTest/cmCTestCoverageCommand.h b/Source/CTest/cmCTestCoverageCommand.h
index 2fe762c..11bb411 100644
--- a/Source/CTest/cmCTestCoverageCommand.h
+++ b/Source/CTest/cmCTestCoverageCommand.h
@@ -41,32 +41,6 @@ public:
*/
virtual const char* GetName() const { return "ctest_coverage";}
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "Collect coverage tool results.";
- }
-
- /**
- * More documentation.
- */
- virtual const char* GetFullDocumentation() const
- {
- return
- " ctest_coverage([BUILD build_dir] [RETURN_VALUE res] [APPEND]\n"
- " [LABELS label1 [label2 [...]]])\n"
- "Perform the coverage of the given build directory and stores results "
- "in Coverage.xml. The second argument is a variable that will hold "
- "value."
- "\n"
- "The LABELS option filters the coverage report to include only "
- "source files labeled with at least one of the labels specified."
- "\n"
- CTEST_COMMAND_APPEND_OPTION_DOCS;
- }
-
cmTypeMacro(cmCTestCoverageCommand, cmCTestHandlerCommand);
protected:
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index 20aded2..3c65c55 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -11,6 +11,7 @@
============================================================================*/
#include "cmCTestCoverageHandler.h"
#include "cmParsePHPCoverage.h"
+#include "cmParsePythonCoverage.h"
#include "cmParseGTMCoverage.h"
#include "cmParseCacheCoverage.h"
#include "cmCTest.h"
@@ -25,6 +26,7 @@
#include <cmsys/Glob.hxx>
#include <cmsys/stl/iterator>
#include <cmsys/stl/algorithm>
+#include <cmsys/FStream.hxx>
#include <stdlib.h>
#include <math.h>
@@ -141,6 +143,7 @@ void cmCTestCoverageHandler::Initialize()
this->Superclass::Initialize();
this->CustomCoverageExclude.clear();
this->SourceLabels.clear();
+ this->TargetDirs.clear();
this->LabelIdMap.clear();
this->Labels.clear();
this->LabelFilter.clear();
@@ -392,6 +395,13 @@ int cmCTestCoverageHandler::ProcessHandler()
{
return error;
}
+ file_count += this->HandlePythonCoverage(&cont);
+ error = cont.Error;
+ if ( file_count < 0 )
+ {
+ return error;
+ }
+
file_count += this->HandleMumpsCoverage(&cont);
error = cont.Error;
if ( file_count < 0 )
@@ -502,7 +512,7 @@ int cmCTestCoverageHandler::ProcessHandler()
<< "\" FullPath=\"" << cmXMLSafe(shortFileName) << "\">\n"
<< "\t\t<Report>" << std::endl;
- std::ifstream ifs(fullFileName.c_str());
+ cmsys::ifstream ifs(fullFileName.c_str());
if ( !ifs)
{
cmOStringStream ostr;
@@ -591,7 +601,7 @@ int cmCTestCoverageHandler::ProcessHandler()
<< "\" FullPath=\"" << cmXMLSafe(*i) << "\">\n"
<< "\t\t<Report>" << std::endl;
- std::ifstream ifs(fullPath.c_str());
+ cmsys::ifstream ifs(fullPath.c_str());
if (!ifs)
{
cmOStringStream ostr;
@@ -761,6 +771,32 @@ int cmCTestCoverageHandler::HandlePHPCoverage(
}
return static_cast<int>(cont->TotalCoverage.size());
}
+
+//----------------------------------------------------------------------
+int cmCTestCoverageHandler::HandlePythonCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParsePythonCoverage cov(*cont, this->CTest);
+
+ // Assume the coverage.xml is in the source directory
+ std::string coverageXMLFile = this->CTest->GetBinaryDir() + "/coverage.xml";
+
+ if(cmSystemTools::FileExists(coverageXMLFile.c_str()))
+ {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Parsing coverage.py XML file: " << coverageXMLFile
+ << std::endl);
+ cov.ReadCoverageXML(coverageXMLFile.c_str());
+ }
+ else
+ {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Cannot find coverage.py XML file: " << coverageXMLFile
+ << std::endl);
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+
//----------------------------------------------------------------------
int cmCTestCoverageHandler::HandleMumpsCoverage(
cmCTestCoverageHandlerContainer* cont)
@@ -1123,7 +1159,7 @@ int cmCTestCoverageHandler::HandleGCovCoverage(
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " in gcovFile: "
<< gcovFile << std::endl);
- std::ifstream ifile(gcovFile.c_str());
+ cmsys::ifstream ifile(gcovFile.c_str());
if ( ! ifile )
{
cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open file: "
@@ -1335,7 +1371,7 @@ int cmCTestCoverageHandler::HandleTracePyCoverage(
= &cont->TotalCoverage[actualSourceFile];
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
" in file: " << fileIt->c_str() << std::endl);
- std::ifstream ifile(fileIt->c_str());
+ cmsys::ifstream ifile(fileIt->c_str());
if ( ! ifile )
{
cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open file: "
@@ -1495,7 +1531,7 @@ int cmCTestCoverageHandler::RunBullseyeCoverageBranch(
"covbr output in " << outputFile
<< std::endl);
// open the output file
- std::ifstream fin(outputFile.c_str());
+ cmsys::ifstream fin(outputFile.c_str());
if(!fin)
{
cmCTestLog(this->CTest, ERROR_MESSAGE,
@@ -1708,7 +1744,7 @@ int cmCTestCoverageHandler::RunBullseyeSourceSummary(
std::vector<std::string> coveredFiles;
std::vector<std::string> coveredFilesFullPath;
// Read and parse the summary output file
- std::ifstream fin(outputFile.c_str());
+ cmsys::ifstream fin(outputFile.c_str());
if(!fin)
{
cmCTestLog(this->CTest, ERROR_MESSAGE,
@@ -1977,7 +2013,7 @@ void cmCTestCoverageHandler::LoadLabels()
fileList += "/TargetDirectories.txt";
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
" target directory list [" << fileList << "]\n");
- std::ifstream finList(fileList.c_str());
+ cmsys::ifstream finList(fileList.c_str());
std::string line;
while(cmSystemTools::GetLineFromStream(finList, line))
{
@@ -1991,7 +2027,7 @@ void cmCTestCoverageHandler::LoadLabels(const char* dir)
LabelSet& dirLabels = this->TargetDirs[dir];
std::string fname = dir;
fname += "/Labels.txt";
- std::ifstream fin(fname.c_str());
+ cmsys::ifstream fin(fname.c_str());
if(!fin)
{
return;
@@ -2045,7 +2081,7 @@ void cmCTestCoverageHandler::LoadLabels(const char* dir)
}
//----------------------------------------------------------------------
-void cmCTestCoverageHandler::WriteXMLLabels(std::ofstream& os,
+void cmCTestCoverageHandler::WriteXMLLabels(std::ostream& os,
std::string const& source)
{
LabelMapType::const_iterator li = this->SourceLabels.find(source);
diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h
index 92b0b22..660f501 100644
--- a/Source/CTest/cmCTestCoverageHandler.h
+++ b/Source/CTest/cmCTestCoverageHandler.h
@@ -70,6 +70,10 @@ private:
//! Handle coverage using xdebug php coverage
int HandlePHPCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage for Python with coverage.py
+ int HandlePythonCoverage(cmCTestCoverageHandlerContainer* cont);
+
//! Handle coverage for mumps
int HandleMumpsCoverage(cmCTestCoverageHandlerContainer* cont);
@@ -128,7 +132,7 @@ private:
// Label reading and writing methods.
void LoadLabels();
void LoadLabels(const char* dir);
- void WriteXMLLabels(std::ofstream& os, std::string const& source);
+ void WriteXMLLabels(std::ostream& os, std::string const& source);
// Label-based filtering.
std::set<int> LabelFilter;
diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h
index a763fe9..07e59a4 100644
--- a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h
+++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h
@@ -50,26 +50,6 @@ public:
*/
virtual const char* GetName() const { return "ctest_empty_binary_directory";}
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "empties the binary directory";
- }
-
- /**
- * More documentation.
- */
- virtual const char* GetFullDocumentation() const
- {
- return
- " ctest_empty_binary_directory( directory )\n"
- "Removes a binary directory. This command will perform some checks "
- "prior to deleting the directory in an attempt to avoid malicious "
- "or accidental directory deletion.";
- }
-
cmTypeMacro(cmCTestEmptyBinaryDirectoryCommand, cmCTestCommand);
};
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
index 5b34491..0e0e797 100644
--- a/Source/CTest/cmCTestGIT.cxx
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -18,6 +18,7 @@
#include <cmsys/RegularExpression.hxx>
#include <cmsys/ios/sstream>
#include <cmsys/Process.h>
+#include <cmsys/FStream.hxx>
#include <sys/types.h>
#include <time.h>
@@ -200,7 +201,7 @@ bool cmCTestGIT::UpdateByFetchAndReset()
std::string sha1;
{
std::string fetch_head = this->FindGitDir() + "/FETCH_HEAD";
- std::ifstream fin(fetch_head.c_str(), std::ios::in | std::ios::binary);
+ cmsys::ifstream fin(fetch_head.c_str(), std::ios::in | std::ios::binary);
if(!fin)
{
this->Log << "Unable to open " << fetch_head << "\n";
@@ -536,11 +537,11 @@ private:
void DoHeaderLine()
{
// Look for header fields that we need.
- if(strncmp(this->Line.c_str(), "commit ", 7) == 0)
+ if(cmHasLiteralPrefix(this->Line.c_str(), "commit "))
{
this->Rev.Rev = this->Line.c_str()+7;
}
- else if(strncmp(this->Line.c_str(), "author ", 7) == 0)
+ else if(cmHasLiteralPrefix(this->Line.c_str(), "author "))
{
Person author;
this->ParsePerson(this->Line.c_str()+7, author);
@@ -548,7 +549,7 @@ private:
this->Rev.EMail = author.EMail;
this->Rev.Date = this->FormatDateTime(author);
}
- else if(strncmp(this->Line.c_str(), "committer ", 10) == 0)
+ else if(cmHasLiteralPrefix(this->Line.c_str(), "committer "))
{
Person committer;
this->ParsePerson(this->Line.c_str()+10, committer);
diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
index 9831d02..7d9c034 100644
--- a/Source/CTest/cmCTestLaunch.cxx
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -19,6 +19,7 @@
#include <cmsys/MD5.h>
#include <cmsys/Process.h>
#include <cmsys/RegularExpression.hxx>
+#include <cmsys/FStream.hxx>
//----------------------------------------------------------------------------
cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
@@ -64,7 +65,8 @@ bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
DoingTargetName,
DoingTargetType,
DoingBuildDir,
- DoingCount };
+ DoingCount,
+ DoingFilterPrefix };
Doing doing = DoingNone;
int arg0 = 0;
for(int i=1; !arg0 && i < argc; ++i)
@@ -98,6 +100,10 @@ bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
{
doing = DoingBuildDir;
}
+ else if(strcmp(arg, "--filter-prefix") == 0)
+ {
+ doing = DoingFilterPrefix;
+ }
else if(doing == DoingOutput)
{
this->OptionOutput = arg;
@@ -132,6 +138,11 @@ bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
this->OptionBuildDir = arg;
doing = DoingNone;
}
+ else if(doing == DoingFilterPrefix)
+ {
+ this->OptionFilterPrefix = arg;
+ doing = DoingNone;
+ }
}
// Extract the real command line.
@@ -161,7 +172,7 @@ void cmCTestLaunch::HandleRealArg(const char* arg)
// Expand response file arguments.
if(arg[0] == '@' && cmSystemTools::FileExists(arg+1))
{
- std::ifstream fin(arg+1);
+ cmsys::ifstream fin(arg+1);
std::string line;
while(cmSystemTools::GetLineFromStream(fin, line))
{
@@ -231,8 +242,8 @@ void cmCTestLaunch::RunChild()
cmsysProcess* cp = this->Process;
cmsysProcess_SetCommand(cp, this->RealArgV);
- std::ofstream fout;
- std::ofstream ferr;
+ cmsys::ofstream fout;
+ cmsys::ofstream ferr;
if(this->Passthru)
{
// In passthru mode we just share the output pipes.
@@ -320,7 +331,7 @@ void cmCTestLaunch::LoadLabels()
cmSystemTools::ConvertToUnixSlashes(source);
// Load the labels file.
- std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
+ cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
if(!fin) { return; }
bool inTarget = true;
bool inSource = false;
@@ -569,12 +580,19 @@ void cmCTestLaunch::WriteXMLLabels(std::ostream& fxml)
void cmCTestLaunch::DumpFileToXML(std::ostream& fxml,
std::string const& fname)
{
- std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
+ cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
std::string line;
const char* sep = "";
+
while(cmSystemTools::GetLineFromStream(fin, line))
{
+ if(OptionFilterPrefix.size() && cmSystemTools::StringStartsWith(
+ line.c_str(), OptionFilterPrefix.c_str()))
+ {
+ continue;
+ }
+
fxml << sep << cmXMLSafe(line).Quotes(false);
sep = "\n";
}
@@ -635,7 +653,7 @@ cmCTestLaunch
fname += "Custom";
fname += purpose;
fname += ".txt";
- std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
+ cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
std::string line;
cmsys::RegularExpression rex;
while(cmSystemTools::GetLineFromStream(fin, line))
@@ -654,7 +672,7 @@ bool cmCTestLaunch::ScrapeLog(std::string const& fname)
// Look for log file lines matching warning expressions but not
// suppression expressions.
- std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
+ cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
std::string line;
while(cmSystemTools::GetLineFromStream(fin, line))
{
diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h
index 7457e83..a86a9df 100644
--- a/Source/CTest/cmCTestLaunch.h
+++ b/Source/CTest/cmCTestLaunch.h
@@ -45,6 +45,7 @@ private:
std::string OptionTargetName;
std::string OptionTargetType;
std::string OptionBuildDir;
+ std::string OptionFilterPrefix;
bool ParseArguments(int argc, const char* const* argv);
// The real command line appearing after launcher arguments.
diff --git a/Source/CTest/cmCTestMemCheckCommand.h b/Source/CTest/cmCTestMemCheckCommand.h
index 6db47ae..b50170d 100644
--- a/Source/CTest/cmCTestMemCheckCommand.h
+++ b/Source/CTest/cmCTestMemCheckCommand.h
@@ -43,40 +43,6 @@ public:
*/
virtual const char* GetName() const { return "ctest_memcheck";}
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "Run tests with a dynamic analysis tool.";
- }
-
- /**
- * More documentation.
- */
- virtual const char* GetFullDocumentation() const
- {
- return
- " ctest_memcheck([BUILD build_dir] [RETURN_VALUE res] [APPEND]\n"
- " [START start number] [END end number]\n"
- " [STRIDE stride number] [EXCLUDE exclude regex ]\n"
- " [INCLUDE include regex] \n"
- " [EXCLUDE_LABEL exclude regex] \n"
- " [INCLUDE_LABEL label regex] \n"
- " [PARALLEL_LEVEL level] )\n"
- "Tests the given build directory and stores results in MemCheck.xml. "
- "The second argument is a variable that will hold value. Optionally, "
- "you can specify the starting test number START, the ending test number "
- "END, the number of tests to skip between each test STRIDE, a regular "
- "expression for tests to run INCLUDE, or a regular expression for tests "
- "not to run EXCLUDE. EXCLUDE_LABEL and INCLUDE_LABEL are regular "
- "expressions for tests to be included or excluded by the test "
- "property LABEL. PARALLEL_LEVEL should be set to a positive number "
- "representing the number of tests to be run in parallel."
- "\n"
- CTEST_COMMAND_APPEND_OPTION_DOCS;
- }
-
cmTypeMacro(cmCTestMemCheckCommand, cmCTestTestCommand);
protected:
diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx
index 3ae2ac6..fdce04d 100644
--- a/Source/CTest/cmCTestMemCheckHandler.cxx
+++ b/Source/CTest/cmCTestMemCheckHandler.cxx
@@ -18,6 +18,7 @@
#include <cmsys/Process.h>
#include <cmsys/RegularExpression.hxx>
#include <cmsys/Base64.h>
+#include <cmsys/FStream.hxx>
#include "cmMakefile.h"
#include "cmXMLSafe.h"
@@ -929,7 +930,7 @@ cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(cmCTestTestResult& res,
}
// put a scope around this to close ifs so the file can be removed
{
- std::ifstream ifs(ofile.c_str());
+ cmsys::ifstream ifs(ofile.c_str());
if ( !ifs )
{
std::string log = "Cannot read memory tester output file: " + ofile;
@@ -984,7 +985,7 @@ cmCTestMemCheckHandler::appendMemTesterOutput(cmCTestTestResult& res,
{
return;
}
- std::ifstream ifs(ofile.c_str());
+ cmsys::ifstream ifs(ofile.c_str());
if ( !ifs )
{
std::string log = "Cannot read memory tester output file: " + ofile;
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 76ddeea..ddd1707 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -17,6 +17,7 @@
#include <stdlib.h>
#include <stack>
#include <float.h>
+#include <cmsys/FStream.hxx>
class TestComparator
{
@@ -41,6 +42,7 @@ cmCTestMultiProcessHandler::cmCTestMultiProcessHandler()
this->Completed = 0;
this->RunningCount = 0;
this->StopTimePassed = false;
+ this->HasCycles = false;
}
cmCTestMultiProcessHandler::~cmCTestMultiProcessHandler()
@@ -65,6 +67,11 @@ cmCTestMultiProcessHandler::SetTests(TestMap& tests,
if(!this->CTest->GetShowOnly())
{
this->ReadCostData();
+ this->HasCycles = !this->CheckCycles();
+ if(this->HasCycles)
+ {
+ return;
+ }
this->CreateTestCostList();
}
}
@@ -79,7 +86,7 @@ void cmCTestMultiProcessHandler::SetParallelLevel(size_t level)
void cmCTestMultiProcessHandler::RunTests()
{
this->CheckResume();
- if(!this->CheckCycles())
+ if(this->HasCycles)
{
return;
}
@@ -133,6 +140,13 @@ void cmCTestMultiProcessHandler::StartTestProcess(int test)
}
else
{
+
+ for(TestMap::iterator j = this->Tests.begin();
+ j != this->Tests.end(); ++j)
+ {
+ j->second.erase(test);
+ }
+
this->UnlockResources(test);
this->Completed++;
this->TestFinishMap[test] = true;
@@ -205,37 +219,8 @@ bool cmCTestMultiProcessHandler::StartTest(int test)
}
}
- // copy the depend tests locally because when
- // a test is finished it will be removed from the depend list
- // and we don't want to be iterating a list while removing from it
- TestSet depends = this->Tests[test];
- size_t totalDepends = depends.size();
- if(totalDepends)
- {
- for(TestSet::const_iterator i = depends.begin();
- i != depends.end(); ++i)
- {
- // if the test is not already running then start it
- if(!this->TestRunningMap[*i])
- {
- // this test might be finished, but since
- // this is a copy of the depend map we might
- // still have it
- if(!this->TestFinishMap[*i])
- {
- // only start one test in this function
- return this->StartTest(*i);
- }
- else
- {
- // the depend has been and finished
- totalDepends--;
- }
- }
- }
- }
// if there are no depends left then run this test
- if(totalDepends == 0)
+ if(this->Tests[test].empty())
{
this->StartTestProcess(test);
return true;
@@ -262,25 +247,17 @@ void cmCTestMultiProcessHandler::StartNextTests()
TestList copy = this->SortedTests;
for(TestList::iterator test = copy.begin(); test != copy.end(); ++test)
{
- //in case this test has already been started due to dependency
- if(this->TestRunningMap[*test] || this->TestFinishMap[*test])
- {
- continue;
- }
size_t processors = GetProcessorsUsed(*test);
- if(processors > numToStart)
- {
- return;
- }
- if(this->StartTest(*test))
+
+ if(processors <= numToStart && this->StartTest(*test))
{
- if(this->StopTimePassed)
- {
- return;
- }
- numToStart -= processors;
+ if(this->StopTimePassed)
+ {
+ return;
+ }
+ numToStart -= processors;
}
- if(numToStart == 0)
+ else if(numToStart == 0)
{
return;
}
@@ -349,7 +326,7 @@ void cmCTestMultiProcessHandler::UpdateCostData()
if(cmSystemTools::FileExists(fname.c_str()))
{
- std::ifstream fin;
+ cmsys::ifstream fin;
fin.open(fname.c_str());
std::string line;
@@ -408,7 +385,7 @@ void cmCTestMultiProcessHandler::ReadCostData()
if(cmSystemTools::FileExists(fname.c_str(), true))
{
- std::ifstream fin;
+ cmsys::ifstream fin;
fin.open(fname.c_str());
std::string line;
while(std::getline(fin, line))
@@ -472,24 +449,160 @@ int cmCTestMultiProcessHandler::SearchByName(std::string name)
//---------------------------------------------------------
void cmCTestMultiProcessHandler::CreateTestCostList()
{
- for(TestMap::iterator i = this->Tests.begin();
- i != this->Tests.end(); ++i)
+ if(this->ParallelLevel > 1)
{
- SortedTests.push_back(i->first);
+ CreateParallelTestCostList();
+ }
+ else
+ {
+ CreateSerialTestCostList();
+ }
+}
- //If the test failed last time, it should be run first, so max the cost.
- //Only do this for parallel runs; in non-parallel runs, avoid clobbering
- //the test's explicitly set cost.
- if(this->ParallelLevel > 1 &&
- std::find(this->LastTestsFailed.begin(), this->LastTestsFailed.end(),
+//---------------------------------------------------------
+void cmCTestMultiProcessHandler::CreateParallelTestCostList()
+{
+ TestSet alreadySortedTests;
+
+ std::list<TestSet> priorityStack;
+ priorityStack.push_back(TestSet());
+ TestSet &topLevel = priorityStack.back();
+
+ // In parallel test runs add previously failed tests to the front
+ // of the cost list and queue other tests for further sorting
+ for(TestMap::const_iterator i = this->Tests.begin();
+ i != this->Tests.end(); ++i)
+ {
+ if(std::find(this->LastTestsFailed.begin(), this->LastTestsFailed.end(),
this->Properties[i->first]->Name) != this->LastTestsFailed.end())
{
- this->Properties[i->first]->Cost = FLT_MAX;
+ //If the test failed last time, it should be run first.
+ this->SortedTests.push_back(i->first);
+ alreadySortedTests.insert(i->first);
+ }
+ else
+ {
+ topLevel.insert(i->first);
}
}
+ // In parallel test runs repeatedly move dependencies of the tests on
+ // the current dependency level to the next level until no
+ // further dependencies exist.
+ while(priorityStack.back().size())
+ {
+ TestSet &previousSet = priorityStack.back();
+ priorityStack.push_back(TestSet());
+ TestSet &currentSet = priorityStack.back();
+
+ for(TestSet::const_iterator i = previousSet.begin();
+ i != previousSet.end(); ++i)
+ {
+ TestSet const& dependencies = this->Tests[*i];
+ for(TestSet::const_iterator j = dependencies.begin();
+ j != dependencies.end(); ++j)
+ {
+ currentSet.insert(*j);
+ }
+ }
+
+ for(TestSet::const_iterator i = currentSet.begin();
+ i != currentSet.end(); ++i)
+ {
+ previousSet.erase(*i);
+ }
+ }
+
+ // Remove the empty dependency level
+ priorityStack.pop_back();
+
+ // Reverse iterate over the different dependency levels (deepest first).
+ // Sort tests within each level by COST and append them to the cost list.
+ for(std::list<TestSet>::reverse_iterator i = priorityStack.rbegin();
+ i != priorityStack.rend(); ++i)
+ {
+ TestSet const& currentSet = *i;
+ TestComparator comp(this);
+
+ TestList sortedCopy;
+
+ for(TestSet::const_iterator j = currentSet.begin();
+ j != currentSet.end(); ++j)
+ {
+ sortedCopy.push_back(*j);
+ }
+
+ std::stable_sort(sortedCopy.begin(), sortedCopy.end(), comp);
+
+ for(TestList::const_iterator j = sortedCopy.begin();
+ j != sortedCopy.end(); ++j)
+ {
+ if(alreadySortedTests.find(*j) == alreadySortedTests.end())
+ {
+ this->SortedTests.push_back(*j);
+ alreadySortedTests.insert(*j);
+ }
+ }
+ }
+}
+
+//---------------------------------------------------------
+void cmCTestMultiProcessHandler::GetAllTestDependencies(
+ int test, TestList& dependencies)
+{
+ TestSet const& dependencySet = this->Tests[test];
+ for(TestSet::const_iterator i = dependencySet.begin();
+ i != dependencySet.end(); ++i)
+ {
+ GetAllTestDependencies(*i, dependencies);
+ dependencies.push_back(*i);
+ }
+}
+
+//---------------------------------------------------------
+void cmCTestMultiProcessHandler::CreateSerialTestCostList()
+{
+ TestList presortedList;
+
+ for(TestMap::iterator i = this->Tests.begin();
+ i != this->Tests.end(); ++i)
+ {
+ presortedList.push_back(i->first);
+ }
+
TestComparator comp(this);
- std::stable_sort(SortedTests.begin(), SortedTests.end(), comp);
+ std::stable_sort(presortedList.begin(), presortedList.end(), comp);
+
+ TestSet alreadySortedTests;
+
+ for(TestList::const_iterator i = presortedList.begin();
+ i != presortedList.end(); ++i)
+ {
+ int test = *i;
+
+ if(alreadySortedTests.find(test) != alreadySortedTests.end())
+ {
+ continue;
+ }
+
+ TestList dependencies;
+ GetAllTestDependencies(test, dependencies);
+
+ for(TestList::const_iterator j = dependencies.begin();
+ j != dependencies.end(); ++j)
+ {
+ int testDependency = *j;
+
+ if(alreadySortedTests.find(testDependency) == alreadySortedTests.end())
+ {
+ alreadySortedTests.insert(testDependency);
+ this->SortedTests.push_back(testDependency);
+ }
+ }
+
+ alreadySortedTests.insert(test);
+ this->SortedTests.push_back(test);
+ }
}
//---------------------------------------------------------
@@ -609,7 +722,7 @@ void cmCTestMultiProcessHandler::CheckResume()
<< "----------------------------------------------------------"
<< std::endl;
- std::ifstream fin;
+ cmsys::ifstream fin;
fin.open(fname.c_str());
std::string line;
while(std::getline(fin, line))
diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h
index cd21d91..1b53ec7 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.h
+++ b/Source/CTest/cmCTestMultiProcessHandler.h
@@ -72,6 +72,12 @@ protected:
int SearchByName(std::string name);
void CreateTestCostList();
+
+ void GetAllTestDependencies(int test, TestList& dependencies);
+ void CreateSerialTestCostList();
+
+ void CreateParallelTestCostList();
+
// Removes the checkpoint file
void MarkFinished();
void EraseTest(int index);
@@ -111,6 +117,7 @@ protected:
std::set<cmCTestRunTest*> RunningTests; // current running tests
cmCTestTestHandler * TestHandler;
cmCTest* CTest;
+ bool HasCycles;
};
#endif
diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx
new file mode 100644
index 0000000..0058721
--- /dev/null
+++ b/Source/CTest/cmCTestP4.cxx
@@ -0,0 +1,559 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2013 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 "cmCTestP4.h"
+
+#include "cmCTest.h"
+#include "cmSystemTools.h"
+#include "cmXMLSafe.h"
+
+#include <cmsys/RegularExpression.hxx>
+#include <cmsys/ios/sstream>
+#include <cmsys/Process.h>
+
+#include <sys/types.h>
+#include <time.h>
+#include <ctype.h>
+
+//----------------------------------------------------------------------------
+cmCTestP4::cmCTestP4(cmCTest* ct, std::ostream& log):
+ cmCTestGlobalVC(ct, log)
+{
+ this->PriorRev = this->Unknown;
+}
+
+//----------------------------------------------------------------------------
+cmCTestP4::~cmCTestP4()
+{
+}
+
+//----------------------------------------------------------------------------
+class cmCTestP4::IdentifyParser: public cmCTestVC::LineParser
+{
+public:
+ IdentifyParser(cmCTestP4* p4, const char* prefix,
+ std::string& rev): Rev(rev)
+ {
+ this->SetLog(&p4->Log, prefix);
+ this->RegexIdentify.compile("^Change ([0-9]+) on");
+ }
+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 cmCTestP4::ChangesParser: public cmCTestVC::LineParser
+{
+public:
+ ChangesParser(cmCTestP4* p4, const char* prefix) : P4(p4)
+ {
+ this->SetLog(&P4->Log, prefix);
+ this->RegexIdentify.compile("^Change ([0-9]+) on");
+ }
+private:
+ cmsys::RegularExpression RegexIdentify;
+ cmCTestP4* P4;
+
+ bool ProcessLine()
+ {
+ if(this->RegexIdentify.find(this->Line))
+ {
+ P4->ChangeLists.push_back(this->RegexIdentify.match(1));
+ }
+ return true;
+ }
+};
+
+//----------------------------------------------------------------------------
+class cmCTestP4::UserParser: public cmCTestVC::LineParser
+{
+public:
+ UserParser(cmCTestP4* p4, const char* prefix) : P4(p4)
+ {
+ this->SetLog(&P4->Log, prefix);
+ this->RegexUser.compile("^(.+) <(.*)> \\((.*)\\) accessed (.*)$");
+ }
+private:
+ cmsys::RegularExpression RegexUser;
+ cmCTestP4* P4;
+
+ bool ProcessLine()
+ {
+ if(this->RegexUser.find(this->Line))
+ {
+ User NewUser;
+
+ NewUser.UserName = this->RegexUser.match(1);
+ NewUser.EMail = this->RegexUser.match(2);
+ NewUser.Name = this->RegexUser.match(3);
+ NewUser.AccessTime = this->RegexUser.match(4);
+ P4->Users[this->RegexUser.match(1)] = NewUser;
+
+ return false;
+ }
+ return true;
+ }
+};
+
+//----------------------------------------------------------------------------
+/* Diff format:
+==== //depot/file#rev - /absolute/path/to/file ====
+(diff data)
+==== //depot/file2#rev - /absolute/path/to/file2 ====
+(diff data)
+==== //depot/file3#rev - /absolute/path/to/file3 ====
+==== //depot/file4#rev - /absolute/path/to/file4 ====
+(diff data)
+*/
+class cmCTestP4::DiffParser: public cmCTestVC::LineParser
+{
+public:
+ DiffParser(cmCTestP4* p4, const char* prefix)
+ : P4(p4), AlreadyNotified(false)
+ {
+ this->SetLog(&P4->Log, prefix);
+ this->RegexDiff.compile("^==== (.*)#[0-9]+ - (.*)");
+ }
+private:
+ cmCTestP4* P4;
+ bool AlreadyNotified;
+ std::string CurrentPath;
+ cmsys::RegularExpression RegexDiff;
+
+ bool ProcessLine()
+ {
+ if(!this->Line.empty() && this->Line[0] == '='
+ && this->RegexDiff.find(this->Line))
+ {
+ CurrentPath = this->RegexDiff.match(1);
+ AlreadyNotified = false;
+ }
+ else
+ {
+ if(!AlreadyNotified)
+ {
+ P4->DoModification(PathModified, CurrentPath);
+ AlreadyNotified = true;
+ }
+ }
+ return true;
+ }
+};
+
+//----------------------------------------------------------------------------
+cmCTestP4::User cmCTestP4::GetUserData(const std::string& username)
+{
+ std::map<std::string, cmCTestP4::User>::const_iterator it =
+ Users.find(username);
+
+ if(it == Users.end())
+ {
+ std::vector<char const*> p4_users;
+ SetP4Options(p4_users);
+ p4_users.push_back("users");
+ p4_users.push_back("-m");
+ p4_users.push_back("1");
+ p4_users.push_back(username.c_str());
+ p4_users.push_back(0);
+
+ UserParser out(this, "users-out> ");
+ OutputLogger err(this->Log, "users-err> ");
+ RunChild(&p4_users[0], &out, &err);
+
+ // The user should now be added to the map. Search again.
+ it = Users.find(username);
+ if(it == Users.end())
+ {
+ return cmCTestP4::User();
+ }
+ }
+
+ return it->second;
+}
+
+//----------------------------------------------------------------------------
+/* Commit format:
+
+Change 1111111 by user@client on 2013/09/26 11:50:36
+
+ text
+ text
+
+Affected files ...
+
+... //path/to/file#rev edit
+... //path/to/file#rev add
+... //path/to/file#rev delete
+... //path/to/file#rev integrate
+*/
+class cmCTestP4::DescribeParser: public cmCTestVC::LineParser
+{
+public:
+ DescribeParser(cmCTestP4* p4, const char* prefix):
+ LineParser('\n', false), P4(p4), Section(SectionHeader)
+ {
+ this->SetLog(&P4->Log, prefix);
+ this->RegexHeader.compile("^Change ([0-9]+) by (.+)@(.+) on (.*)$");
+ this->RegexDiff.compile("^\\.\\.\\. (.*)#[0-9]+ ([^ ]+)$");
+ }
+private:
+ cmsys::RegularExpression RegexHeader;
+ cmsys::RegularExpression RegexDiff;
+ cmCTestP4* P4;
+
+ typedef cmCTestP4::Revision Revision;
+ typedef cmCTestP4::Change Change;
+ std::vector<Change> Changes;
+ enum SectionType { SectionHeader, SectionBody, SectionDiffHeader,
+ SectionDiff, SectionCount };
+ SectionType Section;
+ Revision Rev;
+
+ virtual bool ProcessLine()
+ {
+ if(this->Line.empty())
+ {
+ this->NextSection();
+ }
+ else
+ {
+ switch(this->Section)
+ {
+ case SectionHeader: this->DoHeaderLine(); break;
+ case SectionBody: this->DoBodyLine(); break;
+ case SectionDiffHeader: break; // nothing to do
+ case SectionDiff: this->DoDiffLine(); break;
+ case SectionCount: break; // never happens
+ }
+ }
+ return true;
+ }
+
+ void NextSection()
+ {
+ if(this->Section == SectionDiff)
+ {
+ this->P4->DoRevision(this->Rev, this->Changes);
+ this->Rev = Revision();
+ }
+
+ this->Section = SectionType((this->Section+1) % SectionCount);
+ }
+
+ void DoHeaderLine()
+ {
+ if(this->RegexHeader.find(this->Line))
+ {
+ this->Rev.Rev = this->RegexHeader.match(1);
+ this->Rev.Date = this->RegexHeader.match(4);
+
+ cmCTestP4::User user = P4->GetUserData(this->RegexHeader.match(2));
+ this->Rev.Author = user.Name;
+ this->Rev.EMail = user.EMail;
+
+ this->Rev.Committer = this->Rev.Author;
+ this->Rev.CommitterEMail = this->Rev.EMail;
+ this->Rev.CommitDate = this->Rev.Date;
+ }
+ }
+
+ void DoBodyLine()
+ {
+ if(this->Line[0] == '\t')
+ {
+ this->Rev.Log += this->Line.substr(1);
+ }
+ this->Rev.Log += "\n";
+ }
+
+ void DoDiffLine()
+ {
+ if(this->RegexDiff.find(this->Line))
+ {
+ Change change;
+ std::string Path = this->RegexDiff.match(1);
+ if(Path.length() > 2 && Path[0] == '/' && Path[1] == '/')
+ {
+ size_t found = Path.find('/', 2);
+ if(found != std::string::npos)
+ {
+ Path = Path.substr(found + 1);
+ }
+ }
+
+ change.Path = Path;
+ std::string action = this->RegexDiff.match(2);
+
+ if(action == "add")
+ {
+ change.Action = 'A';
+ }
+ else if(action == "delete")
+ {
+ change.Action = 'D';
+ }
+ else if(action == "edit" || action == "integrate")
+ {
+ change.Action = 'M';
+ }
+
+ Changes.push_back(change);
+ }
+ }
+};
+
+//----------------------------------------------------------------------------
+void cmCTestP4::SetP4Options(std::vector<char const*> &CommandOptions)
+{
+ if(P4Options.size() == 0)
+ {
+ const char* p4 = this->CommandLineTool.c_str();
+ P4Options.push_back(p4);
+
+ //The CTEST_P4_CLIENT variable sets the P4 client used when issuing
+ //Perforce commands, if it's different from the default one.
+ std::string client = this->CTest->GetCTestConfiguration("P4Client");
+ if(!client.empty())
+ {
+ P4Options.push_back("-c");
+ P4Options.push_back(client);
+ }
+
+ //Set the message language to be English, in case the P4 admin
+ //has localized them
+ P4Options.push_back("-L");
+ P4Options.push_back("en");
+
+ //The CTEST_P4_OPTIONS variable adds additional Perforce command line
+ //options before the main command
+ std::string opts = this->CTest->GetCTestConfiguration("P4Options");
+ std::vector<cmStdString> args =
+ cmSystemTools::ParseArguments(opts.c_str());
+
+ for(std::vector<cmStdString>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai)
+ {
+ P4Options.push_back(ai->c_str());
+ }
+ }
+
+ CommandOptions.clear();
+ for(std::vector<std::string>::iterator i = P4Options.begin();
+ i != P4Options.end(); ++i)
+ {
+ CommandOptions.push_back(i->c_str());
+ }
+}
+
+//----------------------------------------------------------------------------
+std::string cmCTestP4::GetWorkingRevision()
+{
+ std::vector<char const*> p4_identify;
+ SetP4Options(p4_identify);
+
+ p4_identify.push_back("changes");
+ p4_identify.push_back("-m");
+ p4_identify.push_back("1");
+ p4_identify.push_back("-t");
+
+ std::string source = this->SourceDirectory + "/...#have";
+ p4_identify.push_back(source.c_str());
+ p4_identify.push_back(0);
+
+ std::string rev;
+ IdentifyParser out(this, "rev-out> ", rev);
+ OutputLogger err(this->Log, "rev-err> ");
+
+ RunChild(&p4_identify[0], &out, &err);
+
+ if(rev.empty())
+ {
+ return "0";
+ }
+ else
+ {
+ return rev;
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmCTestP4::NoteOldRevision()
+{
+ this->OldRevision = this->GetWorkingRevision();
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " Old revision of repository is: "
+ << this->OldRevision << "\n");
+ this->PriorRev.Rev = this->OldRevision;
+}
+
+//----------------------------------------------------------------------------
+void cmCTestP4::NoteNewRevision()
+{
+ this->NewRevision = this->GetWorkingRevision();
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " New revision of repository is: "
+ << this->NewRevision << "\n");
+}
+
+//----------------------------------------------------------------------------
+void cmCTestP4::LoadRevisions()
+{
+ std::vector<char const*> p4_changes;
+ SetP4Options(p4_changes);
+
+ // Use 'p4 changes ...@old,new' to get a list of changelists
+ std::string range = this->SourceDirectory + "/...";
+
+ if(this->OldRevision != "0")
+ {
+ range.append("@").append(this->OldRevision);
+ }
+
+ if(this->NewRevision != "0")
+ {
+ if(this->OldRevision != "0")
+ {
+ range.append(",").append(this->NewRevision);
+ }
+ else
+ {
+ range.append("@").append(this->NewRevision);
+ }
+ }
+
+ p4_changes.push_back("changes");
+ p4_changes.push_back(range.c_str());
+ p4_changes.push_back(0);
+
+ ChangesParser out(this, "changes-out> ");
+ OutputLogger err(this->Log, "changes-err> ");
+
+ ChangeLists.clear();
+ this->RunChild(&p4_changes[0], &out, &err);
+
+ if(ChangeLists.size() == 0)
+ return;
+
+ //p4 describe -s ...@1111111,2222222
+ std::vector<char const*> p4_describe;
+ for(std::vector<std::string>::reverse_iterator i = ChangeLists.rbegin();
+ i != ChangeLists.rend(); ++i)
+ {
+ SetP4Options(p4_describe);
+ p4_describe.push_back("describe");
+ p4_describe.push_back("-s");
+ p4_describe.push_back(i->c_str());
+ p4_describe.push_back(0);
+
+ DescribeParser outDescribe(this, "describe-out> ");
+ OutputLogger errDescribe(this->Log, "describe-err> ");
+ this->RunChild(&p4_describe[0], &outDescribe, &errDescribe);
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmCTestP4::LoadModifications()
+{
+ std::vector<char const*> p4_diff;
+ SetP4Options(p4_diff);
+
+ p4_diff.push_back("diff");
+
+ //Ideally we would use -Od but not all clients support it
+ p4_diff.push_back("-dn");
+ std::string source = this->SourceDirectory + "/...";
+ p4_diff.push_back(source.c_str());
+ p4_diff.push_back(0);
+
+ DiffParser out(this, "diff-out> ");
+ OutputLogger err(this->Log, "diff-err> ");
+ this->RunChild(&p4_diff[0], &out, &err);
+}
+
+//----------------------------------------------------------------------------
+bool cmCTestP4::UpdateCustom(const std::string& custom)
+{
+ std::vector<std::string> p4_custom_command;
+ cmSystemTools::ExpandListArgument(custom, p4_custom_command, true);
+
+ std::vector<char const*> p4_custom;
+ for(std::vector<std::string>::const_iterator
+ i = p4_custom_command.begin(); i != p4_custom_command.end(); ++i)
+ {
+ p4_custom.push_back(i->c_str());
+ }
+ p4_custom.push_back(0);
+
+ OutputLogger custom_out(this->Log, "custom-out> ");
+ OutputLogger custom_err(this->Log, "custom-err> ");
+
+ return this->RunUpdateCommand(&p4_custom[0], &custom_out, &custom_err);
+}
+
+//----------------------------------------------------------------------------
+bool cmCTestP4::UpdateImpl()
+{
+ std::string custom = this->CTest->GetCTestConfiguration("P4UpdateCustom");
+ if(!custom.empty())
+ {
+ return this->UpdateCustom(custom);
+ }
+
+ std::vector<char const*> p4_sync;
+ SetP4Options(p4_sync);
+
+ p4_sync.push_back("sync");
+
+ // Get user-specified update options.
+ std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
+ if(opts.empty())
+ {
+ opts = this->CTest->GetCTestConfiguration("P4UpdateOptions");
+ }
+ std::vector<cmStdString> args = cmSystemTools::ParseArguments(opts.c_str());
+ for(std::vector<cmStdString>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai)
+ {
+ p4_sync.push_back(ai->c_str());
+ }
+
+ std::string source = this->SourceDirectory + "/...";
+
+ // Specify the start time for nightly testing.
+ if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
+ {
+ std::string date = this->GetNightlyTime();
+ //CTest reports the date as YYYY-MM-DD, Perforce needs it as YYYY/MM/DD
+ std::replace(date.begin(), date.end(), '-', '/');
+
+ //Revision specification: /...@"YYYY/MM/DD HH:MM:SS"
+ source.append("@\"").append(date).append("\"");
+ }
+
+ p4_sync.push_back(source.c_str());
+ p4_sync.push_back(0);
+
+ OutputLogger out(this->Log, "sync-out> ");
+ OutputLogger err(this->Log, "sync-err> ");
+
+ return this->RunUpdateCommand(&p4_sync[0], &out, &err);
+}
diff --git a/Source/CTest/cmCTestP4.h b/Source/CTest/cmCTestP4.h
new file mode 100644
index 0000000..7a53475
--- /dev/null
+++ b/Source/CTest/cmCTestP4.h
@@ -0,0 +1,71 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2013 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.
+============================================================================*/
+#ifndef cmCTestP4_h
+#define cmCTestP4_h
+
+#include "cmCTestGlobalVC.h"
+#include <vector>
+#include <map>
+
+/** \class cmCTestP4
+ * \brief Interaction with the Perforce command-line tool
+ *
+ */
+class cmCTestP4: public cmCTestGlobalVC
+{
+public:
+ /** Construct with a CTest instance and update log stream. */
+ cmCTestP4(cmCTest* ctest, std::ostream& log);
+
+ virtual ~cmCTestP4();
+
+private:
+ std::vector<std::string> ChangeLists;
+
+ struct User
+ {
+ std::string UserName;
+ std::string Name;
+ std::string EMail;
+ std::string AccessTime;
+
+ User(): UserName(), Name(), EMail(), AccessTime() {}
+ };
+ std::map<std::string, User> Users;
+ std::vector<std::string> P4Options;
+
+ User GetUserData(const std::string& username);
+ void SetP4Options(std::vector<char const*> &options);
+
+ std::string GetWorkingRevision();
+ virtual void NoteOldRevision();
+ virtual void NoteNewRevision();
+ virtual bool UpdateImpl();
+ bool UpdateCustom(const std::string& custom);
+
+ void LoadRevisions();
+ void LoadModifications();
+
+ // Parsing helper classes.
+ class IdentifyParser;
+ class ChangesParser;
+ class UserParser;
+ class DescribeParser;
+ class DiffParser;
+ friend class IdentifyParser;
+ friend class ChangesParser;
+ friend class UserParser;
+ friend class DescribeParser;
+ friend class DiffParser;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.h b/Source/CTest/cmCTestReadCustomFilesCommand.h
index b984c84..9c0af81 100644
--- a/Source/CTest/cmCTestReadCustomFilesCommand.h
+++ b/Source/CTest/cmCTestReadCustomFilesCommand.h
@@ -48,25 +48,6 @@ public:
*/
virtual const char* GetName() const { return "ctest_read_custom_files";}
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "read CTestCustom files.";
- }
-
- /**
- * More documentation.
- */
- virtual const char* GetFullDocumentation() const
- {
- return
- " ctest_read_custom_files( directory ... )\n"
- "Read all the CTestCustom.ctest or CTestCustom.cmake files from "
- "the given directory.";
- }
-
cmTypeMacro(cmCTestReadCustomFilesCommand, cmCTestCommand);
};
diff --git a/Source/CTest/cmCTestRunScriptCommand.h b/Source/CTest/cmCTestRunScriptCommand.h
index 05e7899..f34bd13 100644
--- a/Source/CTest/cmCTestRunScriptCommand.h
+++ b/Source/CTest/cmCTestRunScriptCommand.h
@@ -49,30 +49,6 @@ public:
*/
virtual const char* GetName() const { return "ctest_run_script";}
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "runs a ctest -S script";
- }
-
- /**
- * More documentation.
- */
- virtual const char* GetFullDocumentation() const
- {
- return
- " ctest_run_script([NEW_PROCESS] script_file_name script_file_name1 \n"
- " script_file_name2 ... [RETURN_VALUE var])\n"
- "Runs a script or scripts much like if it was run from ctest -S. "
- "If no argument is provided then the current script is run using "
- "the current settings of the variables. If NEW_PROCESS is specified "
- "then each script will be run in a separate process."
- "If RETURN_VALUE is specified the return value of the last script "
- "run will be put into var.";
- }
-
cmTypeMacro(cmCTestRunScriptCommand, cmCTestCommand);
};
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 0e2fa41..cdf90b9 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -206,7 +206,13 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
bool success =
!forceFail && (retVal == 0 ||
this->TestProperties->RequiredRegularExpressions.size());
- if((success && !this->TestProperties->WillFail)
+ if(this->TestProperties->SkipReturnCode >= 0
+ && this->TestProperties->SkipReturnCode == retVal)
+ {
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Skipped ");
+ }
+ else if((success && !this->TestProperties->WillFail)
|| (!success && this->TestProperties->WillFail))
{
this->TestResult.Status = cmCTestTestHandler::COMPLETED;
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 8643cb3..00a0a09 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -22,6 +22,7 @@
//#include <cmsys/RegularExpression.hxx>
#include <cmsys/Process.h>
+#include <cmsys/Directory.hxx>
// used for sleep
#ifdef _WIN32
@@ -221,13 +222,13 @@ int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
// execute the script passing in the arguments to the script as well as the
// arguments from this invocation of cmake
std::vector<const char*> argv;
- argv.push_back(this->CTest->GetCTestExecutable());
+ argv.push_back(cmSystemTools::GetCTestCommand().c_str());
argv.push_back("-SR");
argv.push_back(total_script_arg.c_str());
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Executable for CTest is: " <<
- this->CTest->GetCTestExecutable() << "\n");
+ cmSystemTools::GetCTestCommand() << "\n");
// now pass through all the other arguments
std::vector<cmStdString> &initArgs =
@@ -361,12 +362,6 @@ void cmCTestScriptHandler::CreateCMake()
this->AddCTestCommand(new cmCTestUploadCommand);
}
-void cmCTestScriptHandler::GetCommandDocumentation(
- std::vector<cmDocumentationEntry>& v) const
-{
- this->CMake->GetCommandDocumentation(v);
-}
-
//----------------------------------------------------------------------
// this sets up some variables for the script to use, creates the required
// cmake instance and generators, and then reads in the script
@@ -402,9 +397,9 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
this->Makefile->AddDefinition("CTEST_SCRIPT_NAME",
cmSystemTools::GetFilenameName(script).c_str());
this->Makefile->AddDefinition("CTEST_EXECUTABLE_NAME",
- this->CTest->GetCTestExecutable());
+ cmSystemTools::GetCTestCommand().c_str());
this->Makefile->AddDefinition("CMAKE_EXECUTABLE_NAME",
- this->CTest->GetCMakeExecutable());
+ cmSystemTools::GetCMakeCommand().c_str());
this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", true);
this->UpdateElapsedTime();
@@ -1062,15 +1057,71 @@ bool cmCTestScriptHandler::EmptyBinaryDirectory(const char *sname)
return false;
}
+ // consider non existing target directory a success
+ if(!cmSystemTools::FileExists(sname))
+ {
+ return true;
+ }
+
// try to avoid deleting directories that we shouldn't
std::string check = sname;
check += "/CMakeCache.txt";
- if(cmSystemTools::FileExists(check.c_str()) &&
- !cmSystemTools::RemoveADirectory(sname))
+
+ if(!cmSystemTools::FileExists(check.c_str()))
{
return false;
}
- return true;
+
+ for(int i = 0; i < 5; ++i)
+ {
+ if(TryToRemoveBinaryDirectoryOnce(sname))
+ {
+ return true;
+ }
+ cmSystemTools::Delay(100);
+ }
+
+ return false;
+}
+
+//-------------------------------------------------------------------------
+bool cmCTestScriptHandler::TryToRemoveBinaryDirectoryOnce(
+ const std::string& directoryPath)
+{
+ cmsys::Directory directory;
+ directory.Load(directoryPath.c_str());
+
+ for(unsigned long i = 0; i < directory.GetNumberOfFiles(); ++i)
+ {
+ std::string path = directory.GetFile(i);
+
+ if(path == "." || path == ".." || path == "CMakeCache.txt")
+ {
+ continue;
+ }
+
+ std::string fullPath = directoryPath + std::string("/") + path;
+
+ bool isDirectory = cmSystemTools::FileIsDirectory(fullPath.c_str()) &&
+ !cmSystemTools::FileIsSymlink(fullPath.c_str());
+
+ if(isDirectory)
+ {
+ if(!cmSystemTools::RemoveADirectory(fullPath.c_str()))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if(!cmSystemTools::RemoveFile(fullPath.c_str()))
+ {
+ return false;
+ }
+ }
+ }
+
+ return cmSystemTools::RemoveADirectory(directoryPath.c_str());
}
//-------------------------------------------------------------------------
diff --git a/Source/CTest/cmCTestScriptHandler.h b/Source/CTest/cmCTestScriptHandler.h
index 9d852ca..44e9dd0 100644
--- a/Source/CTest/cmCTestScriptHandler.h
+++ b/Source/CTest/cmCTestScriptHandler.h
@@ -110,7 +110,6 @@ public:
void Initialize();
void CreateCMake();
- void GetCommandDocumentation(std::vector<cmDocumentationEntry>& v) const;
cmake* GetCMake() { return this->CMake;}
private:
// reads in a script
@@ -136,6 +135,9 @@ private:
// Add ctest command
void AddCTestCommand(cmCTestCommand* command);
+ // Try to remove the binary directory once
+ static bool TryToRemoveBinaryDirectoryOnce(const std::string& directoryPath);
+
std::vector<cmStdString> ConfigurationScripts;
std::vector<bool> ScriptProcessScope;
diff --git a/Source/CTest/cmCTestSleepCommand.h b/Source/CTest/cmCTestSleepCommand.h
index 0f51ddf..c6baf1c 100644
--- a/Source/CTest/cmCTestSleepCommand.h
+++ b/Source/CTest/cmCTestSleepCommand.h
@@ -49,26 +49,6 @@ public:
*/
virtual const char* GetName() const { return "ctest_sleep";}
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "sleeps for some amount of time";
- }
-
- /**
- * More documentation.
- */
- virtual const char* GetFullDocumentation() const
- {
- return
- " ctest_sleep(<seconds>)\n"
- "Sleep for given number of seconds.\n"
- " ctest_sleep(<time1> <duration> <time2>)\n"
- "Sleep for t=(time1 + duration - time2) seconds if t > 0.";
- }
-
cmTypeMacro(cmCTestSleepCommand, cmCTestCommand);
};
diff --git a/Source/CTest/cmCTestStartCommand.h b/Source/CTest/cmCTestStartCommand.h
index 6be4770..e5535c1 100644
--- a/Source/CTest/cmCTestStartCommand.h
+++ b/Source/CTest/cmCTestStartCommand.h
@@ -57,30 +57,6 @@ public:
*/
virtual const char* GetName() const { return "ctest_start";}
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "Starts the testing for a given model";
- }
-
- /**
- * More documentation.
- */
- virtual const char* GetFullDocumentation() const
- {
- return
- " ctest_start(Model [TRACK <track>] [APPEND] [source [binary]])\n"
- "Starts the testing for a given model. The command should be called "
- "after the binary directory is initialized. If the 'source' and "
- "'binary' directory are not specified, it reads the "
- "CTEST_SOURCE_DIRECTORY and CTEST_BINARY_DIRECTORY. If the track is "
- "specified, the submissions will go to the specified track. "
- "If APPEND is used, the existing TAG is used rather than "
- "creating a new one based on the current time stamp.";
- }
-
cmTypeMacro(cmCTestStartCommand, cmCTestCommand);
private:
diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h
index 53ee875..64c6cae 100644
--- a/Source/CTest/cmCTestSubmitCommand.h
+++ b/Source/CTest/cmCTestSubmitCommand.h
@@ -50,44 +50,6 @@ public:
*/
virtual const char* GetName() const { return "ctest_submit";}
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "Submit results to a dashboard server.";
- }
-
- /**
- * More documentation.
- */
- virtual const char* GetFullDocumentation() const
- {
- return
- " ctest_submit([PARTS ...] [FILES ...] [RETRY_COUNT count] "
- " [RETRY_DELAY delay][RETURN_VALUE res])\n"
- "By default all available parts are submitted if no PARTS or FILES "
- "are specified. "
- "The PARTS option lists a subset of parts to be submitted. "
- "Valid part names are:\n"
- " Start = nothing\n"
- " Update = ctest_update results, in Update.xml\n"
- " Configure = ctest_configure results, in Configure.xml\n"
- " Build = ctest_build results, in Build.xml\n"
- " Test = ctest_test results, in Test.xml\n"
- " Coverage = ctest_coverage results, in Coverage.xml\n"
- " MemCheck = ctest_memcheck results, in DynamicAnalysis.xml\n"
- " Notes = Files listed by CTEST_NOTES_FILES, in Notes.xml\n"
- " ExtraFiles = Files listed by CTEST_EXTRA_SUBMIT_FILES\n"
- " Submit = nothing\n"
- "The FILES option explicitly lists specific files to be submitted. "
- "Each individual file must exist at the time of the call.\n"
- "The RETRY_DELAY option specifies how long in seconds to wait after "
- "a timed-out submission before attempting to re-submit.\n"
- "The RETRY_COUNT option specifies how many times to retry a timed-out "
- "submission.\n";
- }
-
cmTypeMacro(cmCTestSubmitCommand, cmCTestHandlerCommand);
protected:
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index 941d348..139f515 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -235,7 +235,7 @@ bool cmCTestSubmitHandler::SubmitUsingFTP(const cmStdString& localprefix,
return false;
}
- ftpfile = ::fopen(local_file.c_str(), "rb");
+ ftpfile = cmsys::SystemTools::Fopen(local_file.c_str(), "rb");
*this->LogFile << "\tUpload file: " << local_file.c_str() << " to "
<< upload_as.c_str() << std::endl;
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Upload file: "
@@ -476,7 +476,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix,
return false;
}
- ftpfile = ::fopen(local_file.c_str(), "rb");
+ ftpfile = cmsys::SystemTools::Fopen(local_file.c_str(), "rb");
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Upload file: "
<< local_file.c_str() << " to "
<< upload_as.c_str() << " Size: " << st.st_size << std::endl);
@@ -566,7 +566,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix,
<< count << std::endl);
::fclose(ftpfile);
- ftpfile = ::fopen(local_file.c_str(), "rb");
+ ftpfile = cmsys::SystemTools::Fopen(local_file.c_str(), "rb");
::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
chunk.clear();
@@ -998,7 +998,7 @@ bool cmCTestSubmitHandler::SubmitUsingXMLRPC(const cmStdString& localprefix,
return false;
}
size_t fileSize = static_cast<size_t>(st.st_size);
- FILE* fp = fopen(local_file.c_str(), "rb");
+ FILE* fp = cmsys::SystemTools::Fopen(local_file.c_str(), "rb");
if ( !fp )
{
cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot open file: "
diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h
index 130cb69..451ac99 100644
--- a/Source/CTest/cmCTestTestCommand.h
+++ b/Source/CTest/cmCTestTestCommand.h
@@ -41,45 +41,6 @@ public:
*/
virtual const char* GetName() const { return "ctest_test";}
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "Run tests in the project build tree.";
- }
-
- /**
- * More documentation.
- */
- virtual const char* GetFullDocumentation() const
- {
- return
- " ctest_test([BUILD build_dir] [APPEND]\n"
- " [START start number] [END end number]\n"
- " [STRIDE stride number] [EXCLUDE exclude regex ]\n"
- " [INCLUDE include regex] [RETURN_VALUE res] \n"
- " [EXCLUDE_LABEL exclude regex] \n"
- " [INCLUDE_LABEL label regex] \n"
- " [PARALLEL_LEVEL level] \n"
- " [SCHEDULE_RANDOM on] \n"
- " [STOP_TIME time of day]) \n"
- "Tests the given build directory and stores results in Test.xml. The "
- "second argument is a variable that will hold value. Optionally, "
- "you can specify the starting test number START, the ending test number "
- "END, the number of tests to skip between each test STRIDE, a regular "
- "expression for tests to run INCLUDE, or a regular expression for tests "
- "to not run EXCLUDE. EXCLUDE_LABEL and INCLUDE_LABEL are regular "
- "expression for test to be included or excluded by the test "
- "property LABEL. PARALLEL_LEVEL should be set to a positive number "
- "representing the number of tests to be run in parallel. "
- "SCHEDULE_RANDOM will launch tests in a random order, and is "
- "typically used to detect implicit test dependencies. STOP_TIME is the "
- "time of day at which the tests should all stop running."
- "\n"
- CTEST_COMMAND_APPEND_OPTION_DOCS;
- }
-
cmTypeMacro(cmCTestTestCommand, cmCTestHandlerCommand);
protected:
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index 497774d..3a04b33 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -20,6 +20,8 @@
#include <cmsys/Process.h>
#include <cmsys/RegularExpression.hxx>
#include <cmsys/Base64.h>
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
#include "cmMakefile.h"
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
@@ -60,10 +62,6 @@ public:
*/
virtual const char* GetName() const { return "subdirs";}
- // Unused methods
- virtual const char* GetTerseDocumentation() const { return ""; }
- virtual const char* GetFullDocumentation() const { return ""; }
-
cmTypeMacro(cmCTestSubdirCommand, cmCommand);
cmCTestTestHandler* TestHandler;
@@ -161,10 +159,6 @@ public:
*/
virtual const char* GetName() const { return "add_subdirectory";}
- // Unused methods
- virtual const char* GetTerseDocumentation() const { return ""; }
- virtual const char* GetFullDocumentation() const { return ""; }
-
cmTypeMacro(cmCTestAddSubdirectoryCommand, cmCommand);
cmCTestTestHandler* TestHandler;
@@ -249,11 +243,7 @@ public:
/**
* The name of the command as specified in CMakeList.txt.
*/
- virtual const char* GetName() const { return "ADD_TEST";}
-
- // Unused methods
- virtual const char* GetTerseDocumentation() const { return ""; }
- virtual const char* GetFullDocumentation() const { return ""; }
+ virtual const char* GetName() const { return "add_test";}
cmTypeMacro(cmCTestAddTestCommand, cmCommand);
@@ -297,11 +287,7 @@ public:
/**
* The name of the command as specified in CMakeList.txt.
*/
- virtual const char* GetName() const { return "SET_TESTS_PROPERTIES";}
-
- // Unused methods
- virtual const char* GetTerseDocumentation() const { return ""; }
- virtual const char* GetFullDocumentation() const { return ""; }
+ virtual const char* GetName() const { return "set_tests_properties";}
cmTypeMacro(cmCTestSetTestsPropertiesCommand, cmCommand);
@@ -537,6 +523,7 @@ int cmCTestTestHandler::ProcessHandler()
this->UseExcludeRegExp();
this->SetExcludeRegExp(val);
}
+ this->SetRerunFailed(cmSystemTools::IsOn(this->GetOption("RerunFailed")));
this->TestResults.clear();
@@ -819,6 +806,13 @@ void cmCTestTestHandler::ComputeTestList()
{
this->TestList.clear(); // clear list of test
this->GetListOfTests();
+
+ if (this->RerunFailed)
+ {
+ this->ComputeTestListForRerunFailed();
+ return;
+ }
+
cmCTestTestHandler::ListOfTests::size_type tmsize = this->TestList.size();
// how many tests are in based on RegExp?
int inREcnt = 0;
@@ -881,9 +875,47 @@ void cmCTestTestHandler::ComputeTestList()
this->TotalNumberOfTests = this->TestList.size();
// Set the TestList to the final list of all test
this->TestList = finalList;
+
+ this->UpdateMaxTestNameWidth();
+}
+
+void cmCTestTestHandler::ComputeTestListForRerunFailed()
+{
+ this->ExpandTestsToRunInformationForRerunFailed();
+
+ cmCTestTestHandler::ListOfTests::iterator it;
+ ListOfTests finalList;
+ int cnt = 0;
+ for ( it = this->TestList.begin(); it != this->TestList.end(); it ++ )
+ {
+ cnt ++;
+
+ // if this test is not in our list of tests to run, then skip it.
+ if ((this->TestsToRun.size() &&
+ std::find(this->TestsToRun.begin(), this->TestsToRun.end(), cnt)
+ == this->TestsToRun.end()))
+ {
+ continue;
+ }
+
+ it->Index = cnt;
+ finalList.push_back(*it);
+ }
+
+ // Save the total number of tests before exclusions
+ this->TotalNumberOfTests = this->TestList.size();
+
+ // Set the TestList to the list of failed tests to rerun
+ this->TestList = finalList;
+
+ this->UpdateMaxTestNameWidth();
+}
+
+void cmCTestTestHandler::UpdateMaxTestNameWidth()
+{
std::string::size_type max = this->CTest->GetMaxTestNameWidth();
- for (it = this->TestList.begin();
- it != this->TestList.end(); it ++ )
+ for ( cmCTestTestHandler::ListOfTests::iterator it = this->TestList.begin();
+ it != this->TestList.end(); it ++ )
{
cmCTestTestProperties& p = *it;
if(max < p.Name.size())
@@ -900,7 +932,7 @@ void cmCTestTestHandler::ComputeTestList()
bool cmCTestTestHandler::GetValue(const char* tag,
int& value,
- std::ifstream& fin)
+ std::istream& fin)
{
std::string line;
bool ret = true;
@@ -922,7 +954,7 @@ bool cmCTestTestHandler::GetValue(const char* tag,
bool cmCTestTestHandler::GetValue(const char* tag,
double& value,
- std::ifstream& fin)
+ std::istream& fin)
{
std::string line;
cmSystemTools::GetLineFromStream(fin, line);
@@ -944,7 +976,7 @@ bool cmCTestTestHandler::GetValue(const char* tag,
bool cmCTestTestHandler::GetValue(const char* tag,
bool& value,
- std::ifstream& fin)
+ std::istream& fin)
{
std::string line;
cmSystemTools::GetLineFromStream(fin, line);
@@ -976,7 +1008,7 @@ bool cmCTestTestHandler::GetValue(const char* tag,
bool cmCTestTestHandler::GetValue(const char* tag,
size_t& value,
- std::ifstream& fin)
+ std::istream& fin)
{
std::string line;
cmSystemTools::GetLineFromStream(fin, line);
@@ -998,7 +1030,7 @@ bool cmCTestTestHandler::GetValue(const char* tag,
bool cmCTestTestHandler::GetValue(const char* tag,
std::string& value,
- std::ifstream& fin)
+ std::istream& fin)
{
std::string line;
cmSystemTools::GetLineFromStream(fin, line);
@@ -1708,6 +1740,91 @@ void cmCTestTestHandler::ExpandTestsToRunInformation(size_t numTests)
this->TestsToRun.erase(new_end, this->TestsToRun.end());
}
+void cmCTestTestHandler::ExpandTestsToRunInformationForRerunFailed()
+{
+
+ std::string dirName = this->CTest->GetBinaryDir() + "/Testing/Temporary";
+
+ cmsys::Directory directory;
+ if (directory.Load(dirName.c_str()) == 0)
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unable to read the contents of "
+ << dirName << std::endl);
+ return;
+ }
+
+ int numFiles = static_cast<int>
+ (cmsys::Directory::GetNumberOfFilesInDirectory(dirName.c_str()));
+ std::string pattern = "LastTestsFailed";
+ std::string logName = "";
+
+ for (int i = 0; i < numFiles; ++i)
+ {
+ std::string fileName = directory.GetFile(i);
+ // bcc crashes if we attempt a normal substring comparison,
+ // hence the following workaround
+ std::string fileNameSubstring = fileName.substr(0, pattern.length());
+ if (fileNameSubstring.compare(pattern) != 0)
+ {
+ continue;
+ }
+ if (logName == "")
+ {
+ logName = fileName;
+ }
+ else
+ {
+ // if multiple matching logs were found we use the most recently
+ // modified one.
+ int res;
+ cmSystemTools::FileTimeCompare(logName.c_str(), fileName.c_str(), &res);
+ if (res == -1)
+ {
+ logName = fileName;
+ }
+ }
+ }
+
+ std::string lastTestsFailedLog = this->CTest->GetBinaryDir()
+ + "/Testing/Temporary/" + logName;
+
+ if ( !cmSystemTools::FileExists(lastTestsFailedLog.c_str()) )
+ {
+ if ( !this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels() )
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, lastTestsFailedLog
+ << " does not exist!" << std::endl);
+ }
+ return;
+ }
+
+ // parse the list of tests to rerun from LastTestsFailed.log
+ cmsys::ifstream ifs(lastTestsFailedLog.c_str());
+ if ( ifs )
+ {
+ std::string line;
+ std::string::size_type pos;
+ while ( cmSystemTools::GetLineFromStream(ifs, line) )
+ {
+ pos = line.find(':', 0);
+ if (pos == line.npos)
+ {
+ continue;
+ }
+
+ int val = atoi(line.substr(0, pos).c_str());
+ this->TestsToRun.push_back(val);
+ }
+ ifs.close();
+ }
+ else if ( !this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels() )
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Problem reading file: "
+ << lastTestsFailedLog.c_str() <<
+ " while generating list of previously failed tests." << std::endl);
+ }
+}
+
//----------------------------------------------------------------------
// Just for convenience
#define SPACE_REGEX "[ \t\r\n]"
@@ -1848,7 +1965,7 @@ std::string cmCTestTestHandler::GenerateRegressionImages(
}
else
{
- std::ifstream ifs(filename.c_str(), std::ios::in
+ cmsys::ifstream ifs(filename.c_str(), std::ios::in
#ifdef _WIN32
| std::ios::binary
#endif
@@ -1938,7 +2055,7 @@ void cmCTestTestHandler::SetTestsToRunInformation(const char* in)
// string
if(cmSystemTools::FileExists(in))
{
- std::ifstream fin(in);
+ cmsys::ifstream fin(in);
unsigned long filelen = cmSystemTools::FileLength(in);
char* buff = new char[filelen+1];
fin.getline(buff, filelen);
@@ -2112,6 +2229,14 @@ bool cmCTestTestHandler::SetTestsProperties(
rtit->Processors = 1;
}
}
+ if ( key == "SKIP_RETURN_CODE" )
+ {
+ rtit->SkipReturnCode = atoi(val.c_str());
+ if(rtit->SkipReturnCode < 0 || rtit->SkipReturnCode > 255)
+ {
+ rtit->SkipReturnCode = -1;
+ }
+ }
if ( key == "DEPENDS" )
{
std::vector<std::string> lval;
@@ -2247,6 +2372,7 @@ bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args)
test.ExplicitTimeout = false;
test.Cost = 0;
test.Processors = 1;
+ test.SkipReturnCode = -1;
test.PreviousRuns = 0;
if (this->UseIncludeRegExpFlag &&
!this->IncludeTestsRegularExpression.find(testname.c_str()))
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index 93b793b..63f9c93 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -44,6 +44,12 @@ public:
void SetUseUnion(bool val) { this->UseUnion = val; }
/**
+ * Set whether or not CTest should only execute the tests that failed
+ * on the previous run. By default this is false.
+ */
+ void SetRerunFailed(bool val) { this->RerunFailed = val; }
+
+ /**
* This method is called when reading CTest custom file
*/
void PopulateCustomVectors(cmMakefile *mf);
@@ -103,6 +109,8 @@ public:
int Index;
//Requested number of process slots
int Processors;
+ // return code of test which will mark test as "not run"
+ int SkipReturnCode;
std::vector<std::string> Environment;
std::vector<std::string> Labels;
std::set<std::string> LockedResources;
@@ -213,21 +221,27 @@ private:
// based on union regex and -I stuff
void ComputeTestList();
+ // compute the lists of tests that will actually run
+ // based on LastTestFailed.log
+ void ComputeTestListForRerunFailed();
+
+ void UpdateMaxTestNameWidth();
+
bool GetValue(const char* tag,
std::string& value,
- std::ifstream& fin);
+ std::istream& fin);
bool GetValue(const char* tag,
int& value,
- std::ifstream& fin);
+ std::istream& fin);
bool GetValue(const char* tag,
size_t& value,
- std::ifstream& fin);
+ std::istream& fin);
bool GetValue(const char* tag,
bool& value,
- std::ifstream& fin);
+ std::istream& fin);
bool GetValue(const char* tag,
double& value,
- std::ifstream& fin);
+ std::istream& fin);
/**
* Find the executable for a test
*/
@@ -235,6 +249,7 @@ private:
const char* GetTestStatus(int status);
void ExpandTestsToRunInformation(size_t numPossibleTests);
+ void ExpandTestsToRunInformationForRerunFailed();
std::vector<cmStdString> CustomPreTest;
std::vector<cmStdString> CustomPostTest;
@@ -268,6 +283,8 @@ private:
cmsys::RegularExpression DartStuff;
std::ostream* LogFile;
+
+ bool RerunFailed;
};
#endif
diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx
index 2ca9f6c..5408a8a 100644
--- a/Source/CTest/cmCTestUpdateCommand.cxx
+++ b/Source/CTest/cmCTestUpdateCommand.cxx
@@ -59,6 +59,14 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler()
"HGCommand", "CTEST_HG_COMMAND");
this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
"HGUpdateOptions", "CTEST_HG_UPDATE_OPTIONS");
+ this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
+ "P4Command", "CTEST_P4_COMMAND");
+ this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
+ "P4UpdateOptions", "CTEST_P4_UPDATE_OPTIONS");
+ this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
+ "P4Client", "CTEST_P4_CLIENT");
+ this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
+ "P4Options", "CTEST_P4_OPTIONS");
cmCTestGenericHandler* handler
= this->CTest->GetInitializedHandler("update");
diff --git a/Source/CTest/cmCTestUpdateCommand.h b/Source/CTest/cmCTestUpdateCommand.h
index c578fff..a785bd8 100644
--- a/Source/CTest/cmCTestUpdateCommand.h
+++ b/Source/CTest/cmCTestUpdateCommand.h
@@ -41,28 +41,6 @@ public:
*/
virtual const char* GetName() const { return "ctest_update";}
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "Update the work tree from version control.";
- }
-
- /**
- * More documentation.
- */
- virtual const char* GetFullDocumentation() const
- {
- return
- " ctest_update([SOURCE source] [RETURN_VALUE res])\n"
- "Updates the given source directory and stores results in Update.xml. "
- "If no SOURCE is given, the CTEST_SOURCE_DIRECTORY variable is used. "
- "The RETURN_VALUE option specifies a variable in which to store the "
- "result, which is the number of files updated or -1 on error."
- ;
- }
-
cmTypeMacro(cmCTestUpdateCommand, cmCTestHandlerCommand);
protected:
diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx
index 9eae3f3..11474ec 100644
--- a/Source/CTest/cmCTestUpdateHandler.cxx
+++ b/Source/CTest/cmCTestUpdateHandler.cxx
@@ -28,6 +28,7 @@
#include "cmCTestBZR.h"
#include "cmCTestGIT.h"
#include "cmCTestHG.h"
+#include "cmCTestP4.h"
#include <cmsys/auto_ptr.hxx>
@@ -51,7 +52,8 @@ static const char* cmCTestUpdateHandlerUpdateStrings[] =
"SVN",
"BZR",
"GIT",
- "HG"
+ "HG",
+ "P4"
};
static const char* cmCTestUpdateHandlerUpdateToString(int type)
@@ -146,6 +148,10 @@ int cmCTestUpdateHandler::DetermineType(const char* cmd, const char* type)
{
return cmCTestUpdateHandler::e_HG;
}
+ if ( stype.find("p4") != std::string::npos )
+ {
+ return cmCTestUpdateHandler::e_P4;
+ }
}
else
{
@@ -172,6 +178,10 @@ int cmCTestUpdateHandler::DetermineType(const char* cmd, const char* type)
{
return cmCTestUpdateHandler::e_HG;
}
+ if ( stype.find("p4") != std::string::npos )
+ {
+ return cmCTestUpdateHandler::e_P4;
+ }
}
return cmCTestUpdateHandler::e_UNKNOWN;
}
@@ -223,6 +233,7 @@ int cmCTestUpdateHandler::ProcessHandler()
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;
+ case e_P4: vc.reset(new cmCTestP4(this->CTest, ofs)); break;
default: vc.reset(new cmCTestVC(this->CTest, ofs)); break;
}
vc->SetCommandLineTool(this->UpdateCommand);
@@ -350,6 +361,18 @@ int cmCTestUpdateHandler::DetectVCS(const char* dir)
{
return cmCTestUpdateHandler::e_HG;
}
+ sourceDirectory = dir;
+ sourceDirectory += "/.p4";
+ if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
+ {
+ return cmCTestUpdateHandler::e_P4;
+ }
+ sourceDirectory = dir;
+ sourceDirectory += "/.p4config";
+ if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
+ {
+ return cmCTestUpdateHandler::e_P4;
+ }
return cmCTestUpdateHandler::e_UNKNOWN;
}
@@ -380,6 +403,7 @@ bool cmCTestUpdateHandler::SelectVCS()
case e_BZR: key = "BZRCommand"; break;
case e_GIT: key = "GITCommand"; break;
case e_HG: key = "HGCommand"; break;
+ case e_P4: key = "P4Command"; break;
default: break;
}
if (key)
diff --git a/Source/CTest/cmCTestUpdateHandler.h b/Source/CTest/cmCTestUpdateHandler.h
index 55ec974..954c024 100644
--- a/Source/CTest/cmCTestUpdateHandler.h
+++ b/Source/CTest/cmCTestUpdateHandler.h
@@ -44,6 +44,7 @@ public:
e_BZR,
e_GIT,
e_HG,
+ e_P4,
e_LAST
};
diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h
index 62f379f..e867fb6 100644
--- a/Source/CTest/cmCTestUploadCommand.h
+++ b/Source/CTest/cmCTestUploadCommand.h
@@ -45,25 +45,6 @@ public:
*/
virtual const char* GetName() const { return "ctest_upload";}
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "Upload files to a dashboard server.";
- }
-
- /**
- * More documentation.
- */
- virtual const char* GetFullDocumentation() const
- {
- return
- " ctest_upload(FILES ...)\n"
- "Pass a list of files to be sent along with the build results to "
- "the dashboard server.\n";
- }
-
cmTypeMacro(cmCTestUploadCommand, cmCTestHandlerCommand);
protected:
diff --git a/Source/CTest/cmParseCacheCoverage.cxx b/Source/CTest/cmParseCacheCoverage.cxx
index 137f344..85e07ae 100644
--- a/Source/CTest/cmParseCacheCoverage.cxx
+++ b/Source/CTest/cmParseCacheCoverage.cxx
@@ -5,6 +5,7 @@
#include "cmParseCacheCoverage.h"
#include <cmsys/Directory.hxx>
#include <cmsys/Glob.hxx>
+#include <cmsys/FStream.hxx>
cmParseCacheCoverage::cmParseCacheCoverage(
@@ -106,7 +107,7 @@ bool cmParseCacheCoverage::SplitString(std::vector<std::string>& args,
bool cmParseCacheCoverage::ReadCMCovFile(const char* file)
{
- std::ifstream in(file);
+ cmsys::ifstream in(file);
if(!in)
{
cmCTestLog(this->CTest, ERROR_MESSAGE,
diff --git a/Source/CTest/cmParseGTMCoverage.cxx b/Source/CTest/cmParseGTMCoverage.cxx
index 6b4adb4..528d0db 100644
--- a/Source/CTest/cmParseGTMCoverage.cxx
+++ b/Source/CTest/cmParseGTMCoverage.cxx
@@ -5,6 +5,7 @@
#include "cmParseGTMCoverage.h"
#include <cmsys/Directory.hxx>
#include <cmsys/Glob.hxx>
+#include <cmsys/FStream.hxx>
cmParseGTMCoverage::cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont,
@@ -48,7 +49,7 @@ bool cmParseGTMCoverage::LoadCoverageData(const char* d)
bool cmParseGTMCoverage::ReadMCovFile(const char* file)
{
- std::ifstream in(file);
+ cmsys::ifstream in(file);
if(!in)
{
return false;
@@ -127,7 +128,7 @@ bool cmParseGTMCoverage::FindFunctionInMumpsFile(std::string const& filepath,
std::string const& function,
int& lineoffset)
{
- std::ifstream in(filepath.c_str());
+ cmsys::ifstream in(filepath.c_str());
if(!in)
{
return false;
diff --git a/Source/CTest/cmParseMumpsCoverage.cxx b/Source/CTest/cmParseMumpsCoverage.cxx
index 37e8bd0..6226feb 100644
--- a/Source/CTest/cmParseMumpsCoverage.cxx
+++ b/Source/CTest/cmParseMumpsCoverage.cxx
@@ -5,6 +5,7 @@
#include "cmParseGTMCoverage.h"
#include <cmsys/Directory.hxx>
#include <cmsys/Glob.hxx>
+#include <cmsys/FStream.hxx>
cmParseMumpsCoverage::cmParseMumpsCoverage(
@@ -23,7 +24,7 @@ bool cmParseMumpsCoverage::ReadCoverageFile(const char* file)
// Read the gtm_coverage.mcov file, that has two lines of data:
// packages:/full/path/to/Vista/Packages
// coverage_dir:/full/path/to/dir/with/*.mcov
- std::ifstream in(file);
+ cmsys::ifstream in(file);
if(!in)
{
return false;
@@ -61,7 +62,7 @@ bool cmParseMumpsCoverage::ReadCoverageFile(const char* file)
void cmParseMumpsCoverage::InitializeMumpsFile(std::string& file)
{
// initialize the coverage information for a given mumps file
- std::ifstream in(file.c_str());
+ cmsys::ifstream in(file.c_str());
if(!in)
{
return;
diff --git a/Source/CTest/cmParsePHPCoverage.cxx b/Source/CTest/cmParsePHPCoverage.cxx
index 593b2d1..1c26c1c 100644
--- a/Source/CTest/cmParsePHPCoverage.cxx
+++ b/Source/CTest/cmParsePHPCoverage.cxx
@@ -2,6 +2,7 @@
#include "cmSystemTools.h"
#include "cmParsePHPCoverage.h"
#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
/*
To setup coverage for php.
@@ -20,7 +21,7 @@ cmParsePHPCoverage::cmParsePHPCoverage(cmCTestCoverageHandlerContainer& cont,
{
}
-bool cmParsePHPCoverage::ReadUntil(std::ifstream& in, char until)
+bool cmParsePHPCoverage::ReadUntil(std::istream& in, char until)
{
char c = 0;
while(in.get(c) && c != until)
@@ -32,7 +33,7 @@ bool cmParsePHPCoverage::ReadUntil(std::ifstream& in, char until)
}
return true;
}
-bool cmParsePHPCoverage::ReadCoverageArray(std::ifstream& in,
+bool cmParsePHPCoverage::ReadCoverageArray(std::istream& in,
cmStdString const& fileName)
{
cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector
@@ -109,7 +110,7 @@ bool cmParsePHPCoverage::ReadCoverageArray(std::ifstream& in,
return true;
}
-bool cmParsePHPCoverage::ReadInt(std::ifstream& in, int& v)
+bool cmParsePHPCoverage::ReadInt(std::istream& in, int& v)
{
std::string s;
char c = 0;
@@ -121,7 +122,7 @@ bool cmParsePHPCoverage::ReadInt(std::ifstream& in, int& v)
return true;
}
-bool cmParsePHPCoverage::ReadArraySize(std::ifstream& in, int& size)
+bool cmParsePHPCoverage::ReadArraySize(std::istream& in, int& size)
{
char c = 0;
in.get(c);
@@ -139,7 +140,7 @@ bool cmParsePHPCoverage::ReadArraySize(std::ifstream& in, int& size)
return false;
}
-bool cmParsePHPCoverage::ReadFileInformation(std::ifstream& in)
+bool cmParsePHPCoverage::ReadFileInformation(std::istream& in)
{
char buf[4];
in.read(buf, 2);
@@ -190,7 +191,7 @@ bool cmParsePHPCoverage::ReadFileInformation(std::ifstream& in)
bool cmParsePHPCoverage::ReadPHPData(const char* file)
{
- std::ifstream in(file);
+ cmsys::ifstream in(file);
if(!in)
{
return false;
diff --git a/Source/CTest/cmParsePHPCoverage.h b/Source/CTest/cmParsePHPCoverage.h
index d50a83c..035a093 100644
--- a/Source/CTest/cmParsePHPCoverage.h
+++ b/Source/CTest/cmParsePHPCoverage.h
@@ -32,11 +32,11 @@ public:
void PrintCoverage();
private:
bool ReadPHPData(const char* file);
- bool ReadArraySize(std::ifstream& in, int& size);
- bool ReadFileInformation(std::ifstream& in);
- bool ReadInt(std::ifstream& in, int& v);
- bool ReadCoverageArray(std::ifstream& in, cmStdString const&);
- bool ReadUntil(std::ifstream& in, char until);
+ bool ReadArraySize(std::istream& in, int& size);
+ bool ReadFileInformation(std::istream& in);
+ bool ReadInt(std::istream& in, int& v);
+ bool ReadCoverageArray(std::istream& in, cmStdString const&);
+ bool ReadUntil(std::istream& in, char until);
cmCTestCoverageHandlerContainer& Coverage;
cmCTest* CTest;
};
diff --git a/Source/CTest/cmParsePythonCoverage.cxx b/Source/CTest/cmParsePythonCoverage.cxx
new file mode 100644
index 0000000..38a770a
--- /dev/null
+++ b/Source/CTest/cmParsePythonCoverage.cxx
@@ -0,0 +1,113 @@
+#include "cmStandardIncludes.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include "cmParsePythonCoverage.h"
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+
+//----------------------------------------------------------------------------
+class cmParsePythonCoverage::XMLParser: public cmXMLParser
+{
+public:
+ XMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont)
+ : CTest(ctest), Coverage(cont)
+ {
+ }
+
+ virtual ~XMLParser()
+ {
+ }
+
+protected:
+
+ virtual void StartElement(const char* name, const char** atts)
+ {
+ if(strcmp(name, "class") == 0)
+ {
+ int tagCount = 0;
+ while(true)
+ {
+ if(strcmp(atts[tagCount], "filename") == 0)
+ {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Reading file: "
+ << atts[tagCount+1] << std::endl);
+ this->CurFileName = this->Coverage.SourceDir + "/" +
+ atts[tagCount+1];
+ FileLinesType& curFileLines =
+ this->Coverage.TotalCoverage[this->CurFileName];
+ cmsys::ifstream fin(this->CurFileName.c_str());
+ if(!fin)
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Python Coverage: Error opening " << this->CurFileName
+ << std::endl);
+ this->Coverage.Error++;
+ break;
+ }
+
+ std::string line;
+ curFileLines.push_back(-1);
+ while(cmSystemTools::GetLineFromStream(fin, line))
+ {
+ curFileLines.push_back(-1);
+ }
+
+ break;
+ }
+ ++tagCount;
+ }
+ }
+ else if(strcmp(name, "line") == 0)
+ {
+ int tagCount = 0;
+ int curNumber = -1;
+ int curHits = -1;
+ while(true)
+ {
+ if(strcmp(atts[tagCount], "hits") == 0)
+ {
+ curHits = atoi(atts[tagCount+1]);
+ }
+ else if(strcmp(atts[tagCount], "number") == 0)
+ {
+ curNumber = atoi(atts[tagCount+1]);
+ }
+
+ if(curHits > -1 && curNumber > -1)
+ {
+ FileLinesType& curFileLines =
+ this->Coverage.TotalCoverage[this->CurFileName];
+ curFileLines[curNumber] = curHits;
+ break;
+ }
+ ++tagCount;
+ }
+ }
+ }
+
+ virtual void EndElement(const char*) {}
+
+private:
+
+ typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector
+ FileLinesType;
+ cmCTest* CTest;
+ cmCTestCoverageHandlerContainer& Coverage;
+ std::string CurFileName;
+
+};
+
+
+cmParsePythonCoverage::cmParsePythonCoverage(
+ cmCTestCoverageHandlerContainer& cont,
+ cmCTest* ctest)
+ :Coverage(cont), CTest(ctest)
+{
+}
+
+bool cmParsePythonCoverage::ReadCoverageXML(const char* xmlFile)
+{
+ cmParsePythonCoverage::XMLParser parser(this->CTest, this->Coverage);
+ parser.ParseFile(xmlFile);
+ return true;
+}
diff --git a/Source/CTest/cmParsePythonCoverage.h b/Source/CTest/cmParsePythonCoverage.h
new file mode 100644
index 0000000..668c7f9
--- /dev/null
+++ b/Source/CTest/cmParsePythonCoverage.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ 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.
+============================================================================*/
+
+#ifndef cmParsePythonCoverage_h
+#define cmParsePythonCoverage_h
+
+#include "cmStandardIncludes.h"
+#include "cmCTestCoverageHandler.h"
+
+/** \class cmParsePythonCoverage
+ * \brief Parse coverage.py Python coverage information
+ *
+ * This class is used to parse the output of the coverage.py tool that
+ * is currently maintained by Ned Batchelder. That tool has a command
+ * that produces xml output in the format typically output by the common
+ * Java-based Cobertura coverage application. This helper class parses
+ * that XML file to fill the coverage-handler container.
+ */
+class cmParsePythonCoverage
+{
+public:
+
+ //! Create the coverage parser by passing in the coverage handler
+ //! container and the cmCTest object
+ cmParsePythonCoverage(cmCTestCoverageHandlerContainer& cont,
+ cmCTest* ctest);
+
+ //! Read the XML produced by running `coverage xml`
+ bool ReadCoverageXML(const char* xmlFile);
+
+private:
+
+ class XMLParser;
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+ std::string CurFileName;
+};
+
+#endif