summaryrefslogtreecommitdiff
path: root/Source/CTest
diff options
context:
space:
mode:
authorMyungJoo Ham <myungjoo.ham@samsung.com>2017-10-11 15:16:57 +0900
committerMyungJoo Ham <myungjoo.ham@samsung.com>2017-10-11 15:16:57 +0900
commit915c76ded744c0f5f151402b9fa69f3fd8452573 (patch)
treeca6a387466543248890f346847acaa8343989b22 /Source/CTest
parent317dbdb79761ef65e45c7358cfc7571c6afa54ad (diff)
downloadcmake-915c76ded744c0f5f151402b9fa69f3fd8452573.tar.gz
cmake-915c76ded744c0f5f151402b9fa69f3fd8452573.tar.bz2
cmake-915c76ded744c0f5f151402b9fa69f3fd8452573.zip
Imported Upstream version 3.9.4upstream/3.9.4
Diffstat (limited to 'Source/CTest')
-rw-r--r--Source/CTest/cmCTestBZR.cxx492
-rw-r--r--Source/CTest/cmCTestBZR.h41
-rw-r--r--Source/CTest/cmCTestBatchTestHandler.cxx102
-rw-r--r--Source/CTest/cmCTestBatchTestHandler.h32
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.cxx532
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.h70
-rw-r--r--Source/CTest/cmCTestBuildCommand.cxx214
-rw-r--r--Source/CTest/cmCTestBuildCommand.h72
-rw-r--r--Source/CTest/cmCTestBuildHandler.cxx1181
-rw-r--r--Source/CTest/cmCTestBuildHandler.h128
-rw-r--r--Source/CTest/cmCTestCVS.cxx245
-rw-r--r--Source/CTest/cmCTestCVS.h44
-rw-r--r--Source/CTest/cmCTestCommand.h29
-rw-r--r--Source/CTest/cmCTestConfigureCommand.cxx156
-rw-r--r--Source/CTest/cmCTestConfigureCommand.h64
-rw-r--r--Source/CTest/cmCTestConfigureHandler.cxx152
-rw-r--r--Source/CTest/cmCTestConfigureHandler.h22
-rw-r--r--Source/CTest/cmCTestCoverageCommand.cxx50
-rw-r--r--Source/CTest/cmCTestCoverageCommand.h68
-rw-r--r--Source/CTest/cmCTestCoverageHandler.cxx2809
-rw-r--r--Source/CTest/cmCTestCoverageHandler.h105
-rw-r--r--Source/CTest/cmCTestCurl.cxx276
-rw-r--r--Source/CTest/cmCTestCurl.h53
-rw-r--r--Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx39
-rw-r--r--Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h65
-rw-r--r--Source/CTest/cmCTestGIT.cxx577
-rw-r--r--Source/CTest/cmCTestGIT.h46
-rw-r--r--Source/CTest/cmCTestGenericHandler.cxx163
-rw-r--r--Source/CTest/cmCTestGenericHandler.h67
-rw-r--r--Source/CTest/cmCTestGlobalVC.cxx108
-rw-r--r--Source/CTest/cmCTestGlobalVC.h49
-rw-r--r--Source/CTest/cmCTestHG.cxx292
-rw-r--r--Source/CTest/cmCTestHG.h39
-rw-r--r--Source/CTest/cmCTestHandlerCommand.cxx324
-rw-r--r--Source/CTest/cmCTestHandlerCommand.h45
-rw-r--r--Source/CTest/cmCTestLaunch.cxx676
-rw-r--r--Source/CTest/cmCTestLaunch.h41
-rw-r--r--Source/CTest/cmCTestMemCheckCommand.cxx64
-rw-r--r--Source/CTest/cmCTestMemCheckCommand.h76
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.cxx1498
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.h121
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.cxx888
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.h105
-rw-r--r--Source/CTest/cmCTestP4.cxx529
-rw-r--r--Source/CTest/cmCTestP4.h76
-rw-r--r--Source/CTest/cmCTestReadCustomFilesCommand.cxx34
-rw-r--r--Source/CTest/cmCTestReadCustomFilesCommand.h60
-rw-r--r--Source/CTest/cmCTestRunScriptCommand.cxx64
-rw-r--r--Source/CTest/cmCTestRunScriptCommand.h64
-rw-r--r--Source/CTest/cmCTestRunTest.cxx790
-rw-r--r--Source/CTest/cmCTestRunTest.h98
-rw-r--r--Source/CTest/cmCTestSVN.cxx517
-rw-r--r--Source/CTest/cmCTestSVN.h63
-rw-r--r--Source/CTest/cmCTestScriptHandler.cxx967
-rw-r--r--Source/CTest/cmCTestScriptHandler.h84
-rw-r--r--Source/CTest/cmCTestSleepCommand.cxx44
-rw-r--r--Source/CTest/cmCTestSleepCommand.h61
-rw-r--r--Source/CTest/cmCTestStartCommand.cxx169
-rw-r--r--Source/CTest/cmCTestStartCommand.h71
-rw-r--r--Source/CTest/cmCTestSubmitCommand.cxx332
-rw-r--r--Source/CTest/cmCTestSubmitCommand.h96
-rw-r--r--Source/CTest/cmCTestSubmitHandler.cxx1862
-rw-r--r--Source/CTest/cmCTestSubmitHandler.h104
-rw-r--r--Source/CTest/cmCTestTestCommand.cxx142
-rw-r--r--Source/CTest/cmCTestTestCommand.h80
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx2759
-rw-r--r--Source/CTest/cmCTestTestHandler.h203
-rw-r--r--Source/CTest/cmCTestUpdateCommand.cxx139
-rw-r--r--Source/CTest/cmCTestUpdateCommand.h56
-rw-r--r--Source/CTest/cmCTestUpdateHandler.cxx487
-rw-r--r--Source/CTest/cmCTestUpdateHandler.h45
-rw-r--r--Source/CTest/cmCTestUploadCommand.cxx79
-rw-r--r--Source/CTest/cmCTestUploadCommand.h64
-rw-r--r--Source/CTest/cmCTestUploadHandler.cxx92
-rw-r--r--Source/CTest/cmCTestUploadHandler.h24
-rw-r--r--Source/CTest/cmCTestVC.cxx170
-rw-r--r--Source/CTest/cmCTestVC.h72
-rw-r--r--Source/CTest/cmParseBlanketJSCoverage.cxx139
-rw-r--r--Source/CTest/cmParseBlanketJSCoverage.h42
-rw-r--r--Source/CTest/cmParseCacheCoverage.cxx204
-rw-r--r--Source/CTest/cmParseCacheCoverage.h32
-rw-r--r--Source/CTest/cmParseCoberturaCoverage.cxx171
-rw-r--r--Source/CTest/cmParseCoberturaCoverage.h45
-rw-r--r--Source/CTest/cmParseDelphiCoverage.cxx229
-rw-r--r--Source/CTest/cmParseDelphiCoverage.h38
-rw-r--r--Source/CTest/cmParseGTMCoverage.cxx230
-rw-r--r--Source/CTest/cmParseGTMCoverage.h38
-rw-r--r--Source/CTest/cmParseJacocoCoverage.cxx184
-rw-r--r--Source/CTest/cmParseJacocoCoverage.h53
-rw-r--r--Source/CTest/cmParseMumpsCoverage.cxx153
-rw-r--r--Source/CTest/cmParseMumpsCoverage.h33
-rw-r--r--Source/CTest/cmParsePHPCoverage.cxx212
-rw-r--r--Source/CTest/cmParsePHPCoverage.h38
-rw-r--r--Source/CTest/cmProcess.cxx238
-rw-r--r--Source/CTest/cmProcess.h51
95 files changed, 13052 insertions, 11795 deletions
diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx
index 381c70ce5..94f39c265 100644
--- a/Source/CTest/cmCTestBZR.cxx
+++ b/Source/CTest/cmCTestBZR.cxx
@@ -1,163 +1,148 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestBZR.h"
#include "cmCTest.h"
+#include "cmCTestVC.h"
+#include "cmProcessTools.h"
#include "cmSystemTools.h"
#include "cmXMLParser.h"
-#include "cmXMLSafe.h"
-
-#include <cmsys/RegularExpression.hxx>
-
-#include <cm_expat.h>
-//----------------------------------------------------------------------------
-extern "C"
-int cmBZRXMLParserUnknownEncodingHandler(void*,
- const XML_Char *name,
- XML_Encoding *info)
+#include "cm_expat.h"
+#include "cmsys/RegularExpression.hxx"
+#include <list>
+#include <map>
+#include <ostream>
+#include <stdlib.h>
+#include <vector>
+
+extern "C" int cmBZRXMLParserUnknownEncodingHandler(void* /*unused*/,
+ const XML_Char* name,
+ XML_Encoding* info)
{
- static const int latin1[]=
- {
- 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
- 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
- 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
- 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
- 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
- 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
- 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
- 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
- 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
- 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
- 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
- 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
- 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
- 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
- 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
- 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
- 0x20AC, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
- 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x017D, 0x008F,
- 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
- 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x017E, 0x0178,
- 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
- 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
- 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
- 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
- 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
- 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
- 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
- 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
- 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
- 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
- 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
- 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
- };
+ static const int latin1[] = {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011,
+ 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A,
+ 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0021, 0x0022, 0x0023,
+ 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C,
+ 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035,
+ 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E,
+ 0x003F, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
+ 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059,
+ 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060, 0x0061, 0x0062,
+ 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B,
+ 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074,
+ 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D,
+ 0x007E, 0x007F, 0x20AC, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020,
+ 0x2021, 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x017D, 0x008F,
+ 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC,
+ 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x017E, 0x0178, 0x00A0, 0x00A1,
+ 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA,
+ 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3,
+ 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC,
+ 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5,
+ 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE,
+ 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0,
+ 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9,
+ 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2,
+ 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB,
+ 0x00FC, 0x00FD, 0x00FE, 0x00FF
+ };
// The BZR xml output plugin can use some encodings that are not
// recognized by expat. This will lead to an error, e.g. "Error
// parsing bzr log xml: unknown encoding", the following is a
// workaround for these unknown encodings.
- if(name == std::string("ascii") || name == std::string("cp1252") ||
- name == std::string("ANSI_X3.4-1968"))
- {
- for(unsigned int i=0;i<256;++i) info->map[i] = latin1[i];
- return 1;
+ if (name == std::string("ascii") || name == std::string("cp1252") ||
+ name == std::string("ANSI_X3.4-1968")) {
+ for (unsigned int i = 0; i < 256; ++i) {
+ info->map[i] = latin1[i];
}
+ return 1;
+ }
return 0;
}
-//----------------------------------------------------------------------------
-cmCTestBZR::cmCTestBZR(cmCTest* ct, std::ostream& log):
- cmCTestGlobalVC(ct, log)
+cmCTestBZR::cmCTestBZR(cmCTest* ct, std::ostream& log)
+ : cmCTestGlobalVC(ct, log)
{
this->PriorRev = this->Unknown;
- // Even though it is specified in the documention, with bzr 1.13
+ // Even though it is specified in the documentation, with bzr 1.13
// BZR_PROGRESS_BAR has no effect. In the future this bug might be fixed.
// Since it doesn't hurt, we specify this environment variable.
cmSystemTools::PutEnv("BZR_PROGRESS_BAR=none");
}
-//----------------------------------------------------------------------------
cmCTestBZR::~cmCTestBZR()
{
}
-//----------------------------------------------------------------------------
-class cmCTestBZR::InfoParser: public cmCTestVC::LineParser
+class cmCTestBZR::InfoParser : public cmCTestVC::LineParser
{
public:
- InfoParser(cmCTestBZR* bzr, const char* prefix):
- BZR(bzr), CheckOutFound(false)
- {
+ InfoParser(cmCTestBZR* bzr, const char* prefix)
+ : BZR(bzr)
+ , CheckOutFound(false)
+ {
this->SetLog(&bzr->Log, prefix);
this->RegexCheckOut.compile("checkout of branch: *([^\t\r\n]+)$");
this->RegexParent.compile("parent branch: *([^\t\r\n]+)$");
- }
+ }
+
private:
cmCTestBZR* BZR;
bool CheckOutFound;
cmsys::RegularExpression RegexCheckOut;
cmsys::RegularExpression RegexParent;
- virtual bool ProcessLine()
- {
- if(this->RegexCheckOut.find(this->Line))
- {
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexCheckOut.find(this->Line)) {
this->BZR->URL = this->RegexCheckOut.match(1);
CheckOutFound = true;
- }
- else if(!CheckOutFound && this->RegexParent.find(this->Line))
- {
+ } else if (!CheckOutFound && this->RegexParent.find(this->Line)) {
this->BZR->URL = this->RegexParent.match(1);
- }
- return true;
}
+ return true;
+ }
};
-//----------------------------------------------------------------------------
-class cmCTestBZR::RevnoParser: public cmCTestVC::LineParser
+class cmCTestBZR::RevnoParser : public cmCTestVC::LineParser
{
public:
- RevnoParser(cmCTestBZR* bzr, const char* prefix, std::string& rev):
- Rev(rev)
- {
+ RevnoParser(cmCTestBZR* bzr, const char* prefix, std::string& rev)
+ : Rev(rev)
+ {
this->SetLog(&bzr->Log, prefix);
this->RegexRevno.compile("^([0-9]+)$");
- }
+ }
+
private:
std::string& Rev;
cmsys::RegularExpression RegexRevno;
- virtual bool ProcessLine()
- {
- if(this->RegexRevno.find(this->Line))
- {
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexRevno.find(this->Line)) {
this->Rev = this->RegexRevno.match(1);
- }
- return true;
}
+ return true;
+ }
};
-//----------------------------------------------------------------------------
std::string cmCTestBZR::LoadInfo()
{
// Run "bzr info" to get the repository info from the work tree.
const char* bzr = this->CommandLineTool.c_str();
- const char* bzr_info[] = {bzr, "info", 0};
+ const char* bzr_info[] = { bzr, "info", CM_NULLPTR };
InfoParser iout(this, "info-out> ");
OutputLogger ierr(this->Log, "info-err> ");
this->RunChild(bzr_info, &iout, &ierr);
// Run "bzr revno" to get the repository revision number from the work tree.
- const char* bzr_revno[] = {bzr, "revno", 0};
+ const char* bzr_revno[] = { bzr, "revno", CM_NULLPTR };
std::string rev;
RevnoParser rout(this, "revno-out> ", rev);
OutputLogger rerr(this->Log, "revno-err> ");
@@ -166,51 +151,55 @@ std::string cmCTestBZR::LoadInfo()
return rev;
}
-void cmCTestBZR::NoteOldRevision()
+bool cmCTestBZR::NoteOldRevision()
{
this->OldRevision = this->LoadInfo();
this->Log << "Revision before update: " << this->OldRevision << "\n";
cmCTestLog(this->CTest, HANDLER_OUTPUT, " Old revision of repository is: "
- << this->OldRevision << "\n");
+ << this->OldRevision << "\n");
this->PriorRev.Rev = this->OldRevision;
+ return true;
}
-//----------------------------------------------------------------------------
-void cmCTestBZR::NoteNewRevision()
+bool cmCTestBZR::NoteNewRevision()
{
this->NewRevision = this->LoadInfo();
this->Log << "Revision after update: " << this->NewRevision << "\n";
cmCTestLog(this->CTest, HANDLER_OUTPUT, " New revision of repository is: "
- << this->NewRevision << "\n");
+ << this->NewRevision << "\n");
this->Log << "URL = " << this->URL << "\n";
+ return true;
}
-//----------------------------------------------------------------------------
-class cmCTestBZR::LogParser: public cmCTestVC::OutputLogger,
- private cmXMLParser
+class cmCTestBZR::LogParser : public cmCTestVC::OutputLogger,
+ private cmXMLParser
{
public:
- LogParser(cmCTestBZR* bzr, const char* prefix):
- OutputLogger(bzr->Log, prefix), BZR(bzr),
- EmailRegex("(.*) <([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+)>")
- { this->InitializeParser(); }
- ~LogParser() { this->CleanupParser(); }
-
- virtual int InitializeParser()
- {
- int res = cmXMLParser::InitializeParser();
- if (res)
- {
- XML_SetUnknownEncodingHandler(static_cast<XML_Parser>(this->Parser),
- cmBZRXMLParserUnknownEncodingHandler, 0);
- }
- return res;
- }
+ LogParser(cmCTestBZR* bzr, const char* prefix)
+ : OutputLogger(bzr->Log, prefix)
+ , BZR(bzr)
+ , EmailRegex("(.*) <([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+)>")
+ {
+ this->InitializeParser();
+ }
+ ~LogParser() CM_OVERRIDE { this->CleanupParser(); }
+
+ int InitializeParser() CM_OVERRIDE
+ {
+ int res = cmXMLParser::InitializeParser();
+ if (res) {
+ XML_SetUnknownEncodingHandler(static_cast<XML_Parser>(this->Parser),
+ cmBZRXMLParserUnknownEncodingHandler,
+ CM_NULLPTR);
+ }
+ return res;
+ }
+
private:
cmCTestBZR* BZR;
typedef cmCTestBZR::Revision Revision;
- typedef cmCTestBZR::Change Change;
+ typedef cmCTestBZR::Change Change;
Revision Rev;
std::vector<Change> Changes;
Change CurChange;
@@ -218,198 +207,164 @@ private:
cmsys::RegularExpression EmailRegex;
- virtual bool ProcessChunk(const char* data, int length)
- {
+ bool ProcessChunk(const char* data, int length) CM_OVERRIDE
+ {
this->OutputLogger::ProcessChunk(data, length);
this->ParseChunk(data, length);
return true;
- }
+ }
- virtual void StartElement(const char* name, const char**)
- {
+ void StartElement(const std::string& name, const char** /*atts*/) CM_OVERRIDE
+ {
this->CData.clear();
- if(strcmp(name, "log") == 0)
- {
+ if (name == "log") {
this->Rev = Revision();
this->Changes.clear();
- }
+ }
// affected-files can contain blocks of
// modified, unknown, renamed, kind-changed, removed, conflicts, added
- else if(strcmp(name, "modified") == 0
- || strcmp(name, "renamed") == 0
- || strcmp(name, "kind-changed") == 0)
- {
+ else if (name == "modified" || name == "renamed" ||
+ name == "kind-changed") {
this->CurChange = Change();
this->CurChange.Action = 'M';
- }
- else if(strcmp(name, "added") == 0)
- {
+ } else if (name == "added") {
this->CurChange = Change();
this->CurChange = 'A';
- }
- else if(strcmp(name, "removed") == 0)
- {
+ } else if (name == "removed") {
this->CurChange = Change();
this->CurChange = 'D';
- }
- else if(strcmp(name, "unknown") == 0
- || strcmp(name, "conflicts") == 0)
- {
+ } else if (name == "unknown" || name == "conflicts") {
// Should not happen here
this->CurChange = Change();
- }
}
+ }
- virtual void CharacterDataHandler(const char* data, int length)
- {
- this->CData.insert(this->CData.end(), data, data+length);
- }
+ void CharacterDataHandler(const char* data, int length) CM_OVERRIDE
+ {
+ this->CData.insert(this->CData.end(), data, data + length);
+ }
- virtual void EndElement(const char* name)
- {
- if(strcmp(name, "log") == 0)
- {
+ void EndElement(const std::string& name) CM_OVERRIDE
+ {
+ if (name == "log") {
this->BZR->DoRevision(this->Rev, this->Changes);
- }
- else if((strcmp(name, "file") == 0 || strcmp(name, "directory") == 0)
- && !this->CData.empty())
- {
+ } else if (!this->CData.empty() &&
+ (name == "file" || name == "directory")) {
this->CurChange.Path.assign(&this->CData[0], this->CData.size());
cmSystemTools::ConvertToUnixSlashes(this->CurChange.Path);
this->Changes.push_back(this->CurChange);
- }
- else if(strcmp(name, "symlink") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "symlink") {
// symlinks have an arobase at the end in the log
- this->CurChange.Path.assign(&this->CData[0], this->CData.size()-1);
+ this->CurChange.Path.assign(&this->CData[0], this->CData.size() - 1);
cmSystemTools::ConvertToUnixSlashes(this->CurChange.Path);
this->Changes.push_back(this->CurChange);
- }
- else if(strcmp(name, "committer") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "committer") {
this->Rev.Author.assign(&this->CData[0], this->CData.size());
- if(this->EmailRegex.find(this->Rev.Author))
- {
+ if (this->EmailRegex.find(this->Rev.Author)) {
this->Rev.Author = this->EmailRegex.match(1);
this->Rev.EMail = this->EmailRegex.match(2);
- }
}
- else if(strcmp(name, "timestamp") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "timestamp") {
this->Rev.Date.assign(&this->CData[0], this->CData.size());
- }
- else if(strcmp(name, "message") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "message") {
this->Rev.Log.assign(&this->CData[0], this->CData.size());
- }
- else if(strcmp(name, "revno") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "revno") {
this->Rev.Rev.assign(&this->CData[0], this->CData.size());
- }
- this->CData.clear();
}
+ this->CData.clear();
+ }
- virtual void ReportError(int, int, const char* msg)
- {
+ void ReportError(int /*line*/, int /*column*/, const char* msg) CM_OVERRIDE
+ {
this->BZR->Log << "Error parsing bzr log xml: " << msg << "\n";
- }
+ }
};
-//----------------------------------------------------------------------------
-class cmCTestBZR::UpdateParser: public cmCTestVC::LineParser
+class cmCTestBZR::UpdateParser : public cmCTestVC::LineParser
{
public:
- UpdateParser(cmCTestBZR* bzr, const char* prefix): BZR(bzr)
- {
+ UpdateParser(cmCTestBZR* bzr, const char* prefix)
+ : BZR(bzr)
+ {
this->SetLog(&bzr->Log, prefix);
this->RegexUpdate.compile("^([-+R?XCP ])([NDKM ])([* ]) +(.+)$");
- }
+ }
+
private:
cmCTestBZR* BZR;
cmsys::RegularExpression RegexUpdate;
- virtual bool ProcessChunk(const char* first, int length)
- {
+ bool ProcessChunk(const char* first, int length) CM_OVERRIDE
+ {
bool last_is_new_line = (*first == '\r' || *first == '\n');
const char* const last = first + length;
- for(const char* c = first; c != last; ++c)
- {
- if(*c == '\r' || *c == '\n')
- {
- if(!last_is_new_line)
- {
+ for (const char* c = first; c != last; ++c) {
+ if (*c == '\r' || *c == '\n') {
+ if (!last_is_new_line) {
// Log this line.
- if(this->Log && this->Prefix)
- {
+ if (this->Log && this->Prefix) {
*this->Log << this->Prefix << this->Line << "\n";
- }
+ }
// Hand this line to the subclass implementation.
- if(!this->ProcessLine())
- {
+ if (!this->ProcessLine()) {
this->Line = "";
return false;
- }
+ }
this->Line = "";
last_is_new_line = true;
- }
}
- else
- {
+ } else {
// Append this character to the line under construction.
this->Line.append(1, *c);
last_is_new_line = false;
- }
}
- return true;
}
+ return true;
+ }
- bool ProcessLine()
- {
- if(this->RegexUpdate.find(this->Line))
- {
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexUpdate.find(this->Line)) {
this->DoPath(this->RegexUpdate.match(1)[0],
this->RegexUpdate.match(2)[0],
- this->RegexUpdate.match(3)[0],
- this->RegexUpdate.match(4));
- }
- return true;
+ this->RegexUpdate.match(3)[0], this->RegexUpdate.match(4));
}
+ return true;
+ }
void DoPath(char c0, char c1, char c2, std::string path)
- {
- if(path.empty()) return;
+ {
+ if (path.empty()) {
+ return;
+ }
cmSystemTools::ConvertToUnixSlashes(path);
const std::string dir = cmSystemTools::GetFilenamePath(path);
const std::string name = cmSystemTools::GetFilenameName(path);
- if ( c0=='C' )
- {
+ if (c0 == 'C') {
this->BZR->Dirs[dir][name].Status = PathConflicting;
return;
- }
+ }
- if ( c1=='M' || c1=='K' || c1=='N' || c1=='D' || c2 =='*' )
- {
+ if (c1 == 'M' || c1 == 'K' || c1 == 'N' || c1 == 'D' || c2 == '*') {
this->BZR->Dirs[dir][name].Status = PathUpdated;
return;
- }
}
+ }
};
-//----------------------------------------------------------------------------
bool cmCTestBZR::UpdateImpl()
{
// Get user-specified update options.
std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
- if(opts.empty())
- {
+ if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("BZRUpdateOptions");
- }
- std::vector<cmStdString> args = cmSystemTools::ParseArguments(opts.c_str());
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
// TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
@@ -418,15 +373,14 @@ bool cmCTestBZR::UpdateImpl()
bzr_update.push_back(this->CommandLineTool.c_str());
bzr_update.push_back("pull");
- for(std::vector<cmStdString>::const_iterator ai = args.begin();
- ai != args.end(); ++ai)
- {
+ for (std::vector<std::string>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai) {
bzr_update.push_back(ai->c_str());
- }
+ }
bzr_update.push_back(this->URL.c_str());
- bzr_update.push_back(0);
+ bzr_update.push_back(CM_NULLPTR);
// For some reason bzr uses stderr to display the update status.
OutputLogger out(this->Log, "pull-out> ");
@@ -434,90 +388,88 @@ bool cmCTestBZR::UpdateImpl()
return this->RunUpdateCommand(&bzr_update[0], &out, &err);
}
-//----------------------------------------------------------------------------
-void cmCTestBZR::LoadRevisions()
+bool cmCTestBZR::LoadRevisions()
{
cmCTestLog(this->CTest, HANDLER_OUTPUT,
" Gathering version information (one . per revision):\n"
- " " << std::flush);
+ " "
+ << std::flush);
// We are interested in every revision included in the update.
this->Revisions.clear();
std::string revs;
- if(atoi(this->OldRevision.c_str()) <= atoi(this->NewRevision.c_str()))
- {
+ if (atoi(this->OldRevision.c_str()) <= atoi(this->NewRevision.c_str())) {
// DoRevision takes care of discarding the information about OldRevision
revs = this->OldRevision + ".." + this->NewRevision;
- }
- else
- {
- return;
- }
+ } else {
+ return true;
+ }
// Run "bzr log" to get all global revisions of interest.
const char* bzr = this->CommandLineTool.c_str();
- const char* bzr_log[] = {bzr, "log", "-v", "-r", revs.c_str(), "--xml",
- this->URL.c_str(), 0};
+ const char* bzr_log[] = {
+ bzr, "log", "-v", "-r", revs.c_str(), "--xml", this->URL.c_str(),
+ CM_NULLPTR
+ };
{
- LogParser out(this, "log-out> ");
- OutputLogger err(this->Log, "log-err> ");
- this->RunChild(bzr_log, &out, &err);
+ LogParser out(this, "log-out> ");
+ OutputLogger err(this->Log, "log-err> ");
+ this->RunChild(bzr_log, &out, &err);
}
cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
+ return true;
}
-//----------------------------------------------------------------------------
-class cmCTestBZR::StatusParser: public cmCTestVC::LineParser
+class cmCTestBZR::StatusParser : public cmCTestVC::LineParser
{
public:
- StatusParser(cmCTestBZR* bzr, const char* prefix): BZR(bzr)
- {
+ StatusParser(cmCTestBZR* bzr, const char* prefix)
+ : BZR(bzr)
+ {
this->SetLog(&bzr->Log, prefix);
this->RegexStatus.compile("^([-+R?XCP ])([NDKM ])([* ]) +(.+)$");
- }
+ }
+
private:
cmCTestBZR* BZR;
cmsys::RegularExpression RegexStatus;
- bool ProcessLine()
- {
- if(this->RegexStatus.find(this->Line))
- {
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexStatus.find(this->Line)) {
this->DoPath(this->RegexStatus.match(1)[0],
this->RegexStatus.match(2)[0],
- this->RegexStatus.match(3)[0],
- this->RegexStatus.match(4));
- }
- return true;
+ this->RegexStatus.match(3)[0], this->RegexStatus.match(4));
}
+ return true;
+ }
void DoPath(char c0, char c1, char c2, std::string path)
- {
- if(path.empty()) return;
+ {
+ if (path.empty()) {
+ return;
+ }
cmSystemTools::ConvertToUnixSlashes(path);
- if ( c0=='C' )
- {
+ if (c0 == 'C') {
this->BZR->DoModification(PathConflicting, path);
return;
- }
+ }
- if ( c0 == '+' || c0 == 'R' || c0 == 'P'
- || c1=='M' || c1=='K' || c1=='N' || c1=='D'
- || c2 =='*' )
- {
+ if (c0 == '+' || c0 == 'R' || c0 == 'P' || c1 == 'M' || c1 == 'K' ||
+ c1 == 'N' || c1 == 'D' || c2 == '*') {
this->BZR->DoModification(PathModified, path);
return;
- }
}
+ }
};
-//----------------------------------------------------------------------------
-void cmCTestBZR::LoadModifications()
+bool cmCTestBZR::LoadModifications()
{
// Run "bzr status" which reports local modifications.
const char* bzr = this->CommandLineTool.c_str();
- const char* bzr_status[] = {bzr, "status", "-SV", 0};
+ const char* bzr_status[] = { bzr, "status", "-SV", CM_NULLPTR };
StatusParser out(this, "status-out> ");
OutputLogger err(this->Log, "status-err> ");
this->RunChild(bzr_status, &out, &err);
+ return true;
}
diff --git a/Source/CTest/cmCTestBZR.h b/Source/CTest/cmCTestBZR.h
index df688e1ee..2e8e88f95 100644
--- a/Source/CTest/cmCTestBZR.h
+++ b/Source/CTest/cmCTestBZR.h
@@ -1,53 +1,52 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestBZR_h
#define cmCTestBZR_h
+#include "cmConfigure.h"
+
#include "cmCTestGlobalVC.h"
+#include <iosfwd>
+#include <string>
+
+class cmCTest;
+
/** \class cmCTestBZR
* \brief Interaction with bzr command-line tool
*
*/
-class cmCTestBZR: public cmCTestGlobalVC
+class cmCTestBZR : public cmCTestGlobalVC
{
public:
/** Construct with a CTest instance and update log stream. */
cmCTestBZR(cmCTest* ctest, std::ostream& log);
- virtual ~cmCTestBZR();
+ ~cmCTestBZR() CM_OVERRIDE;
private:
// Implement cmCTestVC internal API.
- virtual void NoteOldRevision();
- virtual void NoteNewRevision();
- virtual bool UpdateImpl();
+ bool NoteOldRevision() CM_OVERRIDE;
+ bool NoteNewRevision() CM_OVERRIDE;
+ bool UpdateImpl() CM_OVERRIDE;
// URL of repository directory checked out in the working tree.
std::string URL;
std::string LoadInfo();
- void LoadModifications();
- void LoadRevisions();
+ bool LoadModifications() CM_OVERRIDE;
+ bool LoadRevisions() CM_OVERRIDE;
// Parsing helper classes.
class InfoParser;
- class RevnoParser;
class LogParser;
- class UpdateParser;
+ class RevnoParser;
class StatusParser;
+ class UpdateParser;
+
friend class InfoParser;
- friend class RevnoParser;
friend class LogParser;
+ friend class RevnoParser;
friend class UpdateParser;
friend class StatusParser;
};
diff --git a/Source/CTest/cmCTestBatchTestHandler.cxx b/Source/CTest/cmCTestBatchTestHandler.cxx
index 934481b88..beee53a13 100644
--- a/Source/CTest/cmCTestBatchTestHandler.cxx
+++ b/Source/CTest/cmCTestBatchTestHandler.cxx
@@ -1,64 +1,55 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestBatchTestHandler.h"
-#include "cmProcess.h"
-#include "cmStandardIncludes.h"
+
#include "cmCTest.h"
+#include "cmCTestMultiProcessHandler.h"
+#include "cmCTestTestHandler.h"
+#include "cmProcess.h"
#include "cmSystemTools.h"
-#include <stdlib.h>
+
+#include <map>
+#include <utility>
+#include <vector>
cmCTestBatchTestHandler::~cmCTestBatchTestHandler()
{
}
-//---------------------------------------------------------
void cmCTestBatchTestHandler::RunTests()
{
this->WriteBatchScript();
this->SubmitBatchScript();
}
-//---------------------------------------------------------
void cmCTestBatchTestHandler::WriteBatchScript()
{
- this->Script = this->CTest->GetBinaryDir()
- + "/Testing/CTestBatch.txt";
- std::fstream fout;
- fout.open(this->Script.c_str(), std::ios::out);
+ this->Script = this->CTest->GetBinaryDir() + "/Testing/CTestBatch.txt";
+ cmsys::ofstream fout;
+ fout.open(this->Script.c_str());
fout << "#!/bin/sh\n";
- for(TestMap::iterator i = this->Tests.begin(); i != this->Tests.end(); ++i)
- {
+ for (TestMap::iterator i = this->Tests.begin(); i != this->Tests.end();
+ ++i) {
this->WriteSrunArgs(i->first, fout);
this->WriteTestCommand(i->first, fout);
fout << "\n";
- }
+ }
fout.flush();
fout.close();
}
-//---------------------------------------------------------
-void cmCTestBatchTestHandler::WriteSrunArgs(int test, std::fstream& fout)
+void cmCTestBatchTestHandler::WriteSrunArgs(int test, std::ostream& fout)
{
cmCTestTestHandler::cmCTestTestProperties* properties =
- this->Properties[test];
+ this->Properties[test];
fout << "srun ";
- //fout << "--jobid=" << test << " ";
+ // fout << "--jobid=" << test << " ";
fout << "-J=" << properties->Name << " ";
- //Write dependency information
- /*if(this->Tests[test].size() > 0)
+ // Write dependency information
+ /*if(!this->Tests[test].empty())
{
fout << "-P=afterany";
for(TestSet::iterator i = this->Tests[test].begin();
@@ -68,18 +59,15 @@ void cmCTestBatchTestHandler::WriteSrunArgs(int test, std::fstream& fout)
}
fout << " ";
}*/
- if(properties->RunSerial)
- {
+ if (properties->RunSerial) {
fout << "--exclusive ";
- }
- if(properties->Processors > 1)
- {
+ }
+ if (properties->Processors > 1) {
fout << "-n" << properties->Processors << " ";
- }
+ }
}
-//---------------------------------------------------------
-void cmCTestBatchTestHandler::WriteTestCommand(int test, std::fstream& fout)
+void cmCTestBatchTestHandler::WriteTestCommand(int test, std::ostream& fout)
{
std::vector<std::string> args = this->Properties[test]->Args;
std::vector<std::string> processArgs;
@@ -88,47 +76,41 @@ void cmCTestBatchTestHandler::WriteTestCommand(int test, std::fstream& fout)
command = this->TestHandler->FindTheExecutable(args[1].c_str());
command = cmSystemTools::ConvertToOutputPath(command.c_str());
- //Prepends memcheck args to our command string if this is a memcheck
+ // Prepends memcheck args to our command string if this is a memcheck
this->TestHandler->GenerateTestCommand(processArgs, test);
processArgs.push_back(command);
- for(std::vector<std::string>::iterator arg = processArgs.begin();
- arg != processArgs.end(); ++arg)
- {
+ for (std::vector<std::string>::iterator arg = processArgs.begin();
+ arg != processArgs.end(); ++arg) {
fout << *arg << " ";
- }
+ }
std::vector<std::string>::iterator i = args.begin();
- ++i; //the test name
- ++i; //the executable (command)
- if(args.size() > 2)
- {
+ ++i; // the test name
+ ++i; // the executable (command)
+ if (args.size() > 2) {
fout << "'";
- }
- while(i != args.end())
- {
- fout << "\"" << *i << "\""; //args to the test executable
+ }
+ while (i != args.end()) {
+ fout << "\"" << *i << "\""; // args to the test executable
++i;
- if(i == args.end() && args.size() > 2)
- {
+ if (i == args.end() && args.size() > 2) {
fout << "'";
- }
- fout << " ";
}
- //TODO ZACH build TestResult.FullCommandLine
- //this->TestResult.FullCommandLine = this->TestCommand;
+ fout << " ";
+ }
+ // TODO ZACH build TestResult.FullCommandLine
+ // this->TestResult.FullCommandLine = this->TestCommand;
}
-//---------------------------------------------------------
void cmCTestBatchTestHandler::SubmitBatchScript()
{
cmProcess sbatch;
std::vector<std::string> args;
args.push_back(this->Script);
args.push_back("-o");
- args.push_back(this->CTest->GetBinaryDir()
- + "/Testing/CTestBatch.txt");
+ args.push_back(this->CTest->GetBinaryDir() + "/Testing/CTestBatch.txt");
sbatch.SetCommand("sbatch");
sbatch.SetCommandArguments(args);
diff --git a/Source/CTest/cmCTestBatchTestHandler.h b/Source/CTest/cmCTestBatchTestHandler.h
index ab0d081ae..4a5dac1d6 100644
--- a/Source/CTest/cmCTestBatchTestHandler.h
+++ b/Source/CTest/cmCTestBatchTestHandler.h
@@ -1,22 +1,13 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestBatchTestHandler_h
#define cmCTestBatchTestHandler_h
-#include <cmStandardIncludes.h>
-#include <cmCTestTestHandler.h>
-#include <cmCTestMultiProcessHandler.h>
-#include <cmCTestRunTest.h>
+#include "cmConfigure.h"
+
+#include "cmCTestMultiProcessHandler.h"
+#include "cmsys/FStream.hxx"
+#include <string>
/** \class cmCTestBatchTestHandler
* \brief run parallel ctest
@@ -26,12 +17,13 @@
class cmCTestBatchTestHandler : public cmCTestMultiProcessHandler
{
public:
- ~cmCTestBatchTestHandler();
- virtual void RunTests();
+ ~cmCTestBatchTestHandler() CM_OVERRIDE;
+ void RunTests() CM_OVERRIDE;
+
protected:
void WriteBatchScript();
- void WriteSrunArgs(int test, std::fstream& fout);
- void WriteTestCommand(int test, std::fstream& fout);
+ void WriteSrunArgs(int test, std::ostream& fout);
+ void WriteTestCommand(int test, std::ostream& fout);
void SubmitBatchScript();
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index 4fa3c53b9..cc290715c 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -1,47 +1,35 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestBuildAndTestHandler.h"
-#include "cmSystemTools.h"
#include "cmCTest.h"
-#include "cmake.h"
-#include "cmGlobalGenerator.h"
-#include <cmsys/Process.h>
#include "cmCTestTestHandler.h"
+#include "cmGlobalGenerator.h"
+#include "cmSystemTools.h"
+#include "cmWorkingDirectory.h"
+#include "cmake.h"
+
+#include "cmsys/Process.h"
+#include <stdlib.h>
-//----------------------------------------------------------------------
cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler()
{
- this->BuildTwoConfig = false;
- this->BuildNoClean = false;
- this->BuildNoCMake = false;
+ this->BuildTwoConfig = false;
+ this->BuildNoClean = false;
+ this->BuildNoCMake = false;
this->Timeout = 0;
}
-//----------------------------------------------------------------------
void cmCTestBuildAndTestHandler::Initialize()
{
- this->BuildTargets.erase(
- this->BuildTargets.begin(), this->BuildTargets.end());
+ this->BuildTargets.clear();
this->Superclass::Initialize();
}
-//----------------------------------------------------------------------
const char* cmCTestBuildAndTestHandler::GetOutput()
{
return this->Output.c_str();
}
-//----------------------------------------------------------------------
int cmCTestBuildAndTestHandler::ProcessHandler()
{
this->Output = "";
@@ -52,271 +40,235 @@ int cmCTestBuildAndTestHandler::ProcessHandler()
return retv;
}
-//----------------------------------------------------------------------
int cmCTestBuildAndTestHandler::RunCMake(std::string* outstring,
- cmOStringStream &out, std::string &cmakeOutString, std::string &cwd,
- cmake *cm)
+ std::ostringstream& out,
+ std::string& cmakeOutString,
+ cmake* cm)
{
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())
- {
+ if (!this->BuildGenerator.empty()) {
std::string generator = "-G";
generator += this->BuildGenerator;
args.push_back(generator);
- }
- if(this->BuildGeneratorToolset.size())
- {
+ }
+ if (!this->BuildGeneratorPlatform.empty()) {
+ std::string platform = "-A";
+ platform += this->BuildGeneratorPlatform;
+ args.push_back(platform);
+ }
+ if (!this->BuildGeneratorToolset.empty()) {
std::string toolset = "-T";
toolset += this->BuildGeneratorToolset;
args.push_back(toolset);
- }
+ }
- const char* config = 0;
- if ( this->CTest->GetConfigType().size() > 0 )
- {
+ const char* config = CM_NULLPTR;
+ if (!this->CTest->GetConfigType().empty()) {
config = this->CTest->GetConfigType().c_str();
- }
+ }
#ifdef CMAKE_INTDIR
- if(!config)
- {
+ if (!config) {
config = CMAKE_INTDIR;
- }
+ }
#endif
- if ( config )
- {
- std::string btype
- = "-DCMAKE_BUILD_TYPE:STRING=" + std::string(config);
+ if (config) {
+ std::string btype = "-DCMAKE_BUILD_TYPE:STRING=" + std::string(config);
args.push_back(btype);
- }
+ }
- for(k=0; k < this->BuildOptions.size(); ++k)
- {
+ for (k = 0; k < this->BuildOptions.size(); ++k) {
args.push_back(this->BuildOptions[k]);
- }
- if (cm->Run(args) != 0)
- {
+ }
+ if (cm->Run(args) != 0) {
out << "Error: cmake execution failed\n";
out << cmakeOutString << "\n";
- // return to the original directory
- cmSystemTools::ChangeDirectory(cwd.c_str());
- if(outstring)
- {
+ if (outstring) {
*outstring = out.str();
- }
- else
- {
+ } else {
cmCTestLog(this->CTest, ERROR_MESSAGE, out.str() << std::endl);
- }
- return 1;
}
+ return 1;
+ }
// do another config?
- if(this->BuildTwoConfig)
- {
- if (cm->Run(args) != 0)
- {
+ if (this->BuildTwoConfig) {
+ if (cm->Run(args) != 0) {
out << "Error: cmake execution failed\n";
out << cmakeOutString << "\n";
- // return to the original directory
- cmSystemTools::ChangeDirectory(cwd.c_str());
- if(outstring)
- {
+ if (outstring) {
*outstring = out.str();
- }
- else
- {
+ } else {
cmCTestLog(this->CTest, ERROR_MESSAGE, out.str() << std::endl);
- }
- return 1;
}
+ return 1;
}
+ }
out << "======== CMake output ======\n";
out << cmakeOutString;
out << "======== End CMake output ======\n";
return 0;
}
-//----------------------------------------------------------------------
-void CMakeMessageCallback(const char* m, const char*, bool&, void* s)
+void CMakeMessageCallback(const char* m, const char* /*unused*/,
+ bool& /*unused*/, void* s)
{
std::string* out = (std::string*)s;
*out += m;
*out += "\n";
}
-void CMakeProgressCallback(const char*msg, float , void * s)
+void CMakeProgressCallback(const char* msg, float /*unused*/, void* s)
{
std::string* out = (std::string*)s;
*out += msg;
*out += "\n";
}
-//----------------------------------------------------------------------
-void CMakeStdoutCallback(const char* m, int len, void* s)
+void CMakeOutputCallback(const char* m, size_t len, void* s)
{
std::string* out = (std::string*)s;
out->append(m, len);
}
-struct cmSetupOutputCaptureCleanup
+
+class cmCTestBuildAndTestCaptureRAII
{
- ~cmSetupOutputCaptureCleanup()
+ cmake& CM;
+
+public:
+ cmCTestBuildAndTestCaptureRAII(cmake& cm, std::string& s)
+ : CM(cm)
{
- cmSystemTools::SetErrorCallback(0, 0);
- cmSystemTools::SetStdoutCallback(0, 0);
+ cmSystemTools::SetMessageCallback(CMakeMessageCallback, &s);
+ cmSystemTools::SetStdoutCallback(CMakeOutputCallback, &s);
+ cmSystemTools::SetStderrCallback(CMakeOutputCallback, &s);
+ this->CM.SetProgressCallback(CMakeProgressCallback, &s);
+ }
+ ~cmCTestBuildAndTestCaptureRAII()
+ {
+ this->CM.SetProgressCallback(CM_NULLPTR, CM_NULLPTR);
+ cmSystemTools::SetStderrCallback(CM_NULLPTR, CM_NULLPTR);
+ cmSystemTools::SetStdoutCallback(CM_NULLPTR, CM_NULLPTR);
+ cmSystemTools::SetMessageCallback(CM_NULLPTR, CM_NULLPTR);
}
};
-//----------------------------------------------------------------------
int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
{
- unsigned int k;
- std::string cmakeOutString;
- cmSystemTools::SetErrorCallback(CMakeMessageCallback, &cmakeOutString);
- cmSystemTools::SetStdoutCallback(CMakeStdoutCallback, &cmakeOutString);
- // make sure SetStdoutCallback and SetErrorCallback are set to null
- // after this function exits so that they do not point at a destroyed
- // string cmakeOutString
- cmSetupOutputCaptureCleanup cleanup;
- static_cast<void>(cleanup);
- cmOStringStream out;
-
// if the generator and make program are not specified then it is an error
- if (!this->BuildGenerator.size() || !this->BuildMakeProgram.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. ";
- }
- return 1;
+ if (this->BuildGenerator.empty()) {
+ if (outstring) {
+ *outstring = "--build-and-test requires that the generator "
+ "be provided using the --build-generator "
+ "command line option. ";
}
+ return 1;
+ }
- if ( this->CTest->GetConfigType().size() == 0 &&
- this->ConfigSample.size())
- {
+ cmake cm(cmake::RoleProject);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ std::string cmakeOutString;
+ cmCTestBuildAndTestCaptureRAII captureRAII(cm, cmakeOutString);
+ static_cast<void>(captureRAII);
+ std::ostringstream out;
+
+ if (this->CTest->GetConfigType().empty() && !this->ConfigSample.empty()) {
// use the config sample to set the ConfigType
std::string fullPath;
std::string resultingConfig;
std::vector<std::string> extraPaths;
std::vector<std::string> failed;
- fullPath =
- cmCTestTestHandler::FindExecutable(this->CTest,
- this->ConfigSample.c_str(),
- resultingConfig,
- extraPaths,
- failed);
- if (fullPath.size() && resultingConfig.size())
- {
+ fullPath = cmCTestTestHandler::FindExecutable(
+ this->CTest, this->ConfigSample.c_str(), resultingConfig, extraPaths,
+ failed);
+ if (!fullPath.empty() && !resultingConfig.empty()) {
this->CTest->SetConfigType(resultingConfig.c_str());
- }
- out << "Using config sample with results: "
- << fullPath << " and " << resultingConfig << std::endl;
}
+ out << "Using config sample with results: " << fullPath << " and "
+ << resultingConfig << std::endl;
+ }
// we need to honor the timeout specified, the timeout include cmake, build
// and test time
double clock_start = cmSystemTools::GetTime();
// make sure the binary dir is there
- std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
- out << "Internal cmake changing into directory: "
- << this->BinaryDir << std::endl;
- if (!cmSystemTools::FileIsDirectory(this->BinaryDir.c_str()))
- {
+ out << "Internal cmake changing into directory: " << this->BinaryDir
+ << std::endl;
+ if (!cmSystemTools::FileIsDirectory(this->BinaryDir)) {
cmSystemTools::MakeDirectory(this->BinaryDir.c_str());
- }
- cmSystemTools::ChangeDirectory(this->BinaryDir.c_str());
-
- // should we cmake?
- cmake cm;
- cm.SetProgressCallback(CMakeProgressCallback, &cmakeOutString);
+ }
+ cmWorkingDirectory workdir(this->BinaryDir);
- if(this->BuildNoCMake)
- {
- cm.SetGlobalGenerator(cm.CreateGlobalGenerator(
- this->BuildGenerator.c_str()));
+ if (this->BuildNoCMake) {
+ // Make the generator available for the Build call below.
+ cm.SetGlobalGenerator(cm.CreateGlobalGenerator(this->BuildGenerator));
+ cm.SetGeneratorPlatform(this->BuildGeneratorPlatform);
cm.SetGeneratorToolset(this->BuildGeneratorToolset);
- }
- else
- {
+
+ // Load the cache to make CMAKE_MAKE_PROGRAM available.
+ cm.LoadCache(this->BinaryDir);
+ } else {
// do the cmake step, no timeout here since it is not a sub process
- if (this->RunCMake(outstring,out,cmakeOutString,cwd,&cm))
- {
+ if (this->RunCMake(outstring, out, cmakeOutString, &cm)) {
return 1;
- }
}
+ }
// do the build
std::vector<std::string>::iterator tarIt;
- if ( this->BuildTargets.size() == 0 )
- {
+ if (this->BuildTargets.empty()) {
this->BuildTargets.push_back("");
- }
- for ( tarIt = this->BuildTargets.begin();
- tarIt != this->BuildTargets.end(); ++ tarIt )
- {
+ }
+ for (tarIt = this->BuildTargets.begin(); tarIt != this->BuildTargets.end();
+ ++tarIt) {
double remainingTime = 0;
- if (this->Timeout > 0)
- {
+ if (this->Timeout > 0) {
remainingTime = this->Timeout - cmSystemTools::GetTime() + clock_start;
- if (remainingTime <= 0)
- {
- if(outstring)
- {
+ if (remainingTime <= 0) {
+ if (outstring) {
*outstring = "--build-and-test timeout exceeded. ";
- }
- return 1;
}
+ return 1;
}
+ }
std::string output;
- const char* config = 0;
- if ( this->CTest->GetConfigType().size() > 0 )
- {
+ const char* config = CM_NULLPTR;
+ if (!this->CTest->GetConfigType().empty()) {
config = this->CTest->GetConfigType().c_str();
- }
+ }
#ifdef CMAKE_INTDIR
- if(!config)
- {
+ if (!config) {
config = CMAKE_INTDIR;
- }
+ }
#endif
- if(!config)
- {
+ if (!config) {
config = "Debug";
- }
+ }
int retVal = cm.GetGlobalGenerator()->Build(
- this->SourceDir.c_str(), this->BinaryDir.c_str(),
- this->BuildProject.c_str(), tarIt->c_str(),
- &output, this->BuildMakeProgram.c_str(),
- config,
- !this->BuildNoClean,
- false, remainingTime);
+ this->SourceDir, this->BinaryDir, this->BuildProject, *tarIt, output,
+ this->BuildMakeProgram, config, !this->BuildNoClean, false, false,
+ remainingTime);
out << output;
// if the build failed then return
- if (retVal)
- {
- if(outstring)
- {
- *outstring = out.str();
- }
- return 1;
+ if (retVal) {
+ if (outstring) {
+ *outstring = out.str();
}
+ return 1;
}
- if(outstring)
- {
- *outstring = out.str();
- }
+ }
+ if (outstring) {
+ *outstring = out.str();
+ }
// if no test was specified then we are done
- if (!this->TestCommand.size())
- {
+ if (this->TestCommand.empty()) {
return 0;
- }
+ }
// now run the compiled test if we can find it
// store the final location in fullPath
@@ -324,219 +276,169 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
std::string resultingConfig;
std::vector<std::string> extraPaths;
// if this->ExecutableDirectory is set try that as well
- if (this->ExecutableDirectory.size())
- {
+ if (!this->ExecutableDirectory.empty()) {
std::string tempPath = this->ExecutableDirectory;
tempPath += "/";
tempPath += this->TestCommand;
extraPaths.push_back(tempPath);
- }
+ }
std::vector<std::string> failed;
fullPath =
- cmCTestTestHandler::FindExecutable(this->CTest,
- this->TestCommand.c_str(),
- resultingConfig,
- extraPaths,
- failed);
+ cmCTestTestHandler::FindExecutable(this->CTest, this->TestCommand.c_str(),
+ resultingConfig, extraPaths, failed);
- if(!cmSystemTools::FileExists(fullPath.c_str()))
- {
+ if (!cmSystemTools::FileExists(fullPath.c_str())) {
out << "Could not find path to executable, perhaps it was not built: "
- << this->TestCommand << "\n";
+ << this->TestCommand << "\n";
out << "tried to find it in these places:\n";
- out << fullPath.c_str() << "\n";
- for(unsigned int i=0; i < failed.size(); ++i)
- {
+ out << fullPath << "\n";
+ for (unsigned int i = 0; i < failed.size(); ++i) {
out << failed[i] << "\n";
- }
- if(outstring)
- {
- *outstring = out.str();
- }
- else
- {
+ }
+ if (outstring) {
+ *outstring = out.str();
+ } else {
cmCTestLog(this->CTest, ERROR_MESSAGE, out.str());
- }
- // return to the original directory
- cmSystemTools::ChangeDirectory(cwd.c_str());
- return 1;
}
+ return 1;
+ }
std::vector<const char*> testCommand;
testCommand.push_back(fullPath.c_str());
- for(k=0; k < this->TestCommandArgs.size(); ++k)
- {
+ for (size_t k = 0; k < this->TestCommandArgs.size(); ++k) {
testCommand.push_back(this->TestCommandArgs[k].c_str());
- }
- testCommand.push_back(0);
+ }
+ testCommand.push_back(CM_NULLPTR);
std::string outs;
int retval = 0;
// run the test from the this->BuildRunDir if set
- if(this->BuildRunDir.size())
- {
+ if (!this->BuildRunDir.empty()) {
out << "Run test in directory: " << this->BuildRunDir << "\n";
- cmSystemTools::ChangeDirectory(this->BuildRunDir.c_str());
- }
+ cmSystemTools::ChangeDirectory(this->BuildRunDir);
+ }
out << "Running test command: \"" << fullPath << "\"";
- for(k=0; k < this->TestCommandArgs.size(); ++k)
- {
+ for (size_t k = 0; k < this->TestCommandArgs.size(); ++k) {
out << " \"" << this->TestCommandArgs[k] << "\"";
- }
+ }
out << "\n";
// how much time is remaining
double remainingTime = 0;
- if (this->Timeout > 0)
- {
+ if (this->Timeout > 0) {
remainingTime = this->Timeout - cmSystemTools::GetTime() + clock_start;
- if (remainingTime <= 0)
- {
- if(outstring)
- {
+ if (remainingTime <= 0) {
+ if (outstring) {
*outstring = "--build-and-test timeout exceeded. ";
- }
- return 1;
}
+ return 1;
}
+ }
- int runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, 0,
- remainingTime, 0);
+ int runTestRes = this->CTest->RunTest(testCommand, &outs, &retval,
+ CM_NULLPTR, remainingTime, CM_NULLPTR);
- if(runTestRes != cmsysProcess_State_Exited || retval != 0)
- {
+ if (runTestRes != cmsysProcess_State_Exited || retval != 0) {
out << "Test command failed: " << testCommand[0] << "\n";
retval = 1;
- }
+ }
out << outs << "\n";
- if(outstring)
- {
+ if (outstring) {
*outstring = out.str();
- }
- else
- {
+ } else {
cmCTestLog(this->CTest, OUTPUT, out.str() << std::endl);
- }
+ }
return retval;
}
-//----------------------------------------------------------------------
int cmCTestBuildAndTestHandler::ProcessCommandLineArguments(
const std::string& currentArg, size_t& idx,
const std::vector<std::string>& allArgs)
{
// --build-and-test options
- if(currentArg.find("--build-and-test",0) == 0 && idx < allArgs.size() - 1)
- {
- if(idx+2 < allArgs.size())
- {
+ if (currentArg.find("--build-and-test", 0) == 0 &&
+ idx < allArgs.size() - 1) {
+ if (idx + 2 < allArgs.size()) {
idx++;
this->SourceDir = allArgs[idx];
idx++;
this->BinaryDir = allArgs[idx];
// dir must exist before CollapseFullPath is called
cmSystemTools::MakeDirectory(this->BinaryDir.c_str());
- this->BinaryDir
- = cmSystemTools::CollapseFullPath(this->BinaryDir.c_str());
- this->SourceDir
- = cmSystemTools::CollapseFullPath(this->SourceDir.c_str());
- }
- else
- {
+ this->BinaryDir = cmSystemTools::CollapseFullPath(this->BinaryDir);
+ this->SourceDir = cmSystemTools::CollapseFullPath(this->SourceDir);
+ } else {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "--build-and-test must have source and binary dir" << std::endl);
+ "--build-and-test must have source and binary dir"
+ << std::endl);
return 0;
- }
}
- if(currentArg.find("--build-target",0) == 0 && idx < allArgs.size() - 1)
- {
+ }
+ if (currentArg.find("--build-target", 0) == 0 && idx < allArgs.size() - 1) {
idx++;
this->BuildTargets.push_back(allArgs[idx]);
- }
- if(currentArg.find("--build-nocmake",0) == 0)
- {
+ }
+ if (currentArg.find("--build-nocmake", 0) == 0) {
this->BuildNoCMake = true;
- }
- if(currentArg.find("--build-run-dir",0) == 0 && idx < allArgs.size() - 1)
- {
+ }
+ if (currentArg.find("--build-run-dir", 0) == 0 && idx < allArgs.size() - 1) {
idx++;
this->BuildRunDir = allArgs[idx];
- }
- if(currentArg.find("--build-two-config",0) == 0)
- {
+ }
+ if (currentArg.find("--build-two-config", 0) == 0) {
this->BuildTwoConfig = true;
- }
- if(currentArg.find("--build-exe-dir",0) == 0 && idx < allArgs.size() - 1)
- {
+ }
+ if (currentArg.find("--build-exe-dir", 0) == 0 && idx < allArgs.size() - 1) {
idx++;
this->ExecutableDirectory = allArgs[idx];
- }
- if(currentArg.find("--test-timeout",0) == 0 && idx < allArgs.size() - 1)
- {
+ }
+ if (currentArg.find("--test-timeout", 0) == 0 && idx < allArgs.size() - 1) {
idx++;
this->Timeout = atof(allArgs[idx].c_str());
- }
- if(currentArg == "--build-generator" && idx < allArgs.size() - 1)
- {
+ }
+ if (currentArg == "--build-generator" && idx < allArgs.size() - 1) {
idx++;
this->BuildGenerator = allArgs[idx];
- }
- if(currentArg == "--build-generator-toolset" &&
- idx < allArgs.size() - 1)
- {
+ }
+ if (currentArg == "--build-generator-platform" && idx < allArgs.size() - 1) {
+ idx++;
+ this->BuildGeneratorPlatform = allArgs[idx];
+ }
+ if (currentArg == "--build-generator-toolset" && idx < allArgs.size() - 1) {
idx++;
this->BuildGeneratorToolset = allArgs[idx];
- }
- if(currentArg.find("--build-project",0) == 0 && idx < allArgs.size() - 1)
- {
+ }
+ if (currentArg.find("--build-project", 0) == 0 && idx < allArgs.size() - 1) {
idx++;
this->BuildProject = allArgs[idx];
- }
- if(currentArg.find("--build-makeprogram",0) == 0 &&
- idx < allArgs.size() - 1)
- {
+ }
+ if (currentArg.find("--build-makeprogram", 0) == 0 &&
+ idx < allArgs.size() - 1) {
idx++;
this->BuildMakeProgram = allArgs[idx];
- }
- if(currentArg.find("--build-config-sample",0) == 0 &&
- idx < allArgs.size() - 1)
- {
+ }
+ if (currentArg.find("--build-config-sample", 0) == 0 &&
+ idx < allArgs.size() - 1) {
idx++;
this->ConfigSample = allArgs[idx];
- }
- if(currentArg.find("--build-noclean",0) == 0)
- {
+ }
+ if (currentArg.find("--build-noclean", 0) == 0) {
this->BuildNoClean = true;
- }
- if(currentArg.find("--build-options",0) == 0 && idx < allArgs.size() - 1)
- {
- ++idx;
- bool done = false;
- while(idx < allArgs.size() && !done)
- {
+ }
+ if (currentArg.find("--build-options", 0) == 0) {
+ 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)
- {
+ }
+ if (currentArg.find("--test-command", 0) == 0 && idx < allArgs.size() - 1) {
++idx;
this->TestCommand = allArgs[idx];
- while(idx+1 < allArgs.size())
- {
+ while (idx + 1 < allArgs.size()) {
++idx;
this->TestCommandArgs.push_back(allArgs[idx]);
- }
}
+ }
return 1;
}
-
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.h b/Source/CTest/cmCTestBuildAndTestHandler.h
index ca50c6452..2e85e9fed 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.h
+++ b/Source/CTest/cmCTestBuildAndTestHandler.h
@@ -1,21 +1,16 @@
-/*============================================================================
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestBuildAndTestHandler_h
#define cmCTestBuildAndTestHandler_h
+#include "cmConfigure.h"
#include "cmCTestGenericHandler.h"
-#include "cmListFileCache.h"
+
+#include <sstream>
+#include <stddef.h>
+#include <string>
+#include <vector>
class cmake;
@@ -26,17 +21,17 @@ class cmake;
class cmCTestBuildAndTestHandler : public cmCTestGenericHandler
{
public:
- cmTypeMacro(cmCTestBuildAndTestHandler, cmCTestGenericHandler);
+ typedef cmCTestGenericHandler Superclass;
/*
* The main entry point for this class
*/
- int ProcessHandler();
+ int ProcessHandler() CM_OVERRIDE;
//! Set all the build and test arguments
- virtual int ProcessCommandLineArguments(
- const std::string& currentArg, size_t& idx,
- const std::vector<std::string>& allArgs);
+ int ProcessCommandLineArguments(const std::string& currentArg, size_t& idx,
+ const std::vector<std::string>& allArgs)
+ CM_OVERRIDE;
/*
* Get the output variable
@@ -45,35 +40,34 @@ public:
cmCTestBuildAndTestHandler();
- virtual void Initialize();
+ void Initialize() CM_OVERRIDE;
protected:
///! Run CMake and build a test and then run it as a single test.
int RunCMakeAndTest(std::string* output);
- int RunCMake(std::string* outstring, cmOStringStream &out,
- std::string &cmakeOutString,
- std::string &cwd, cmake *cm);
+ int RunCMake(std::string* outstring, std::ostringstream& out,
+ std::string& cmakeOutString, cmake* cm);
- cmStdString Output;
+ std::string Output;
- std::string BuildGenerator;
- std::string BuildGeneratorToolset;
+ std::string BuildGenerator;
+ std::string BuildGeneratorPlatform;
+ std::string BuildGeneratorToolset;
std::vector<std::string> BuildOptions;
- bool BuildTwoConfig;
- std::string BuildMakeProgram;
- std::string ConfigSample;
- std::string SourceDir;
- std::string BinaryDir;
- std::string BuildProject;
- std::string TestCommand;
- bool BuildNoClean;
- std::string BuildRunDir;
- std::string ExecutableDirectory;
+ bool BuildTwoConfig;
+ std::string BuildMakeProgram;
+ std::string ConfigSample;
+ std::string SourceDir;
+ std::string BinaryDir;
+ std::string BuildProject;
+ std::string TestCommand;
+ bool BuildNoClean;
+ std::string BuildRunDir;
+ std::string ExecutableDirectory;
std::vector<std::string> TestCommandArgs;
std::vector<std::string> BuildTargets;
- bool BuildNoCMake;
- double Timeout;
+ bool BuildNoCMake;
+ double Timeout;
};
#endif
-
diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx
index 1f63185c1..4c8276007 100644
--- a/Source/CTest/cmCTestBuildCommand.cxx
+++ b/Source/CTest/cmCTestBuildCommand.cxx
@@ -1,71 +1,60 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestBuildCommand.h"
#include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
#include "cmCTestBuildHandler.h"
-#include "cmake.h"
+#include "cmCTestGenericHandler.h"
#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+#include <sstream>
+#include <string.h>
+
+class cmExecutionStatus;
-//----------------------------------------------------------------------------
cmCTestBuildCommand::cmCTestBuildCommand()
{
- this->GlobalGenerator = 0;
+ this->GlobalGenerator = CM_NULLPTR;
this->Arguments[ctb_NUMBER_ERRORS] = "NUMBER_ERRORS";
this->Arguments[ctb_NUMBER_WARNINGS] = "NUMBER_WARNINGS";
this->Arguments[ctb_TARGET] = "TARGET";
this->Arguments[ctb_CONFIGURATION] = "CONFIGURATION";
this->Arguments[ctb_FLAGS] = "FLAGS";
this->Arguments[ctb_PROJECT_NAME] = "PROJECT_NAME";
- this->Arguments[ctb_LAST] = 0;
+ this->Arguments[ctb_LAST] = CM_NULLPTR;
this->Last = ctb_LAST;
}
-//----------------------------------------------------------------------------
cmCTestBuildCommand::~cmCTestBuildCommand()
{
- if ( this->GlobalGenerator )
- {
+ if (this->GlobalGenerator) {
delete this->GlobalGenerator;
- this->GlobalGenerator = 0;
- }
+ this->GlobalGenerator = CM_NULLPTR;
+ }
}
-//----------------------------------------------------------------------------
cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
{
- cmCTestGenericHandler* handler
- = this->CTest->GetInitializedHandler("build");
- if ( !handler )
- {
+ cmCTestGenericHandler* handler = this->CTest->GetInitializedHandler("build");
+ if (!handler) {
this->SetError("internal CTest error. Cannot instantiate build handler");
- return 0;
- }
- this->Handler = (cmCTestBuildHandler*)handler;
-
- const char* ctestBuildCommand
- = this->Makefile->GetDefinition("CTEST_BUILD_COMMAND");
- if ( ctestBuildCommand && *ctestBuildCommand )
- {
- this->CTest->SetCTestConfiguration("MakeCommand", ctestBuildCommand);
- }
- else
- {
- const char* cmakeGeneratorName
- = this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR");
- const char* cmakeProjectName
- = (this->Values[ctb_PROJECT_NAME] && *this->Values[ctb_PROJECT_NAME])
+ return CM_NULLPTR;
+ }
+ this->Handler = (cmCTestBuildHandler*)handler;
+
+ const char* ctestBuildCommand =
+ this->Makefile->GetDefinition("CTEST_BUILD_COMMAND");
+ if (ctestBuildCommand && *ctestBuildCommand) {
+ this->CTest->SetCTestConfiguration("MakeCommand", ctestBuildCommand,
+ this->Quiet);
+ } else {
+ const char* cmakeGeneratorName =
+ this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR");
+ const char* cmakeProjectName =
+ (this->Values[ctb_PROJECT_NAME] && *this->Values[ctb_PROJECT_NAME])
? this->Values[ctb_PROJECT_NAME]
: this->Makefile->GetDefinition("CTEST_PROJECT_NAME");
@@ -74,77 +63,73 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
// CTEST_CONFIGURATION_TYPE script variable, or ctest -C command
// line argument... in that order.
//
- const char* ctestBuildConfiguration
- = this->Makefile->GetDefinition("CTEST_BUILD_CONFIGURATION");
- const char* cmakeBuildConfiguration
- = (this->Values[ctb_CONFIGURATION] && *this->Values[ctb_CONFIGURATION])
+ const char* ctestBuildConfiguration =
+ this->Makefile->GetDefinition("CTEST_BUILD_CONFIGURATION");
+ const char* cmakeBuildConfiguration =
+ (this->Values[ctb_CONFIGURATION] && *this->Values[ctb_CONFIGURATION])
? this->Values[ctb_CONFIGURATION]
: ((ctestBuildConfiguration && *ctestBuildConfiguration)
- ? ctestBuildConfiguration
- : this->CTest->GetConfigType().c_str());
+ ? ctestBuildConfiguration
+ : this->CTest->GetConfigType().c_str());
- const char* cmakeBuildAdditionalFlags
- = (this->Values[ctb_FLAGS] && *this->Values[ctb_FLAGS])
+ const char* cmakeBuildAdditionalFlags =
+ (this->Values[ctb_FLAGS] && *this->Values[ctb_FLAGS])
? this->Values[ctb_FLAGS]
: this->Makefile->GetDefinition("CTEST_BUILD_FLAGS");
- const char* cmakeBuildTarget
- = (this->Values[ctb_TARGET] && *this->Values[ctb_TARGET])
+ const char* cmakeBuildTarget =
+ (this->Values[ctb_TARGET] && *this->Values[ctb_TARGET])
? this->Values[ctb_TARGET]
: this->Makefile->GetDefinition("CTEST_BUILD_TARGET");
- if ( cmakeGeneratorName && *cmakeGeneratorName &&
- cmakeProjectName && *cmakeProjectName )
- {
- if ( !cmakeBuildConfiguration )
- {
+ if (cmakeGeneratorName && *cmakeGeneratorName && cmakeProjectName &&
+ *cmakeProjectName) {
+ if (!cmakeBuildConfiguration) {
cmakeBuildConfiguration = "Release";
- }
- if ( this->GlobalGenerator )
- {
- if ( strcmp(this->GlobalGenerator->GetName(),
- cmakeGeneratorName) != 0 )
- {
+ }
+ if (this->GlobalGenerator) {
+ if (this->GlobalGenerator->GetName() != cmakeGeneratorName) {
delete this->GlobalGenerator;
- this->GlobalGenerator = 0;
- }
+ this->GlobalGenerator = CM_NULLPTR;
}
- if ( !this->GlobalGenerator )
- {
+ }
+ if (!this->GlobalGenerator) {
this->GlobalGenerator =
this->Makefile->GetCMakeInstance()->CreateGlobalGenerator(
cmakeGeneratorName);
+ if (!this->GlobalGenerator) {
+ std::string e = "could not create generator named \"";
+ e += cmakeGeneratorName;
+ e += "\"";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e);
+ cmSystemTools::SetFatalErrorOccured();
+ return CM_NULLPTR;
}
- this->GlobalGenerator->FindMakeProgram(this->Makefile);
- const char* cmakeMakeProgram
- = this->Makefile->GetDefinition("CMAKE_MAKE_PROGRAM");
- if(strlen(cmakeBuildConfiguration) == 0)
- {
- const char* config = 0;
+ }
+ if (strlen(cmakeBuildConfiguration) == 0) {
+ const char* config = CM_NULLPTR;
#ifdef CMAKE_INTDIR
config = CMAKE_INTDIR;
#endif
- if(!config)
- {
+ if (!config) {
config = "Debug";
- }
- cmakeBuildConfiguration = config;
}
+ cmakeBuildConfiguration = config;
+ }
std::string dir = this->CTest->GetCTestConfiguration("BuildDirectory");
- std::string buildCommand
- = this->GlobalGenerator->
- GenerateBuildCommand(cmakeMakeProgram,
- cmakeProjectName, dir.c_str(),
- cmakeBuildAdditionalFlags, cmakeBuildTarget,
- cmakeBuildConfiguration, true, false);
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "SetMakeCommand:"
- << buildCommand.c_str() << "\n");
- this->CTest->SetCTestConfiguration("MakeCommand", buildCommand.c_str());
- }
- else
- {
- cmOStringStream ostr;
+ std::string buildCommand =
+ this->GlobalGenerator->GenerateCMakeBuildCommand(
+ cmakeBuildTarget ? cmakeBuildTarget : "", cmakeBuildConfiguration,
+ cmakeBuildAdditionalFlags ? cmakeBuildAdditionalFlags : "",
+ this->Makefile->IgnoreErrorsCMP0061());
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "SetMakeCommand:" << buildCommand << "\n",
+ this->Quiet);
+ this->CTest->SetCTestConfiguration("MakeCommand", buildCommand.c_str(),
+ this->Quiet);
+ } else {
+ std::ostringstream ostr;
+ /* clang-format off */
ostr << "has no project to build. If this is a "
"\"built with CMake\" project, verify that CTEST_CMAKE_GENERATOR "
"and CTEST_PROJECT_NAME are set."
@@ -156,39 +141,38 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
"\n"
"Alternatively, set CTEST_BUILD_COMMAND to build the project "
"with a custom command line.";
- this->SetError(ostr.str().c_str());
- return 0;
- }
+ /* clang-format on */
+ this->SetError(ostr.str());
+ return CM_NULLPTR;
}
+ }
- if(const char* useLaunchers =
- this->Makefile->GetDefinition("CTEST_USE_LAUNCHERS"))
- {
- this->CTest->SetCTestConfiguration("UseLaunchers", useLaunchers);
- }
+ if (const char* useLaunchers =
+ this->Makefile->GetDefinition("CTEST_USE_LAUNCHERS")) {
+ this->CTest->SetCTestConfiguration("UseLaunchers", useLaunchers,
+ this->Quiet);
+ }
+ handler->SetQuiet(this->Quiet);
return handler;
}
-
bool cmCTestBuildCommand::InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus &status)
+ cmExecutionStatus& status)
{
- bool ret = cmCTestHandlerCommand::InitialPass(args, status);
- if ( this->Values[ctb_NUMBER_ERRORS] && *this->Values[ctb_NUMBER_ERRORS])
- {
- cmOStringStream str;
+ bool ret = cmCTestHandlerCommand::InitialPass(args, status);
+ if (this->Values[ctb_NUMBER_ERRORS] && *this->Values[ctb_NUMBER_ERRORS]) {
+ std::ostringstream str;
str << this->Handler->GetTotalErrors();
- this->Makefile->AddDefinition(
- this->Values[ctb_NUMBER_ERRORS], str.str().c_str());
- }
- if ( this->Values[ctb_NUMBER_WARNINGS]
- && *this->Values[ctb_NUMBER_WARNINGS])
- {
- cmOStringStream str;
+ this->Makefile->AddDefinition(this->Values[ctb_NUMBER_ERRORS],
+ str.str().c_str());
+ }
+ if (this->Values[ctb_NUMBER_WARNINGS] &&
+ *this->Values[ctb_NUMBER_WARNINGS]) {
+ std::ostringstream str;
str << this->Handler->GetTotalWarnings();
- this->Makefile->AddDefinition(
- this->Values[ctb_NUMBER_WARNINGS], str.str().c_str());
- }
+ this->Makefile->AddDefinition(this->Values[ctb_NUMBER_WARNINGS],
+ str.str().c_str());
+ }
return ret;
}
diff --git a/Source/CTest/cmCTestBuildCommand.h b/Source/CTest/cmCTestBuildCommand.h
index cabc39b32..9cf6a9652 100644
--- a/Source/CTest/cmCTestBuildCommand.h
+++ b/Source/CTest/cmCTestBuildCommand.h
@@ -1,21 +1,20 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestBuildCommand_h
#define cmCTestBuildCommand_h
+#include "cmConfigure.h"
+
#include "cmCTestHandlerCommand.h"
-class cmGlobalGenerator;
+#include <string>
+#include <vector>
+
class cmCTestBuildHandler;
+class cmCTestGenericHandler;
+class cmCommand;
+class cmExecutionStatus;
+class cmGlobalGenerator;
/** \class cmCTestBuild
* \brief Run a ctest script
@@ -25,62 +24,34 @@ class cmCTestBuildHandler;
class cmCTestBuildCommand : public cmCTestHandlerCommand
{
public:
-
cmCTestBuildCommand();
- ~cmCTestBuildCommand();
+ ~cmCTestBuildCommand() CM_OVERRIDE;
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestBuildCommand* ni = new cmCTestBuildCommand;
ni->CTest = this->CTest;
ni->CTestScriptHandler = this->CTestScriptHandler;
return ni;
- }
+ }
/**
* The name of the command as specified in CMakeList.txt.
*/
- virtual const char* GetName() const { return "ctest_build";}
+ std::string GetName() const CM_OVERRIDE { 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);
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
cmGlobalGenerator* GlobalGenerator;
protected:
cmCTestBuildHandler* Handler;
- enum {
+ enum
+ {
ctb_BUILD = ct_LAST,
ctb_NUMBER_ERRORS,
ctb_NUMBER_WARNINGS,
@@ -91,8 +62,7 @@ protected:
ctb_LAST
};
- cmCTestGenericHandler* InitializeHandler();
+ cmCTestGenericHandler* InitializeHandler() CM_OVERRIDE;
};
-
#endif
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index 39eeb70a3..18ef05c67 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -1,43 +1,22 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestBuildHandler.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
-#include "cmake.h"
-#include "cmMakefile.h"
-#include "cmLocalGenerator.h"
-#include "cmGlobalGenerator.h"
-#include "cmGeneratedFileStream.h"
-#include "cmXMLSafe.h"
#include "cmFileTimeComparison.h"
-
-//#include <cmsys/RegularExpression.hxx>
-#include <cmsys/Process.h>
-#include <cmsys/Directory.hxx>
-
-// used for sleep
-#ifdef _WIN32
-#include "windows.h"
-#endif
-
+#include "cmGeneratedFileStream.h"
+#include "cmMakefile.h"
+#include "cmProcessOutput.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+#include "cmsys/Process.h"
+#include <set>
#include <stdlib.h>
-#include <time.h>
-#include <math.h>
-#include <float.h>
-
-#if defined(__BORLANDC__)
-# pragma warn -8060 /* possibly incorrect assignment */
-#endif
+#include <string.h>
static const char* cmCTestErrorMatches[] = {
"^[Bb]us [Ee]rror",
@@ -69,13 +48,13 @@ static const char* cmCTestErrorMatches[] = {
"^CMake Error.*:",
":[ \\t]cannot find",
":[ \\t]can't find",
- ": \\*\\*\\* No rule to make target \\`.*\\'. Stop",
+ ": \\*\\*\\* No rule to make target [`'].*\\'. Stop",
": \\*\\*\\* No targets specified and no makefile found",
": Invalid loader fixup for symbol",
": Invalid fixups exist",
": Can't find library for",
": internal link edit command failed",
- ": Unrecognized option \\`.*\\'",
+ ": Unrecognized option [`'].*\\'",
"\", line [0-9]+\\.[0-9]+: [0-9]+-[0-9]+ \\([^WI]\\)",
"ld: 0706-006 Cannot find or open library file: -l ",
"ild: \\(argument error\\) can't find library argument ::",
@@ -95,7 +74,7 @@ static const char* cmCTestErrorMatches[] = {
"^The project cannot be built\\.",
"^\\[ERROR\\]",
"^Command .* failed with exit code",
- 0
+ CM_NULLPTR
};
static const char* cmCTestErrorExceptions[] = {
@@ -104,12 +83,13 @@ static const char* cmCTestErrorExceptions[] = {
": warning",
": \\(Warning\\)",
": note",
+ "Note:",
"makefile:",
"Makefile:",
":[ \\t]+Where:",
"([^ :]+):([0-9]+): Warning",
"------ Build started: .* ------",
- 0
+ CM_NULLPTR
};
static const char* cmCTestWarningMatches[] = {
@@ -134,7 +114,7 @@ static const char* cmCTestWarningMatches[] = {
"cc-[0-9]* CC: REMARK File = .*, Line = [0-9]*",
"^CMake Warning.*:",
"^\\[WARNING\\]",
- 0
+ CM_NULLPTR
};
static const char* cmCTestWarningExceptions[] = {
@@ -154,7 +134,7 @@ static const char* cmCTestWarningExceptions[] = {
"ld32: WARNING 85: definition of dataKey in",
"cc: warning 422: Unknown option \"\\+b",
"_with_warning_C",
- 0
+ CM_NULLPTR
};
struct cmCTestBuildCompileErrorWarningRex
@@ -164,19 +144,17 @@ struct cmCTestBuildCompileErrorWarningRex
int LineIndex;
};
-static cmCTestBuildCompileErrorWarningRex
-cmCTestWarningErrorFileLine[] = {
- { "^Warning W[0-9]+ ([a-zA-Z.\\:/0-9_+ ~-]+) ([0-9]+):", 1, 2 },
- { "^([a-zA-Z./0-9_+ ~-]+):([0-9]+):", 1, 2 },
- { "^([a-zA-Z.\\:/0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
- { "^[0-9]+>([a-zA-Z.\\:/0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
- { "^([a-zA-Z./0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
- { "\"([a-zA-Z./0-9_+ ~-]+)\", line ([0-9]+)", 1, 2 },
- { "File = ([a-zA-Z./0-9_+ ~-]+), Line = ([0-9]+)", 1, 2 },
- { 0, 0, 0 }
+static cmCTestBuildCompileErrorWarningRex cmCTestWarningErrorFileLine[] = {
+ { "^Warning W[0-9]+ ([a-zA-Z.\\:/0-9_+ ~-]+) ([0-9]+):", 1, 2 },
+ { "^([a-zA-Z./0-9_+ ~-]+):([0-9]+):", 1, 2 },
+ { "^([a-zA-Z.\\:/0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
+ { "^[0-9]+>([a-zA-Z.\\:/0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
+ { "^([a-zA-Z./0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
+ { "\"([a-zA-Z./0-9_+ ~-]+)\", line ([0-9]+)", 1, 2 },
+ { "File = ([a-zA-Z./0-9_+ ~-]+), Line = ([0-9]+)", 1, 2 },
+ { CM_NULLPTR, 0, 0 }
};
-//----------------------------------------------------------------------
cmCTestBuildHandler::cmCTestBuildHandler()
{
this->MaxPreContext = 10;
@@ -190,7 +168,6 @@ cmCTestBuildHandler::cmCTestBuildHandler()
this->UseCTestLaunch = false;
}
-//----------------------------------------------------------------------
void cmCTestBuildHandler::Initialize()
{
this->Superclass::Initialize();
@@ -236,133 +213,113 @@ void cmCTestBuildHandler::Initialize()
this->UseCTestLaunch = false;
}
-//----------------------------------------------------------------------
-void cmCTestBuildHandler::PopulateCustomVectors(cmMakefile *mf)
+void cmCTestBuildHandler::PopulateCustomVectors(cmMakefile* mf)
{
this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_ERROR_MATCH",
- this->CustomErrorMatches);
+ this->CustomErrorMatches);
this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_ERROR_EXCEPTION",
- this->CustomErrorExceptions);
+ this->CustomErrorExceptions);
this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_WARNING_MATCH",
- this->CustomWarningMatches);
+ this->CustomWarningMatches);
this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_WARNING_EXCEPTION",
- this->CustomWarningExceptions);
- this->CTest->PopulateCustomInteger(mf,
- "CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS",
- this->MaxErrors);
- this->CTest->PopulateCustomInteger(mf,
- "CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS",
- this->MaxWarnings);
+ this->CustomWarningExceptions);
+ this->CTest->PopulateCustomInteger(
+ mf, "CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS", this->MaxErrors);
+ this->CTest->PopulateCustomInteger(
+ mf, "CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS", this->MaxWarnings);
int n = -1;
this->CTest->PopulateCustomInteger(mf, "CTEST_CUSTOM_ERROR_PRE_CONTEXT", n);
- if (n != -1)
- {
+ if (n != -1) {
this->MaxPreContext = static_cast<size_t>(n);
- }
+ }
n = -1;
this->CTest->PopulateCustomInteger(mf, "CTEST_CUSTOM_ERROR_POST_CONTEXT", n);
- if (n != -1)
- {
+ if (n != -1) {
this->MaxPostContext = static_cast<size_t>(n);
- }
+ }
// Record the user-specified custom warning rules.
- if(const char* customWarningMatchers =
- mf->GetDefinition("CTEST_CUSTOM_WARNING_MATCH"))
- {
+ if (const char* customWarningMatchers =
+ mf->GetDefinition("CTEST_CUSTOM_WARNING_MATCH")) {
cmSystemTools::ExpandListArgument(customWarningMatchers,
this->ReallyCustomWarningMatches);
- }
- if(const char* customWarningExceptions =
- mf->GetDefinition("CTEST_CUSTOM_WARNING_EXCEPTION"))
- {
+ }
+ if (const char* customWarningExceptions =
+ mf->GetDefinition("CTEST_CUSTOM_WARNING_EXCEPTION")) {
cmSystemTools::ExpandListArgument(customWarningExceptions,
this->ReallyCustomWarningExceptions);
- }
+ }
}
-//----------------------------------------------------------------------
std::string cmCTestBuildHandler::GetMakeCommand()
{
- std::string makeCommand
- = this->CTest->GetCTestConfiguration("MakeCommand");
- cmCTestLog(this->CTest,
- HANDLER_VERBOSE_OUTPUT, "MakeCommand:" << makeCommand <<
- "\n");
+ std::string makeCommand = this->CTest->GetCTestConfiguration("MakeCommand");
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "MakeCommand:" << makeCommand << "\n", this->Quiet);
std::string configType = this->CTest->GetConfigType();
- if (configType == "")
- {
- configType
- = this->CTest->GetCTestConfiguration("DefaultCTestConfigurationType");
- }
- if (configType == "")
- {
+ if (configType == "") {
+ configType =
+ this->CTest->GetCTestConfiguration("DefaultCTestConfigurationType");
+ }
+ if (configType == "") {
configType = "Release";
- }
+ }
- cmSystemTools::ReplaceString(makeCommand,
- "${CTEST_CONFIGURATION_TYPE}", configType.c_str());
+ cmSystemTools::ReplaceString(makeCommand, "${CTEST_CONFIGURATION_TYPE}",
+ configType.c_str());
return makeCommand;
}
-//----------------------------------------------------------------------
-//clearly it would be nice if this were broken up into a few smaller
-//functions and commented...
+// clearly it would be nice if this were broken up into a few smaller
+// functions and commented...
int cmCTestBuildHandler::ProcessHandler()
{
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "Build project" << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "Build project" << std::endl,
+ this->Quiet);
// do we have time for this
- if (this->CTest->GetRemainingTimeAllowed() < 120)
- {
+ if (this->CTest->GetRemainingTimeAllowed() < 120) {
return 0;
- }
+ }
int entry;
- for ( entry = 0;
- cmCTestWarningErrorFileLine[entry].RegularExpressionString;
- ++ entry )
- {
+ for (entry = 0; cmCTestWarningErrorFileLine[entry].RegularExpressionString;
+ ++entry) {
cmCTestBuildHandler::cmCTestCompileErrorWarningRex r;
- if ( r.RegularExpression.compile(
- cmCTestWarningErrorFileLine[entry].RegularExpressionString) )
- {
+ if (r.RegularExpression.compile(
+ cmCTestWarningErrorFileLine[entry].RegularExpressionString)) {
r.FileIndex = cmCTestWarningErrorFileLine[entry].FileIndex;
r.LineIndex = cmCTestWarningErrorFileLine[entry].LineIndex;
this->ErrorWarningFileLineRegex.push_back(r);
- }
- else
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Problem Compiling regular expression: "
- << cmCTestWarningErrorFileLine[entry].RegularExpressionString
- << std::endl);
- }
+ } else {
+ cmCTestLog(
+ this->CTest, ERROR_MESSAGE, "Problem Compiling regular expression: "
+ << cmCTestWarningErrorFileLine[entry].RegularExpressionString
+ << std::endl);
}
+ }
// Determine build command and build directory
std::string makeCommand = this->GetMakeCommand();
- if ( makeCommand.size() == 0 )
- {
+ if (makeCommand.empty()) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot find MakeCommand key in the DartConfiguration.tcl"
- << std::endl);
+ "Cannot find MakeCommand key in the DartConfiguration.tcl"
+ << std::endl);
return -1;
- }
+ }
- const std::string &buildDirectory
- = this->CTest->GetCTestConfiguration("BuildDirectory");
- if ( buildDirectory.size() == 0 )
- {
+ const std::string& buildDirectory =
+ this->CTest->GetCTestConfiguration("BuildDirectory");
+ if (buildDirectory.empty()) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot find BuildDirectory key in the DartConfiguration.tcl"
- << std::endl);
+ "Cannot find BuildDirectory key in the DartConfiguration.tcl"
+ << std::endl);
return -1;
- }
+ }
std::string const& useLaunchers =
this->CTest->GetCTestConfiguration("UseLaunchers");
@@ -371,94 +328,81 @@ int cmCTestBuildHandler::ProcessHandler()
// Create a last build log
cmGeneratedFileStream ofs;
double elapsed_time_start = cmSystemTools::GetTime();
- if ( !this->StartLogFile("Build", ofs) )
- {
+ if (!this->StartLogFile("Build", ofs)) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create build log file"
- << std::endl);
- }
+ << std::endl);
+ }
// Create lists of regular expression strings for errors, error exceptions,
// warnings and warning exceptions.
- std::vector<cmStdString>::size_type cc;
- for ( cc = 0; cmCTestErrorMatches[cc]; cc ++ )
- {
+ std::vector<std::string>::size_type cc;
+ for (cc = 0; cmCTestErrorMatches[cc]; cc++) {
this->CustomErrorMatches.push_back(cmCTestErrorMatches[cc]);
- }
- for ( cc = 0; cmCTestErrorExceptions[cc]; cc ++ )
- {
+ }
+ for (cc = 0; cmCTestErrorExceptions[cc]; cc++) {
this->CustomErrorExceptions.push_back(cmCTestErrorExceptions[cc]);
- }
- for ( cc = 0; cmCTestWarningMatches[cc]; cc ++ )
- {
+ }
+ for (cc = 0; cmCTestWarningMatches[cc]; cc++) {
this->CustomWarningMatches.push_back(cmCTestWarningMatches[cc]);
- }
+ }
- for ( cc = 0; cmCTestWarningExceptions[cc]; cc ++ )
- {
+ for (cc = 0; cmCTestWarningExceptions[cc]; cc++) {
this->CustomWarningExceptions.push_back(cmCTestWarningExceptions[cc]);
- }
+ }
// Pre-compile regular expressions objects for all regular expressions
- std::vector<cmStdString>::iterator it;
-
-#define cmCTestBuildHandlerPopulateRegexVector(strings, regexes) \
- regexes.clear(); \
- cmCTestLog(this->CTest, DEBUG, this << "Add " #regexes \
- << std::endl); \
- for ( it = strings.begin(); it != strings.end(); ++it ) \
- { \
- cmCTestLog(this->CTest, DEBUG, "Add " #strings ": " \
- << it->c_str() << std::endl); \
- regexes.push_back(it->c_str()); \
- }
- cmCTestBuildHandlerPopulateRegexVector(
- this->CustomErrorMatches, this->ErrorMatchRegex);
- cmCTestBuildHandlerPopulateRegexVector(
- this->CustomErrorExceptions, this->ErrorExceptionRegex);
- cmCTestBuildHandlerPopulateRegexVector(
- this->CustomWarningMatches, this->WarningMatchRegex);
- cmCTestBuildHandlerPopulateRegexVector(
- this->CustomWarningExceptions, this->WarningExceptionRegex);
-
+ std::vector<std::string>::iterator it;
+
+#define cmCTestBuildHandlerPopulateRegexVector(strings, regexes) \
+ regexes.clear(); \
+ cmCTestOptionalLog(this->CTest, DEBUG, \
+ this << "Add " #regexes << std::endl, this->Quiet); \
+ for (it = (strings).begin(); it != (strings).end(); ++it) { \
+ cmCTestOptionalLog(this->CTest, DEBUG, \
+ "Add " #strings ": " << *it << std::endl, \
+ this->Quiet); \
+ (regexes).push_back(it->c_str()); \
+ }
+ cmCTestBuildHandlerPopulateRegexVector(this->CustomErrorMatches,
+ this->ErrorMatchRegex);
+ cmCTestBuildHandlerPopulateRegexVector(this->CustomErrorExceptions,
+ this->ErrorExceptionRegex);
+ cmCTestBuildHandlerPopulateRegexVector(this->CustomWarningMatches,
+ this->WarningMatchRegex);
+ cmCTestBuildHandlerPopulateRegexVector(this->CustomWarningExceptions,
+ this->WarningExceptionRegex);
// Determine source and binary tree substitutions to simplify the output.
this->SimplifySourceDir = "";
this->SimplifyBuildDir = "";
- if ( this->CTest->GetCTestConfiguration("SourceDirectory").size() > 20 )
- {
- std::string srcdir
- = this->CTest->GetCTestConfiguration("SourceDirectory") + "/";
+ if (this->CTest->GetCTestConfiguration("SourceDirectory").size() > 20) {
+ std::string srcdir =
+ this->CTest->GetCTestConfiguration("SourceDirectory") + "/";
std::string srcdirrep;
- for ( cc = srcdir.size()-2; cc > 0; cc -- )
- {
- if ( srcdir[cc] == '/' )
- {
+ for (cc = srcdir.size() - 2; cc > 0; cc--) {
+ if (srcdir[cc] == '/') {
srcdirrep = srcdir.c_str() + cc;
srcdirrep = "/..." + srcdirrep;
- srcdir = srcdir.substr(0, cc+1);
+ srcdir = srcdir.substr(0, cc + 1);
break;
- }
}
- this->SimplifySourceDir = srcdir;
}
- if ( this->CTest->GetCTestConfiguration("BuildDirectory").size() > 20 )
- {
- std::string bindir
- = this->CTest->GetCTestConfiguration("BuildDirectory") + "/";
+ this->SimplifySourceDir = srcdir;
+ }
+ if (this->CTest->GetCTestConfiguration("BuildDirectory").size() > 20) {
+ std::string bindir =
+ this->CTest->GetCTestConfiguration("BuildDirectory") + "/";
std::string bindirrep;
- for ( cc = bindir.size()-2; cc > 0; cc -- )
- {
- if ( bindir[cc] == '/' )
- {
+ for (cc = bindir.size() - 2; cc > 0; cc--) {
+ if (bindir[cc] == '/') {
bindirrep = bindir.c_str() + cc;
bindirrep = "/..." + bindirrep;
- bindir = bindir.substr(0, cc+1);
+ bindir = bindir.substr(0, cc + 1);
break;
- }
}
- this->SimplifyBuildDir = bindir;
}
-
+ this->SimplifyBuildDir = bindir;
+ }
// Ok, let's do the build
@@ -467,16 +411,14 @@ int cmCTestBuildHandler::ProcessHandler()
this->StartBuildTime = cmSystemTools::GetTime();
int retVal = 0;
int res = cmsysProcess_State_Exited;
- if ( !this->CTest->GetShowOnly() )
- {
+ if (!this->CTest->GetShowOnly()) {
res = this->RunMakeCommand(makeCommand.c_str(), &retVal,
- buildDirectory.c_str(), 0, ofs);
- }
- else
- {
- cmCTestLog(this->CTest, DEBUG, "Build with command: " << makeCommand
- << std::endl);
- }
+ buildDirectory.c_str(), 0, ofs);
+ } else {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Build with command: " << makeCommand << std::endl,
+ this->Quiet);
+ }
// Remember end build time and calculate elapsed time
this->EndBuild = this->CTest->CurrentTime();
@@ -485,154 +427,141 @@ int cmCTestBuildHandler::ProcessHandler()
// Cleanups strings in the errors and warnings list.
t_ErrorsAndWarningsVector::iterator evit;
- if ( !this->SimplifySourceDir.empty() )
- {
- for ( evit = this->ErrorsAndWarnings.begin();
- evit != this->ErrorsAndWarnings.end();
- ++ evit )
- {
- cmSystemTools::ReplaceString(
- evit->Text, this->SimplifySourceDir.c_str(), "/.../");
- cmSystemTools::ReplaceString(
- evit->PreContext, this->SimplifySourceDir.c_str(), "/.../");
- cmSystemTools::ReplaceString(
- evit->PostContext, this->SimplifySourceDir.c_str(), "/.../");
- }
+ if (!this->SimplifySourceDir.empty()) {
+ for (evit = this->ErrorsAndWarnings.begin();
+ evit != this->ErrorsAndWarnings.end(); ++evit) {
+ cmSystemTools::ReplaceString(evit->Text, this->SimplifySourceDir.c_str(),
+ "/.../");
+ cmSystemTools::ReplaceString(evit->PreContext,
+ this->SimplifySourceDir.c_str(), "/.../");
+ cmSystemTools::ReplaceString(evit->PostContext,
+ this->SimplifySourceDir.c_str(), "/.../");
}
-
- if ( !this->SimplifyBuildDir.empty() )
- {
- for ( evit = this->ErrorsAndWarnings.begin();
- evit != this->ErrorsAndWarnings.end();
- ++ evit )
- {
- cmSystemTools::ReplaceString(
- evit->Text, this->SimplifyBuildDir.c_str(), "/.../");
- cmSystemTools::ReplaceString(
- evit->PreContext, this->SimplifyBuildDir.c_str(), "/.../");
- cmSystemTools::ReplaceString(
- evit->PostContext, this->SimplifyBuildDir.c_str(), "/.../");
- }
+ }
+
+ if (!this->SimplifyBuildDir.empty()) {
+ for (evit = this->ErrorsAndWarnings.begin();
+ evit != this->ErrorsAndWarnings.end(); ++evit) {
+ cmSystemTools::ReplaceString(evit->Text, this->SimplifyBuildDir.c_str(),
+ "/.../");
+ cmSystemTools::ReplaceString(evit->PreContext,
+ this->SimplifyBuildDir.c_str(), "/.../");
+ cmSystemTools::ReplaceString(evit->PostContext,
+ this->SimplifyBuildDir.c_str(), "/.../");
}
+ }
// Generate XML output
cmGeneratedFileStream xofs;
- if(!this->StartResultingXML(cmCTest::PartBuild, "Build", xofs))
- {
+ if (!this->StartResultingXML(cmCTest::PartBuild, "Build", xofs)) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create build XML file"
- << std::endl);
+ << std::endl);
return -1;
- }
- this->GenerateXMLHeader(xofs);
- if(this->UseCTestLaunch)
- {
- this->GenerateXMLLaunched(xofs);
- }
- else
- {
- this->GenerateXMLLogScraped(xofs);
- }
- this->GenerateXMLFooter(xofs, elapsed_build_time);
-
- if (res != cmsysProcess_State_Exited || retVal || this->TotalErrors > 0)
- {
+ }
+ cmXMLWriter xml(xofs);
+ this->GenerateXMLHeader(xml);
+ if (this->UseCTestLaunch) {
+ this->GenerateXMLLaunched(xml);
+ } else {
+ this->GenerateXMLLogScraped(xml);
+ }
+ this->GenerateXMLFooter(xml, elapsed_build_time);
+
+ if (res != cmsysProcess_State_Exited || retVal || this->TotalErrors > 0) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Error(s) when building project"
- << std::endl);
- }
+ << std::endl);
+ }
// Display message about number of errors and warnings
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " " << this->TotalErrors
- << (this->TotalErrors >= this->MaxErrors ? " or more" : "")
- << " Compiler errors" << std::endl);
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " " << this->TotalWarnings
- << (this->TotalWarnings >= this->MaxWarnings ? " or more" : "")
- << " Compiler warnings" << std::endl);
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " "
+ << this->TotalErrors
+ << (this->TotalErrors >= this->MaxErrors ? " or more" : "")
+ << " Compiler errors" << std::endl);
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " "
+ << this->TotalWarnings
+ << (this->TotalWarnings >= this->MaxWarnings ? " or more" : "")
+ << " Compiler warnings" << std::endl);
return retVal;
}
-//----------------------------------------------------------------------------
-void cmCTestBuildHandler::GenerateXMLHeader(std::ostream& os)
+void cmCTestBuildHandler::GenerateXMLHeader(cmXMLWriter& xml)
{
- this->CTest->StartXML(os, this->AppendXML);
- os << "<Build>\n"
- << "\t<StartDateTime>" << this->StartBuild << "</StartDateTime>\n"
- << "\t<StartBuildTime>" <<
- static_cast<unsigned int>(this->StartBuildTime)
- << "</StartBuildTime>\n"
- << "<BuildCommand>"
- << cmXMLSafe(this->GetMakeCommand())
- << "</BuildCommand>" << std::endl;
+ this->CTest->StartXML(xml, this->AppendXML);
+ xml.StartElement("Build");
+ xml.Element("StartDateTime", this->StartBuild);
+ xml.Element("StartBuildTime",
+ static_cast<unsigned int>(this->StartBuildTime));
+ xml.Element("BuildCommand", this->GetMakeCommand());
}
-//----------------------------------------------------------------------------
class cmCTestBuildHandler::FragmentCompare
{
public:
- FragmentCompare(cmFileTimeComparison* ftc): FTC(ftc) {}
- FragmentCompare(): FTC(0) {}
- bool operator()(std::string const& l, std::string const& r)
- {
+ FragmentCompare(cmFileTimeComparison* ftc)
+ : FTC(ftc)
+ {
+ }
+ FragmentCompare()
+ : FTC(CM_NULLPTR)
+ {
+ }
+ bool operator()(std::string const& l, std::string const& r) const
+ {
// Order files by modification time. Use lexicographic order
// among files with the same time.
int result;
- if(this->FTC->FileTimeCompare(l.c_str(), r.c_str(), &result) &&
- result != 0)
- {
+ if (this->FTC->FileTimeCompare(l.c_str(), r.c_str(), &result) &&
+ result != 0) {
return result < 0;
- }
- else
- {
- return l < r;
- }
}
+ return l < r;
+ }
+
private:
cmFileTimeComparison* FTC;
};
-//----------------------------------------------------------------------------
-void cmCTestBuildHandler::GenerateXMLLaunched(std::ostream& os)
+void cmCTestBuildHandler::GenerateXMLLaunched(cmXMLWriter& xml)
{
- if(this->CTestLaunchDir.empty())
- {
+ if (this->CTestLaunchDir.empty()) {
return;
- }
+ }
// Sort XML fragments in chronological order.
cmFileTimeComparison ftc;
FragmentCompare fragmentCompare(&ftc);
- typedef std::set<cmStdString, FragmentCompare> Fragments;
+ typedef std::set<std::string, FragmentCompare> Fragments;
Fragments fragments(fragmentCompare);
+ // only report the first 50 warnings and first 50 errors
+ int numErrorsAllowed = this->MaxErrors;
+ int numWarningsAllowed = this->MaxWarnings;
// Identify fragments on disk.
cmsys::Directory launchDir;
- launchDir.Load(this->CTestLaunchDir.c_str());
+ launchDir.Load(this->CTestLaunchDir);
unsigned long n = launchDir.GetNumberOfFiles();
- for(unsigned long i=0; i < n; ++i)
- {
+ for (unsigned long i = 0; i < n; ++i) {
const char* fname = launchDir.GetFile(i);
- if(this->IsLaunchedErrorFile(fname))
- {
+ if (this->IsLaunchedErrorFile(fname) && numErrorsAllowed) {
+ numErrorsAllowed--;
fragments.insert(this->CTestLaunchDir + "/" + fname);
++this->TotalErrors;
- }
- else if(this->IsLaunchedWarningFile(fname))
- {
+ } else if (this->IsLaunchedWarningFile(fname) && numWarningsAllowed) {
+ numWarningsAllowed--;
fragments.insert(this->CTestLaunchDir + "/" + fname);
++this->TotalWarnings;
- }
}
+ }
// Copy the fragments into the final XML file.
- for(Fragments::const_iterator fi = fragments.begin();
- fi != fragments.end(); ++fi)
- {
- this->GenerateXMLLaunchedFragment(os, fi->c_str());
- }
+ for (Fragments::const_iterator fi = fragments.begin(); fi != fragments.end();
+ ++fi) {
+ xml.FragmentFile(fi->c_str());
+ }
}
-//----------------------------------------------------------------------------
-void cmCTestBuildHandler::GenerateXMLLogScraped(std::ostream& os)
+void cmCTestBuildHandler::GenerateXMLLogScraped(cmXMLWriter& xml)
{
std::vector<cmCTestBuildErrorWarning>& ew = this->ErrorsAndWarnings;
std::vector<cmCTestBuildErrorWarning>::iterator it;
@@ -643,136 +572,101 @@ void cmCTestBuildHandler::GenerateXMLLogScraped(std::ostream& os)
std::string srcdir = this->CTest->GetCTestConfiguration("SourceDirectory");
// make sure the source dir is in the correct case on windows
// via a call to collapse full path.
- srcdir = cmSystemTools::CollapseFullPath(srcdir.c_str());
+ srcdir = cmSystemTools::CollapseFullPath(srcdir);
srcdir += "/";
- for ( it = ew.begin();
- it != ew.end() && (numErrorsAllowed || numWarningsAllowed); it++ )
- {
- cmCTestBuildErrorWarning *cm = &(*it);
+ for (it = ew.begin();
+ it != ew.end() && (numErrorsAllowed || numWarningsAllowed); it++) {
+ cmCTestBuildErrorWarning* cm = &(*it);
if ((cm->Error && numErrorsAllowed) ||
- (!cm->Error && numWarningsAllowed))
- {
- if (cm->Error)
- {
+ (!cm->Error && numWarningsAllowed)) {
+ if (cm->Error) {
numErrorsAllowed--;
- }
- else
- {
+ } else {
numWarningsAllowed--;
- }
- os << "\t<" << (cm->Error ? "Error" : "Warning") << ">\n"
- << "\t\t<BuildLogLine>" << cm->LogLine << "</BuildLogLine>\n"
- << "\t\t<Text>" << cmXMLSafe(cm->Text).Quotes(false)
- << "\n</Text>" << std::endl;
+ }
+ xml.StartElement(cm->Error ? "Error" : "Warning");
+ xml.Element("BuildLogLine", cm->LogLine);
+ xml.Element("Text", cm->Text);
std::vector<cmCTestCompileErrorWarningRex>::iterator rit;
- for ( rit = this->ErrorWarningFileLineRegex.begin();
- rit != this->ErrorWarningFileLineRegex.end(); ++ rit )
- {
+ for (rit = this->ErrorWarningFileLineRegex.begin();
+ rit != this->ErrorWarningFileLineRegex.end(); ++rit) {
cmsys::RegularExpression* re = &rit->RegularExpression;
- if ( re->find(cm->Text.c_str() ) )
- {
+ if (re->find(cm->Text.c_str())) {
cm->SourceFile = re->match(rit->FileIndex);
// At this point we need to make this->SourceFile relative to
// the source root of the project, so cvs links will work
cmSystemTools::ConvertToUnixSlashes(cm->SourceFile);
- if(cm->SourceFile.find("/.../") != cm->SourceFile.npos)
- {
+ if (cm->SourceFile.find("/.../") != std::string::npos) {
cmSystemTools::ReplaceString(cm->SourceFile, "/.../", "");
- std::string::size_type p = cm->SourceFile.find("/");
- if(p != cm->SourceFile.npos)
- {
- cm->SourceFile = cm->SourceFile.substr(
- p+1, cm->SourceFile.size()-p);
- }
+ std::string::size_type p = cm->SourceFile.find('/');
+ if (p != std::string::npos) {
+ cm->SourceFile =
+ cm->SourceFile.substr(p + 1, cm->SourceFile.size() - p);
}
- else
- {
+ } else {
// make sure it is a full path with the correct case
- cm->SourceFile = cmSystemTools::CollapseFullPath(
- cm->SourceFile.c_str());
- cmSystemTools::ReplaceString(
- cm->SourceFile, srcdir.c_str(), "");
- }
+ cm->SourceFile = cmSystemTools::CollapseFullPath(cm->SourceFile);
+ cmSystemTools::ReplaceString(cm->SourceFile, srcdir.c_str(), "");
+ }
cm->LineNumber = atoi(re->match(rit->LineIndex).c_str());
break;
- }
}
- if ( !cm->SourceFile.empty() && cm->LineNumber >= 0 )
- {
- if ( cm->SourceFile.size() > 0 )
- {
- os << "\t\t<SourceFile>" << cm->SourceFile << "</SourceFile>"
- << std::endl;
- }
- if ( cm->SourceFileTail.size() > 0 )
- {
- os << "\t\t<SourceFileTail>" << cm->SourceFileTail
- << "</SourceFileTail>" << std::endl;
- }
- if ( cm->LineNumber >= 0 )
- {
- os << "\t\t<SourceLineNumber>" << cm->LineNumber
- << "</SourceLineNumber>" << std::endl;
- }
+ }
+ if (!cm->SourceFile.empty() && cm->LineNumber >= 0) {
+ if (!cm->SourceFile.empty()) {
+ xml.Element("SourceFile", cm->SourceFile);
+ }
+ if (!cm->SourceFileTail.empty()) {
+ xml.Element("SourceFileTail", cm->SourceFileTail);
+ }
+ if (cm->LineNumber >= 0) {
+ xml.Element("SourceLineNumber", cm->LineNumber);
}
- os << "\t\t<PreContext>" << cmXMLSafe(cm->PreContext).Quotes(false)
- << "</PreContext>\n"
- << "\t\t<PostContext>" << cmXMLSafe(cm->PostContext).Quotes(false);
+ }
+ xml.Element("PreContext", cm->PreContext);
+ xml.StartElement("PostContext");
+ xml.Content(cm->PostContext);
// is this the last warning or error, if so notify
if ((cm->Error && !numErrorsAllowed) ||
- (!cm->Error && !numWarningsAllowed))
- {
- os << "\nThe maximum number of reported warnings or errors has been "
- "reached!!!\n";
- }
- os << "</PostContext>\n"
- << "\t\t<RepeatCount>0</RepeatCount>\n"
- << "</" << (cm->Error ? "Error" : "Warning") << ">\n\n"
- << std::endl;
+ (!cm->Error && !numWarningsAllowed)) {
+ xml.Content("\nThe maximum number of reported warnings or errors "
+ "has been reached!!!\n");
}
+ xml.EndElement(); // PostContext
+ xml.Element("RepeatCount", "0");
+ xml.EndElement(); // "Error" / "Warning"
}
+ }
}
-//----------------------------------------------------------------------------
-void cmCTestBuildHandler::GenerateXMLFooter(std::ostream& os,
+void cmCTestBuildHandler::GenerateXMLFooter(cmXMLWriter& xml,
double elapsed_build_time)
{
- os << "\t<Log Encoding=\"base64\" Compression=\"/bin/gzip\">\n\t</Log>\n"
- << "\t<EndDateTime>" << this->EndBuild << "</EndDateTime>\n"
- << "\t<EndBuildTime>" << static_cast<unsigned int>(this->EndBuildTime)
- << "</EndBuildTime>\n"
- << "<ElapsedMinutes>" << static_cast<int>(elapsed_build_time/6)/10.0
- << "</ElapsedMinutes>"
- << "</Build>" << std::endl;
- this->CTest->EndXML(os);
-}
-
-//----------------------------------------------------------------------------
-void cmCTestBuildHandler::GenerateXMLLaunchedFragment(std::ostream& os,
- const char* fname)
-{
- std::ifstream fin(fname, std::ios::in | std::ios::binary);
- std::string line;
- while(cmSystemTools::GetLineFromStream(fin, line))
- {
- os << line << "\n";
- }
+ xml.StartElement("Log");
+ xml.Attribute("Encoding", "base64");
+ xml.Attribute("Compression", "bin/gzip");
+ xml.EndElement(); // Log
+
+ xml.Element("EndDateTime", this->EndBuild);
+ xml.Element("EndBuildTime", static_cast<unsigned int>(this->EndBuildTime));
+ xml.Element("ElapsedMinutes",
+ static_cast<int>(elapsed_build_time / 6) / 10.0);
+ xml.EndElement(); // Build
+ this->CTest->EndXML(xml);
}
-//----------------------------------------------------------------------------
bool cmCTestBuildHandler::IsLaunchedErrorFile(const char* fname)
{
// error-{hash}.xml
- return (strncmp(fname, "error-", 6) == 0 &&
- strcmp(fname+strlen(fname)-4, ".xml") == 0);
+ return (cmHasLiteralPrefix(fname, "error-") &&
+ strcmp(fname + strlen(fname) - 4, ".xml") == 0);
}
-//----------------------------------------------------------------------------
bool cmCTestBuildHandler::IsLaunchedWarningFile(const char* fname)
{
// warning-{hash}.xml
- return (strncmp(fname, "warning-", 8) == 0 &&
- strcmp(fname+strlen(fname)-4, ".xml") == 0);
+ return (cmHasLiteralPrefix(fname, "warning-") &&
+ strcmp(fname + strlen(fname) - 4, ".xml") == 0);
}
//######################################################################
@@ -780,12 +674,12 @@ bool cmCTestBuildHandler::IsLaunchedWarningFile(const char* fname)
//######################################################################
//######################################################################
-//----------------------------------------------------------------------------
class cmCTestBuildHandler::LaunchHelper
{
public:
LaunchHelper(cmCTestBuildHandler* handler);
~LaunchHelper();
+
private:
cmCTestBuildHandler* Handler;
cmCTest* CTest;
@@ -795,19 +689,16 @@ private:
std::vector<std::string> const& matchers);
};
-//----------------------------------------------------------------------------
-cmCTestBuildHandler::LaunchHelper::LaunchHelper(cmCTestBuildHandler* handler):
- Handler(handler), CTest(handler->CTest)
+cmCTestBuildHandler::LaunchHelper::LaunchHelper(cmCTestBuildHandler* handler)
+ : Handler(handler)
+ , CTest(handler->CTest)
{
std::string tag = this->CTest->GetCurrentTag();
- if(tag.empty())
- {
+ if (tag.empty()) {
// This is not for a dashboard submission, so there is no XML.
// Skip enabling the launchers.
this->Handler->UseCTestLaunch = false;
- }
- else
- {
+ } else {
// Compute a directory in which to store launcher fragments.
std::string& launchDir = this->Handler->CTestLaunchDir;
launchDir = this->CTest->GetBinaryDir();
@@ -816,36 +707,31 @@ cmCTestBuildHandler::LaunchHelper::LaunchHelper(cmCTestBuildHandler* handler):
launchDir += "/Build";
// Clean out any existing launcher fragments.
- cmSystemTools::RemoveADirectory(launchDir.c_str());
+ cmSystemTools::RemoveADirectory(launchDir);
- if(this->Handler->UseCTestLaunch)
- {
+ if (this->Handler->UseCTestLaunch) {
// Enable launcher fragments.
cmSystemTools::MakeDirectory(launchDir.c_str());
this->WriteLauncherConfig();
std::string launchEnv = "CTEST_LAUNCH_LOGS=";
launchEnv += launchDir;
- cmSystemTools::PutEnv(launchEnv.c_str());
- }
+ cmSystemTools::PutEnv(launchEnv);
}
+ }
// If not using launchers, make sure they passthru.
- if(!this->Handler->UseCTestLaunch)
- {
+ if (!this->Handler->UseCTestLaunch) {
cmSystemTools::UnsetEnv("CTEST_LAUNCH_LOGS");
- }
+ }
}
-//----------------------------------------------------------------------------
cmCTestBuildHandler::LaunchHelper::~LaunchHelper()
{
- if(this->Handler->UseCTestLaunch)
- {
+ if (this->Handler->UseCTestLaunch) {
cmSystemTools::UnsetEnv("CTEST_LAUNCH_LOGS");
- }
+ }
}
-//----------------------------------------------------------------------------
void cmCTestBuildHandler::LaunchHelper::WriteLauncherConfig()
{
this->WriteScrapeMatchers("Warning",
@@ -861,55 +747,50 @@ void cmCTestBuildHandler::LaunchHelper::WriteLauncherConfig()
fout << "set(CTEST_SOURCE_DIRECTORY \"" << srcdir << "\")\n";
}
-//----------------------------------------------------------------------------
-void
-cmCTestBuildHandler::LaunchHelper
-::WriteScrapeMatchers(const char* purpose,
- std::vector<std::string> const& matchers)
+void cmCTestBuildHandler::LaunchHelper::WriteScrapeMatchers(
+ const char* purpose, std::vector<std::string> const& matchers)
{
- if(matchers.empty())
- {
+ if (matchers.empty()) {
return;
- }
+ }
std::string fname = this->Handler->CTestLaunchDir;
fname += "/Custom";
fname += purpose;
fname += ".txt";
cmGeneratedFileStream fout(fname.c_str());
- for(std::vector<std::string>::const_iterator mi = matchers.begin();
- mi != matchers.end(); ++mi)
- {
+ for (std::vector<std::string>::const_iterator mi = matchers.begin();
+ mi != matchers.end(); ++mi) {
fout << *mi << "\n";
- }
+ }
}
-//----------------------------------------------------------------------
-int cmCTestBuildHandler::RunMakeCommand(const char* command,
- int* retVal, const char* dir, int timeout, std::ofstream& ofs)
+int cmCTestBuildHandler::RunMakeCommand(const char* command, int* retVal,
+ const char* dir, int timeout,
+ std::ostream& ofs, Encoding encoding)
{
// First generate the command and arguments
- std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);
+ std::vector<std::string> args = cmSystemTools::ParseArguments(command);
- if(args.size() < 1)
- {
+ if (args.empty()) {
return false;
- }
+ }
std::vector<const char*> argv;
- for(std::vector<cmStdString>::const_iterator a = args.begin();
- a != args.end(); ++a)
- {
+ for (std::vector<std::string>::const_iterator a = args.begin();
+ a != args.end(); ++a) {
argv.push_back(a->c_str());
- }
- argv.push_back(0);
+ }
+ argv.push_back(CM_NULLPTR);
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run command:");
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run command:",
+ this->Quiet);
std::vector<const char*>::iterator ait;
- for ( ait = argv.begin(); ait != argv.end() && *ait; ++ ait )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " \"" << *ait << "\"");
- }
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl);
+ for (ait = argv.begin(); ait != argv.end() && *ait; ++ait) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " \"" << *ait << "\"", this->Quiet);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl,
+ this->Quiet);
// Optionally use make rule launchers to record errors and warnings.
LaunchHelper launchHelper(this);
@@ -929,12 +810,16 @@ int cmCTestBuildHandler::RunMakeCommand(const char* command,
char* data;
int length;
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- " Each symbol represents " << tick_len << " bytes of output."
- << std::endl
- << (this->UseCTestLaunch? "" :
- " '!' represents an error and '*' a warning.\n")
- << " " << std::flush);
+ cmProcessOutput processOutput(encoding);
+ std::string strdata;
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_PROGRESS_OUTPUT, " Each symbol represents "
+ << tick_len << " bytes of output." << std::endl
+ << (this->UseCTestLaunch
+ ? ""
+ : " '!' represents an error and '*' a warning.\n")
+ << " " << std::flush,
+ this->Quiet);
// Initialize building structures
this->BuildProcessingQueue.clear();
@@ -949,94 +834,97 @@ int cmCTestBuildHandler::RunMakeCommand(const char* command,
// For every chunk of data
int res;
- while((res = cmsysProcess_WaitForData(cp, &data, &length, 0)))
- {
+ while ((res = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR))) {
// Replace '\0' with '\n', since '\0' does not really make sense. This is
// for Visual Studio output
- for(int cc =0; cc < length; ++cc)
- {
- if(data[cc] == 0)
- {
+ for (int cc = 0; cc < length; ++cc) {
+ if (data[cc] == 0) {
data[cc] = '\n';
- }
}
+ }
// Process the chunk of data
- if ( res == cmsysProcess_Pipe_STDERR )
- {
- this->ProcessBuffer(data, length, tick, tick_len, ofs,
- &this->BuildProcessingErrorQueue);
- }
- else
- {
- this->ProcessBuffer(data, length, tick, tick_len, ofs,
- &this->BuildProcessingQueue);
- }
+ if (res == cmsysProcess_Pipe_STDERR) {
+ processOutput.DecodeText(data, length, strdata, 1);
+ this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs,
+ &this->BuildProcessingErrorQueue);
+ } else {
+ processOutput.DecodeText(data, length, strdata, 2);
+ this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs,
+ &this->BuildProcessingQueue);
}
-
- this->ProcessBuffer(0, 0, tick, tick_len, ofs, &this->BuildProcessingQueue);
- this->ProcessBuffer(0, 0, tick, tick_len, ofs,
- &this->BuildProcessingErrorQueue);
- cmCTestLog(this->CTest, OUTPUT, " Size of output: "
- << ((this->BuildOutputLogSize + 512) / 1024) << "K" << std::endl);
+ }
+ processOutput.DecodeText(std::string(), strdata, 1);
+ if (!strdata.empty()) {
+ this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs,
+ &this->BuildProcessingErrorQueue);
+ }
+ processOutput.DecodeText(std::string(), strdata, 2);
+ if (!strdata.empty()) {
+ this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs,
+ &this->BuildProcessingQueue);
+ }
+
+ this->ProcessBuffer(CM_NULLPTR, 0, tick, tick_len, ofs,
+ &this->BuildProcessingQueue);
+ this->ProcessBuffer(CM_NULLPTR, 0, tick, tick_len, ofs,
+ &this->BuildProcessingErrorQueue);
+ cmCTestOptionalLog(this->CTest, HANDLER_PROGRESS_OUTPUT, " Size of output: "
+ << ((this->BuildOutputLogSize + 512) / 1024) << "K"
+ << std::endl,
+ this->Quiet);
// Properly handle output of the build command
- cmsysProcess_WaitForExit(cp, 0);
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
int result = cmsysProcess_GetState(cp);
- if(result == cmsysProcess_State_Exited)
- {
- if (retVal)
- {
+ if (result == cmsysProcess_State_Exited) {
+ if (retVal) {
*retVal = cmsysProcess_GetExitValue(cp);
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Command exited with the value: " << *retVal << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Command exited with the value: " << *retVal
+ << std::endl,
+ this->Quiet);
// if a non zero return value
- if (*retVal)
- {
+ if (*retVal) {
// If there was an error running command, report that on the
// dashboard.
cmCTestBuildErrorWarning errorwarning;
- errorwarning.LogLine = 1;
- errorwarning.Text
- = "*** WARNING non-zero return value in ctest from: ";
- errorwarning.Text += argv[0];
- errorwarning.PreContext = "";
+ errorwarning.LogLine = 1;
+ errorwarning.Text =
+ "*** WARNING non-zero return value in ctest from: ";
+ errorwarning.Text += argv[0];
+ errorwarning.PreContext = "";
errorwarning.PostContext = "";
- errorwarning.Error = false;
+ errorwarning.Error = false;
this->ErrorsAndWarnings.push_back(errorwarning);
- this->TotalWarnings ++;
- }
+ this->TotalWarnings++;
}
}
- else if(result == cmsysProcess_State_Exception)
- {
- if (retVal)
- {
+ } else if (result == cmsysProcess_State_Exception) {
+ if (retVal) {
*retVal = cmsysProcess_GetExitException(cp);
- cmCTestLog(this->CTest, WARNING, "There was an exception: " << *retVal
- << std::endl);
- }
- }
- else if(result == cmsysProcess_State_Expired)
- {
- cmCTestLog(this->CTest, WARNING, "There was a timeout" << std::endl);
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "There was an exception: " << *retVal << std::endl,
+ this->Quiet);
}
- else if(result == cmsysProcess_State_Error)
- {
+ } else if (result == cmsysProcess_State_Expired) {
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "There was a timeout" << std::endl, this->Quiet);
+ } else if (result == cmsysProcess_State_Error) {
// If there was an error running command, report that on the dashboard.
cmCTestBuildErrorWarning errorwarning;
- errorwarning.LogLine = 1;
- errorwarning.Text = "*** ERROR executing: ";
- errorwarning.Text += cmsysProcess_GetErrorString(cp);
- errorwarning.PreContext = "";
+ errorwarning.LogLine = 1;
+ errorwarning.Text = "*** ERROR executing: ";
+ errorwarning.Text += cmsysProcess_GetErrorString(cp);
+ errorwarning.PreContext = "";
errorwarning.PostContext = "";
- errorwarning.Error = true;
+ errorwarning.Error = true;
this->ErrorsAndWarnings.push_back(errorwarning);
- this->TotalErrors ++;
+ this->TotalErrors++;
cmCTestLog(this->CTest, ERROR_MESSAGE, "There was an error: "
- << cmsysProcess_GetErrorString(cp) << std::endl);
- }
+ << cmsysProcess_GetErrorString(cp) << std::endl);
+ }
cmsysProcess_Delete(cp);
return result;
@@ -1047,55 +935,43 @@ int cmCTestBuildHandler::RunMakeCommand(const char* command,
//######################################################################
//######################################################################
-//----------------------------------------------------------------------
-void cmCTestBuildHandler::ProcessBuffer(const char* data, int length,
- size_t& tick, size_t tick_len, std::ofstream& ofs,
- t_BuildProcessingQueueType* queue)
+void cmCTestBuildHandler::ProcessBuffer(const char* data, size_t length,
+ size_t& tick, size_t tick_len,
+ std::ostream& ofs,
+ t_BuildProcessingQueueType* queue)
{
const std::string::size_type tick_line_len = 50;
const char* ptr;
- for ( ptr = data; ptr < data+length; ptr ++ )
- {
+ for (ptr = data; ptr < data + length; ptr++) {
queue->push_back(*ptr);
- }
+ }
this->BuildOutputLogSize += length;
// until there are any lines left in the buffer
- while ( 1 )
- {
+ while (true) {
// Find the end of line
t_BuildProcessingQueueType::iterator it;
- for ( it = queue->begin();
- it != queue->end();
- ++ it )
- {
- if ( *it == '\n' )
- {
+ for (it = queue->begin(); it != queue->end(); ++it) {
+ if (*it == '\n') {
break;
- }
}
+ }
// Once certain number of errors or warnings reached, ignore future errors
// or warnings.
- if ( this->TotalWarnings >= this->MaxWarnings )
- {
+ if (this->TotalWarnings >= this->MaxWarnings) {
this->WarningQuotaReached = true;
- }
- if ( this->TotalErrors >= this->MaxErrors )
- {
+ }
+ if (this->TotalErrors >= this->MaxErrors) {
this->ErrorQuotaReached = true;
- }
+ }
// If the end of line was found
- if ( it != queue->end() )
- {
+ if (it != queue->end()) {
// Create a contiguous array for the line
this->CurrentProcessingLine.clear();
- t_BuildProcessingQueueType::iterator cit;
- for ( cit = queue->begin(); cit != it; ++cit )
- {
- this->CurrentProcessingLine.push_back(*cit);
- }
+ this->CurrentProcessingLine.insert(this->CurrentProcessingLine.end(),
+ queue->begin(), it);
this->CurrentProcessingLine.push_back(0);
const char* line = &*this->CurrentProcessingLine.begin();
@@ -1103,120 +979,107 @@ void cmCTestBuildHandler::ProcessBuffer(const char* data, int length,
int lineType = this->ProcessSingleLine(line);
// Erase the line from the queue
- queue->erase(queue->begin(), it+1);
+ queue->erase(queue->begin(), it + 1);
// Depending on the line type, produce error or warning, or nothing
cmCTestBuildErrorWarning errorwarning;
bool found = false;
- switch ( lineType )
- {
- case b_WARNING_LINE:
- this->LastTickChar = '*';
- errorwarning.Error = false;
- found = true;
- this->TotalWarnings ++;
- break;
- case b_ERROR_LINE:
- this->LastTickChar = '!';
- errorwarning.Error = true;
- found = true;
- this->TotalErrors ++;
- break;
- }
- if ( found )
- {
+ switch (lineType) {
+ case b_WARNING_LINE:
+ this->LastTickChar = '*';
+ errorwarning.Error = false;
+ found = true;
+ this->TotalWarnings++;
+ break;
+ case b_ERROR_LINE:
+ this->LastTickChar = '!';
+ errorwarning.Error = true;
+ found = true;
+ this->TotalErrors++;
+ break;
+ }
+ if (found) {
// This is an error or warning, so generate report
- errorwarning.LogLine = static_cast<int>(this->OutputLineCounter+1);
- errorwarning.Text = line;
- errorwarning.PreContext = "";
+ errorwarning.LogLine = static_cast<int>(this->OutputLineCounter + 1);
+ errorwarning.Text = line;
+ errorwarning.PreContext = "";
errorwarning.PostContext = "";
// Copy pre-context to report
- std::deque<cmStdString>::iterator pcit;
- for ( pcit = this->PreContext.begin();
- pcit != this->PreContext.end();
- ++pcit )
- {
+ std::deque<std::string>::iterator pcit;
+ for (pcit = this->PreContext.begin(); pcit != this->PreContext.end();
+ ++pcit) {
errorwarning.PreContext += *pcit + "\n";
- }
+ }
this->PreContext.clear();
// Store report
this->ErrorsAndWarnings.push_back(errorwarning);
- this->LastErrorOrWarning = this->ErrorsAndWarnings.end()-1;
+ this->LastErrorOrWarning = this->ErrorsAndWarnings.end() - 1;
this->PostContextCount = 0;
- }
- else
- {
+ } else {
// This is not an error or warning.
// So, figure out if this is a post-context line
- if ( this->ErrorsAndWarnings.size() &&
- this->LastErrorOrWarning != this->ErrorsAndWarnings.end() &&
- this->PostContextCount < this->MaxPostContext )
- {
- this->PostContextCount ++;
+ if (!this->ErrorsAndWarnings.empty() &&
+ this->LastErrorOrWarning != this->ErrorsAndWarnings.end() &&
+ this->PostContextCount < this->MaxPostContext) {
+ this->PostContextCount++;
this->LastErrorOrWarning->PostContext += line;
- if ( this->PostContextCount < this->MaxPostContext )
- {
+ if (this->PostContextCount < this->MaxPostContext) {
this->LastErrorOrWarning->PostContext += "\n";
- }
}
- else
- {
+ } else {
// Otherwise store pre-context for the next error
this->PreContext.push_back(line);
- if ( this->PreContext.size() > this->MaxPreContext )
- {
+ if (this->PreContext.size() > this->MaxPreContext) {
this->PreContext.erase(this->PreContext.begin(),
- this->PreContext.end()-this->MaxPreContext);
- }
+ this->PreContext.end() -
+ this->MaxPreContext);
}
}
- this->OutputLineCounter ++;
}
- else
- {
+ this->OutputLineCounter++;
+ } else {
break;
- }
}
+ }
// Now that the buffer is processed, display missing ticks
int tickDisplayed = false;
- while ( this->BuildOutputLogSize > (tick * tick_len) )
- {
- tick ++;
- cmCTestLog(this->CTest, HANDLER_OUTPUT, this->LastTickChar);
+ while (this->BuildOutputLogSize > (tick * tick_len)) {
+ tick++;
+ cmCTestOptionalLog(this->CTest, HANDLER_PROGRESS_OUTPUT,
+ this->LastTickChar, this->Quiet);
tickDisplayed = true;
- if ( tick % tick_line_len == 0 && tick > 0 )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Size: "
- << ((this->BuildOutputLogSize + 512) / 1024) << "K" << std::endl
- << " ");
- }
+ if (tick % tick_line_len == 0 && tick > 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_PROGRESS_OUTPUT, " Size: "
+ << ((this->BuildOutputLogSize + 512) / 1024) << "K"
+ << std::endl
+ << " ",
+ this->Quiet);
}
- if ( tickDisplayed )
- {
+ }
+ if (tickDisplayed) {
this->LastTickChar = '.';
- }
+ }
// And if this is verbose output, display the content of the chunk
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- cmCTestLogWrite(data, length));
+ cmCTestLogWrite(data, length));
// Always store the chunk to the file
ofs << cmCTestLogWrite(data, length);
}
-//----------------------------------------------------------------------
int cmCTestBuildHandler::ProcessSingleLine(const char* data)
{
- if(this->UseCTestLaunch)
- {
+ if (this->UseCTestLaunch) {
// No log scraping when using launchers.
return b_REGULAR_LINE;
- }
+ }
- cmCTestLog(this->CTest, DEBUG, "Line: [" << data << "]" << std::endl);
+ cmCTestOptionalLog(this->CTest, DEBUG, "Line: [" << data << "]" << std::endl,
+ this->Quiet);
std::vector<cmsys::RegularExpression>::iterator it;
@@ -1225,86 +1088,76 @@ int cmCTestBuildHandler::ProcessSingleLine(const char* data)
// Check for regular expressions
- if ( !this->ErrorQuotaReached )
- {
+ if (!this->ErrorQuotaReached) {
// Errors
int wrxCnt = 0;
- for ( it = this->ErrorMatchRegex.begin();
- it != this->ErrorMatchRegex.end();
- ++ it )
- {
- if ( it->find(data) )
- {
+ for (it = this->ErrorMatchRegex.begin(); it != this->ErrorMatchRegex.end();
+ ++it) {
+ if (it->find(data)) {
errorLine = 1;
- cmCTestLog(this->CTest, DEBUG, " Error Line: " << data
- << " (matches: " << this->CustomErrorMatches[wrxCnt] << ")"
- << std::endl);
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ " Error Line: " << data << " (matches: "
+ << this->CustomErrorMatches[wrxCnt]
+ << ")" << std::endl,
+ this->Quiet);
break;
- }
- wrxCnt ++;
}
+ wrxCnt++;
+ }
// Error exceptions
wrxCnt = 0;
- for ( it = this->ErrorExceptionRegex.begin();
- it != this->ErrorExceptionRegex.end();
- ++ it )
- {
- if ( it->find(data) )
- {
+ for (it = this->ErrorExceptionRegex.begin();
+ it != this->ErrorExceptionRegex.end(); ++it) {
+ if (it->find(data)) {
errorLine = 0;
- cmCTestLog(this->CTest, DEBUG, " Not an error Line: " << data
- << " (matches: " << this->CustomErrorExceptions[wrxCnt] << ")"
- << std::endl);
+ cmCTestOptionalLog(this->CTest, DEBUG, " Not an error Line: "
+ << data << " (matches: "
+ << this->CustomErrorExceptions[wrxCnt] << ")"
+ << std::endl,
+ this->Quiet);
break;
- }
- wrxCnt ++;
}
+ wrxCnt++;
}
- if ( !this->WarningQuotaReached )
- {
+ }
+ if (!this->WarningQuotaReached) {
// Warnings
int wrxCnt = 0;
- for ( it = this->WarningMatchRegex.begin();
- it != this->WarningMatchRegex.end();
- ++ it )
- {
- if ( it->find(data) )
- {
+ for (it = this->WarningMatchRegex.begin();
+ it != this->WarningMatchRegex.end(); ++it) {
+ if (it->find(data)) {
warningLine = 1;
- cmCTestLog(this->CTest, DEBUG,
- " Warning Line: " << data
- << " (matches: " << this->CustomWarningMatches[wrxCnt] << ")"
- << std::endl);
+ cmCTestOptionalLog(this->CTest, DEBUG, " Warning Line: "
+ << data << " (matches: "
+ << this->CustomWarningMatches[wrxCnt] << ")"
+ << std::endl,
+ this->Quiet);
break;
- }
- wrxCnt ++;
}
+ wrxCnt++;
+ }
wrxCnt = 0;
// Warning exceptions
- for ( it = this->WarningExceptionRegex.begin();
- it != this->WarningExceptionRegex.end();
- ++ it )
- {
- if ( it->find(data) )
- {
+ for (it = this->WarningExceptionRegex.begin();
+ it != this->WarningExceptionRegex.end(); ++it) {
+ if (it->find(data)) {
warningLine = 0;
- cmCTestLog(this->CTest, DEBUG, " Not a warning Line: " << data
- << " (matches: " << this->CustomWarningExceptions[wrxCnt] << ")"
- << std::endl);
+ cmCTestOptionalLog(this->CTest, DEBUG, " Not a warning Line: "
+ << data << " (matches: "
+ << this->CustomWarningExceptions[wrxCnt] << ")"
+ << std::endl,
+ this->Quiet);
break;
- }
- wrxCnt ++;
}
+ wrxCnt++;
}
- if ( errorLine )
- {
+ }
+ if (errorLine) {
return b_ERROR_LINE;
- }
- if ( warningLine )
- {
+ }
+ if (warningLine) {
return b_WARNING_LINE;
- }
+ }
return b_REGULAR_LINE;
}
-
diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h
index 439efd604..ef3cddf1b 100644
--- a/Source/CTest/cmCTestBuildHandler.h
+++ b/Source/CTest/cmCTestBuildHandler.h
@@ -1,25 +1,22 @@
-/*============================================================================
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestBuildHandler_h
#define cmCTestBuildHandler_h
+#include "cmConfigure.h"
#include "cmCTestGenericHandler.h"
-#include "cmListFileCache.h"
-#include <cmsys/RegularExpression.hxx>
+#include "cmProcessOutput.h"
+#include "cmsys/RegularExpression.hxx"
+#include <deque>
+#include <iosfwd>
+#include <stddef.h>
+#include <string>
+#include <vector>
class cmMakefile;
+class cmXMLWriter;
/** \class cmCTestBuildHandler
* \brief A class that handles ctest -S invocations
@@ -28,79 +25,80 @@ class cmMakefile;
class cmCTestBuildHandler : public cmCTestGenericHandler
{
public:
- cmTypeMacro(cmCTestBuildHandler, cmCTestGenericHandler);
+ typedef cmCTestGenericHandler Superclass;
+ typedef cmProcessOutput::Encoding Encoding;
/*
* The main entry point for this class
*/
- int ProcessHandler();
+ int ProcessHandler() CM_OVERRIDE;
cmCTestBuildHandler();
- void PopulateCustomVectors(cmMakefile *mf);
+ void PopulateCustomVectors(cmMakefile* mf) CM_OVERRIDE;
/**
* Initialize handler
*/
- virtual void Initialize();
+ void Initialize() CM_OVERRIDE;
- int GetTotalErrors() { return this->TotalErrors;}
- int GetTotalWarnings() { return this->TotalWarnings;}
+ int GetTotalErrors() { return this->TotalErrors; }
+ int GetTotalWarnings() { return this->TotalWarnings; }
private:
std::string GetMakeCommand();
//! Run command specialized for make and configure. Returns process status
// and retVal is return value or exception.
- int RunMakeCommand(const char* command,
- int* retVal, const char* dir, int timeout,
- std::ofstream& ofs);
+ int RunMakeCommand(const char* command, int* retVal, const char* dir,
+ int timeout, std::ostream& ofs,
+ Encoding encoding = cmProcessOutput::Auto);
- enum {
+ enum
+ {
b_REGULAR_LINE,
b_WARNING_LINE,
b_ERROR_LINE
};
class cmCTestCompileErrorWarningRex
- {
+ {
public:
cmCTestCompileErrorWarningRex() {}
int FileIndex;
int LineIndex;
cmsys::RegularExpression RegularExpression;
- };
+ };
struct cmCTestBuildErrorWarning
{
- bool Error;
- int LogLine;
+ bool Error;
+ int LogLine;
std::string Text;
std::string SourceFile;
std::string SourceFileTail;
- int LineNumber;
+ int LineNumber;
std::string PreContext;
std::string PostContext;
};
// generate the XML output
- void GenerateXMLHeader(std::ostream& os);
- void GenerateXMLLaunched(std::ostream& os);
- void GenerateXMLLogScraped(std::ostream& os);
- void GenerateXMLFooter(std::ostream& os, double elapsed_build_time);
- void GenerateXMLLaunchedFragment(std::ostream& os, const char* fname);
+ void GenerateXMLHeader(cmXMLWriter& xml);
+ void GenerateXMLLaunched(cmXMLWriter& xml);
+ void GenerateXMLLogScraped(cmXMLWriter& xml);
+ void GenerateXMLFooter(cmXMLWriter& xml, double elapsed_build_time);
bool IsLaunchedErrorFile(const char* fname);
bool IsLaunchedWarningFile(const char* fname);
- std::string StartBuild;
- std::string EndBuild;
- double StartBuildTime;
- double EndBuildTime;
+ std::string StartBuild;
+ std::string EndBuild;
+ double StartBuildTime;
+ double EndBuildTime;
- std::vector<cmStdString> CustomErrorMatches;
- std::vector<cmStdString> CustomErrorExceptions;
- std::vector<cmStdString> CustomWarningMatches;
- std::vector<cmStdString> CustomWarningExceptions;
+ std::vector<std::string> CustomErrorMatches;
+ std::vector<std::string> CustomErrorExceptions;
+ std::vector<std::string> CustomWarningMatches;
+ std::vector<std::string> CustomWarningExceptions;
std::vector<std::string> ReallyCustomWarningMatches;
std::vector<std::string> ReallyCustomWarningExceptions;
std::vector<cmCTestCompileErrorWarningRex> ErrorWarningFileLineRegex;
@@ -112,39 +110,41 @@ 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);
+ void ProcessBuffer(const char* data, size_t length, size_t& tick,
+ size_t tick_len, std::ostream& ofs,
+ t_BuildProcessingQueueType* queue);
int ProcessSingleLine(const char* data);
- t_BuildProcessingQueueType BuildProcessingQueue;
- t_BuildProcessingQueueType BuildProcessingErrorQueue;
- size_t BuildOutputLogSize;
- std::vector<char> CurrentProcessingLine;
+ t_BuildProcessingQueueType BuildProcessingQueue;
+ t_BuildProcessingQueueType BuildProcessingErrorQueue;
+ size_t BuildOutputLogSize;
+ std::vector<char> CurrentProcessingLine;
- cmStdString SimplifySourceDir;
- cmStdString SimplifyBuildDir;
- size_t OutputLineCounter;
+ std::string SimplifySourceDir;
+ std::string SimplifyBuildDir;
+ size_t OutputLineCounter;
typedef std::vector<cmCTestBuildErrorWarning> t_ErrorsAndWarningsVector;
- t_ErrorsAndWarningsVector ErrorsAndWarnings;
- t_ErrorsAndWarningsVector::iterator LastErrorOrWarning;
- size_t PostContextCount;
- size_t MaxPreContext;
- size_t MaxPostContext;
- std::deque<cmStdString> PreContext;
+ t_ErrorsAndWarningsVector ErrorsAndWarnings;
+ t_ErrorsAndWarningsVector::iterator LastErrorOrWarning;
+ size_t PostContextCount;
+ size_t MaxPreContext;
+ size_t MaxPostContext;
+ std::deque<std::string> PreContext;
- int TotalErrors;
- int TotalWarnings;
- char LastTickChar;
+ int TotalErrors;
+ int TotalWarnings;
+ char LastTickChar;
- bool ErrorQuotaReached;
- bool WarningQuotaReached;
+ bool ErrorQuotaReached;
+ bool WarningQuotaReached;
- int MaxErrors;
- int MaxWarnings;
+ int MaxErrors;
+ int MaxWarnings;
bool UseCTestLaunch;
std::string CTestLaunchDir;
class LaunchHelper;
+
friend class LaunchHelper;
class FragmentCompare;
};
diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx
index 726950704..fad360ba4 100644
--- a/Source/CTest/cmCTestCVS.cxx
+++ b/Source/CTest/cmCTestCVS.cxx
@@ -1,38 +1,31 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestCVS.h"
#include "cmCTest.h"
+#include "cmProcessTools.h"
#include "cmSystemTools.h"
-#include "cmXMLSafe.h"
+#include "cmXMLWriter.h"
-#include <cmsys/RegularExpression.hxx>
+#include "cmsys/FStream.hxx"
+#include "cmsys/RegularExpression.hxx"
+#include <utility>
-//----------------------------------------------------------------------------
-cmCTestCVS::cmCTestCVS(cmCTest* ct, std::ostream& log): cmCTestVC(ct, log)
+cmCTestCVS::cmCTestCVS(cmCTest* ct, std::ostream& log)
+ : cmCTestVC(ct, log)
{
}
-//----------------------------------------------------------------------------
cmCTestCVS::~cmCTestCVS()
{
}
-//----------------------------------------------------------------------------
-class cmCTestCVS::UpdateParser: public cmCTestVC::LineParser
+class cmCTestCVS::UpdateParser : public cmCTestVC::LineParser
{
public:
- UpdateParser(cmCTestCVS* cvs, const char* prefix): CVS(cvs)
- {
+ UpdateParser(cmCTestCVS* cvs, const char* prefix)
+ : CVS(cvs)
+ {
this->SetLog(&cvs->Log, prefix);
// See "man cvs", section "update output".
this->RegexFileUpdated.compile("^([UP]) *(.*)");
@@ -43,7 +36,8 @@ public:
this->RegexFileRemoved2.compile(
"cvs[^ ]* update: "
"warning: `?([^']*)'? is not \\(any longer\\) pertinent");
- }
+ }
+
private:
cmCTestCVS* CVS;
cmsys::RegularExpression RegexFileUpdated;
@@ -52,266 +46,233 @@ private:
cmsys::RegularExpression RegexFileRemoved1;
cmsys::RegularExpression RegexFileRemoved2;
- virtual bool ProcessLine()
- {
- if(this->RegexFileUpdated.find(this->Line))
- {
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexFileUpdated.find(this->Line)) {
this->DoFile(PathUpdated, this->RegexFileUpdated.match(2));
- }
- else if(this->RegexFileModified.find(this->Line))
- {
+ } else if (this->RegexFileModified.find(this->Line)) {
this->DoFile(PathModified, this->RegexFileModified.match(2));
- }
- else if(this->RegexFileConflicting.find(this->Line))
- {
+ } else if (this->RegexFileConflicting.find(this->Line)) {
this->DoFile(PathConflicting, this->RegexFileConflicting.match(2));
- }
- else if(this->RegexFileRemoved1.find(this->Line))
- {
+ } else if (this->RegexFileRemoved1.find(this->Line)) {
this->DoFile(PathUpdated, this->RegexFileRemoved1.match(1));
- }
- else if(this->RegexFileRemoved2.find(this->Line))
- {
+ } else if (this->RegexFileRemoved2.find(this->Line)) {
this->DoFile(PathUpdated, this->RegexFileRemoved2.match(1));
- }
- return true;
}
+ return true;
+ }
void DoFile(PathStatus status, std::string const& file)
- {
+ {
std::string dir = cmSystemTools::GetFilenamePath(file);
std::string name = cmSystemTools::GetFilenameName(file);
this->CVS->Dirs[dir][name] = status;
- }
+ }
};
-//----------------------------------------------------------------------------
bool cmCTestCVS::UpdateImpl()
{
// Get user-specified update options.
std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
- if(opts.empty())
- {
+ if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("CVSUpdateOptions");
- if(opts.empty())
- {
+ if (opts.empty()) {
opts = "-dP";
- }
}
- std::vector<cmStdString> args = cmSystemTools::ParseArguments(opts.c_str());
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
// Specify the start time for nightly testing.
- if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
- {
+ if (this->CTest->GetTestModel() == cmCTest::NIGHTLY) {
args.push_back("-D" + this->GetNightlyTime() + " UTC");
- }
+ }
// Run "cvs update" to update the work tree.
std::vector<char const*> cvs_update;
cvs_update.push_back(this->CommandLineTool.c_str());
cvs_update.push_back("-z3");
cvs_update.push_back("update");
- for(std::vector<cmStdString>::const_iterator ai = args.begin();
- ai != args.end(); ++ai)
- {
+ for (std::vector<std::string>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai) {
cvs_update.push_back(ai->c_str());
- }
- cvs_update.push_back(0);
+ }
+ cvs_update.push_back(CM_NULLPTR);
UpdateParser out(this, "up-out> ");
UpdateParser err(this, "up-err> ");
return this->RunUpdateCommand(&cvs_update[0], &out, &err);
}
-//----------------------------------------------------------------------------
-class cmCTestCVS::LogParser: public cmCTestVC::LineParser
+class cmCTestCVS::LogParser : public cmCTestVC::LineParser
{
public:
typedef cmCTestCVS::Revision Revision;
- LogParser(cmCTestCVS* cvs, const char* prefix, std::vector<Revision>& revs):
- CVS(cvs), Revisions(revs), Section(SectionHeader)
- {
+ LogParser(cmCTestCVS* cvs, const char* prefix, std::vector<Revision>& revs)
+ : CVS(cvs)
+ , Revisions(revs)
+ , Section(SectionHeader)
+ {
this->SetLog(&cvs->Log, prefix),
- this->RegexRevision.compile("^revision +([^ ]*) *$");
+ this->RegexRevision.compile("^revision +([^ ]*) *$");
this->RegexBranches.compile("^branches: .*$");
this->RegexPerson.compile("^date: +([^;]+); +author: +([^;]+);");
- }
+ }
+
private:
cmCTestCVS* CVS;
std::vector<Revision>& Revisions;
cmsys::RegularExpression RegexRevision;
cmsys::RegularExpression RegexBranches;
cmsys::RegularExpression RegexPerson;
- enum SectionType { SectionHeader, SectionRevisions, SectionEnd };
+ enum SectionType
+ {
+ SectionHeader,
+ SectionRevisions,
+ SectionEnd
+ };
SectionType Section;
Revision Rev;
- virtual bool ProcessLine()
- {
- if(this->Line == ("======================================="
- "======================================"))
- {
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->Line == ("======================================="
+ "======================================")) {
// This line ends the revision list.
- if(this->Section == SectionRevisions)
- {
+ if (this->Section == SectionRevisions) {
this->FinishRevision();
- }
- this->Section = SectionEnd;
}
- else if(this->Line == "----------------------------")
- {
+ this->Section = SectionEnd;
+ } else if (this->Line == "----------------------------") {
// This line divides revisions from the header and each other.
- if(this->Section == SectionHeader)
- {
+ if (this->Section == SectionHeader) {
this->Section = SectionRevisions;
- }
- else if(this->Section == SectionRevisions)
- {
+ } else if (this->Section == SectionRevisions) {
this->FinishRevision();
- }
}
- else if(this->Section == SectionRevisions)
- {
- if(!this->Rev.Log.empty())
- {
+ } else if (this->Section == SectionRevisions) {
+ if (!this->Rev.Log.empty()) {
// Continue the existing log.
this->Rev.Log += this->Line;
this->Rev.Log += "\n";
- }
- else if(this->Rev.Rev.empty() && this->RegexRevision.find(this->Line))
- {
+ } else if (this->Rev.Rev.empty() &&
+ this->RegexRevision.find(this->Line)) {
this->Rev.Rev = this->RegexRevision.match(1);
- }
- else if(this->Rev.Date.empty() && this->RegexPerson.find(this->Line))
- {
+ } else if (this->Rev.Date.empty() &&
+ this->RegexPerson.find(this->Line)) {
this->Rev.Date = this->RegexPerson.match(1);
this->Rev.Author = this->RegexPerson.match(2);
- }
- else if(!this->RegexBranches.find(this->Line))
- {
+ } else if (!this->RegexBranches.find(this->Line)) {
// Start the log.
this->Rev.Log += this->Line;
this->Rev.Log += "\n";
- }
}
- return this->Section != SectionEnd;
}
+ return this->Section != SectionEnd;
+ }
void FinishRevision()
- {
- if(!this->Rev.Rev.empty())
- {
+ {
+ if (!this->Rev.Rev.empty()) {
// Record this revision.
+ /* clang-format off */
this->CVS->Log << "Found revision " << this->Rev.Rev << "\n"
<< " author = " << this->Rev.Author << "\n"
<< " date = " << this->Rev.Date << "\n";
+ /* clang-format on */
this->Revisions.push_back(this->Rev);
// We only need two revisions.
- if(this->Revisions.size() >= 2)
- {
+ if (this->Revisions.size() >= 2) {
this->Section = SectionEnd;
- }
}
- this->Rev = Revision();
}
+ this->Rev = Revision();
+ }
};
-//----------------------------------------------------------------------------
std::string cmCTestCVS::ComputeBranchFlag(std::string const& dir)
{
// Compute the tag file location for this directory.
std::string tagFile = this->SourceDirectory;
- if(!dir.empty())
- {
+ if (!dir.empty()) {
tagFile += "/";
tagFile += dir;
- }
+ }
tagFile += "/CVS/Tag";
// Lookup the branch in the tag file, if any.
std::string tagLine;
- std::ifstream tagStream(tagFile.c_str());
- if(tagStream && cmSystemTools::GetLineFromStream(tagStream, tagLine) &&
- tagLine.size() > 1 && tagLine[0] == 'T')
- {
+ cmsys::ifstream tagStream(tagFile.c_str());
+ if (tagStream && cmSystemTools::GetLineFromStream(tagStream, tagLine) &&
+ tagLine.size() > 1 && tagLine[0] == 'T') {
// Use the branch specified in the tag file.
std::string flag = "-r";
flag += tagLine.substr(1);
return flag;
- }
- else
- {
- // Use the default branch.
- return "-b";
- }
+ }
+ // Use the default branch.
+ return "-b";
}
-//----------------------------------------------------------------------------
-void cmCTestCVS::LoadRevisions(std::string const& file,
- const char* branchFlag,
+void cmCTestCVS::LoadRevisions(std::string const& file, const char* branchFlag,
std::vector<Revision>& revisions)
{
cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
// Run "cvs log" to get revisions of this file on this branch.
const char* cvs = this->CommandLineTool.c_str();
- const char* cvs_log[] =
- {cvs, "log", "-N", branchFlag, file.c_str(), 0};
+ const char* cvs_log[] = { cvs, "log", "-N",
+ branchFlag, file.c_str(), CM_NULLPTR };
LogParser out(this, "log-out> ", revisions);
OutputLogger err(this->Log, "log-err> ");
this->RunChild(cvs_log, &out, &err);
}
-//----------------------------------------------------------------------------
-void cmCTestCVS::WriteXMLDirectory(std::ostream& xml,
- std::string const& path,
+void cmCTestCVS::WriteXMLDirectory(cmXMLWriter& xml, std::string const& path,
Directory const& dir)
{
- const char* slash = path.empty()? "":"/";
- xml << "\t<Directory>\n"
- << "\t\t<Name>" << cmXMLSafe(path) << "</Name>\n";
+ const char* slash = path.empty() ? "" : "/";
+ xml.StartElement("Directory");
+ xml.Element("Name", path);
// Lookup the branch checked out in the working tree.
std::string branchFlag = this->ComputeBranchFlag(path);
// Load revisions and write an entry for each file in this directory.
std::vector<Revision> revisions;
- for(Directory::const_iterator fi = dir.begin(); fi != dir.end(); ++fi)
- {
+ for (Directory::const_iterator fi = dir.begin(); fi != dir.end(); ++fi) {
std::string full = path + slash + fi->first;
// Load two real or unknown revisions.
revisions.clear();
- if(fi->second != PathUpdated)
- {
+ if (fi->second != PathUpdated) {
// For local modifications the current rev is unknown and the
// prior rev is the latest from cvs.
revisions.push_back(this->Unknown);
- }
+ }
this->LoadRevisions(full, branchFlag.c_str(), revisions);
revisions.resize(2, this->Unknown);
// Write the entry for this file with these revisions.
File f(fi->second, &revisions[0], &revisions[1]);
this->WriteXMLEntry(xml, path, fi->first, full, f);
- }
- xml << "\t</Directory>\n";
+ }
+ xml.EndElement(); // Directory
}
-//----------------------------------------------------------------------------
-bool cmCTestCVS::WriteXMLUpdates(std::ostream& xml)
+bool cmCTestCVS::WriteXMLUpdates(cmXMLWriter& xml)
{
cmCTestLog(this->CTest, HANDLER_OUTPUT,
" Gathering version information (one . per updated file):\n"
- " " << std::flush);
+ " "
+ << std::flush);
- for(std::map<cmStdString, Directory>::const_iterator
- di = this->Dirs.begin(); di != this->Dirs.end(); ++di)
- {
+ for (std::map<std::string, Directory>::const_iterator di =
+ this->Dirs.begin();
+ di != this->Dirs.end(); ++di) {
this->WriteXMLDirectory(xml, di->first, di->second);
- }
+ }
cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
diff --git a/Source/CTest/cmCTestCVS.h b/Source/CTest/cmCTestCVS.h
index b7fe567d8..1208cfad6 100644
--- a/Source/CTest/cmCTestCVS.h
+++ b/Source/CTest/cmCTestCVS.h
@@ -1,51 +1,55 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestCVS_h
#define cmCTestCVS_h
+#include "cmConfigure.h"
+
#include "cmCTestVC.h"
+#include <iosfwd>
+#include <map>
+#include <string>
+#include <vector>
+
+class cmCTest;
+class cmXMLWriter;
+
/** \class cmCTestCVS
* \brief Interaction with cvs command-line tool
*
*/
-class cmCTestCVS: public cmCTestVC
+class cmCTestCVS : public cmCTestVC
{
public:
/** Construct with a CTest instance and update log stream. */
cmCTestCVS(cmCTest* ctest, std::ostream& log);
- virtual ~cmCTestCVS();
+ ~cmCTestCVS() CM_OVERRIDE;
private:
// Implement cmCTestVC internal API.
- virtual bool UpdateImpl();
- virtual bool WriteXMLUpdates(std::ostream& xml);
+ bool UpdateImpl() CM_OVERRIDE;
+ bool WriteXMLUpdates(cmXMLWriter& xml) CM_OVERRIDE;
// Update status for files in each directory.
- class Directory: public std::map<cmStdString, PathStatus> {};
- std::map<cmStdString, Directory> Dirs;
+ class Directory : public std::map<std::string, PathStatus>
+ {
+ };
+ std::map<std::string, Directory> Dirs;
std::string ComputeBranchFlag(std::string const& dir);
void LoadRevisions(std::string const& file, const char* branchFlag,
std::vector<Revision>& revisions);
- void WriteXMLDirectory(std::ostream& xml, std::string const& path,
+ void WriteXMLDirectory(cmXMLWriter& xml, std::string const& path,
Directory const& dir);
// Parsing helper classes.
- class UpdateParser;
class LogParser;
- friend class UpdateParser;
+ class UpdateParser;
+
friend class LogParser;
+ friend class UpdateParser;
};
#endif
diff --git a/Source/CTest/cmCTestCommand.h b/Source/CTest/cmCTestCommand.h
index e2ebba8fd..6fc237aac 100644
--- a/Source/CTest/cmCTestCommand.h
+++ b/Source/CTest/cmCTestCommand.h
@@ -1,14 +1,5 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestCommand_h
#define cmCTestCommand_h
@@ -27,14 +18,14 @@ class cmCTestScriptHandler;
class cmCTestCommand : public cmCommand
{
public:
-
- cmCTestCommand() {this->CTest = 0; this->CTestScriptHandler = 0;}
-
- cmCTest *CTest;
- cmCTestScriptHandler *CTestScriptHandler;
-
- cmTypeMacro(cmCTestCommand, cmCommand);
+ cmCTestCommand()
+ {
+ this->CTest = CM_NULLPTR;
+ this->CTestScriptHandler = CM_NULLPTR;
+ }
+
+ cmCTest* CTest;
+ cmCTestScriptHandler* CTestScriptHandler;
};
-
#endif
diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx
index db33cb68e..73e893df3 100644
--- a/Source/CTest/cmCTestConfigureCommand.cxx
+++ b/Source/CTest/cmCTestConfigureCommand.cxx
@@ -1,24 +1,22 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestConfigureCommand.h"
-#include "cmGlobalGenerator.h"
#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <sstream>
+#include <string.h>
+#include <vector>
cmCTestConfigureCommand::cmCTestConfigureCommand()
{
this->Arguments[ctc_OPTIONS] = "OPTIONS";
- this->Arguments[ctc_LAST] = 0;
+ this->Arguments[ctc_LAST] = CM_NULLPTR;
this->Last = ctc_LAST;
}
@@ -26,130 +24,130 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
{
std::vector<std::string> options;
- if (this->Values[ctc_OPTIONS])
- {
+ if (this->Values[ctc_OPTIONS]) {
cmSystemTools::ExpandListArgument(this->Values[ctc_OPTIONS], options);
- }
+ }
- if ( this->CTest->GetCTestConfiguration("BuildDirectory").empty() )
- {
- this->SetError("Build directory not specified. Either use BUILD "
+ if (this->CTest->GetCTestConfiguration("BuildDirectory").empty()) {
+ this->SetError(
+ "Build directory not specified. Either use BUILD "
"argument to CTEST_CONFIGURE command or set CTEST_BINARY_DIRECTORY "
"variable");
- return 0;
- }
+ return CM_NULLPTR;
+ }
- const char* ctestConfigureCommand
- = this->Makefile->GetDefinition("CTEST_CONFIGURE_COMMAND");
+ const char* ctestConfigureCommand =
+ this->Makefile->GetDefinition("CTEST_CONFIGURE_COMMAND");
- if ( ctestConfigureCommand && *ctestConfigureCommand )
- {
+ if (ctestConfigureCommand && *ctestConfigureCommand) {
this->CTest->SetCTestConfiguration("ConfigureCommand",
- ctestConfigureCommand);
- }
- else
- {
- const char* cmakeGeneratorName
- = this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR");
- if ( cmakeGeneratorName && *cmakeGeneratorName )
- {
- const std::string& source_dir
- = this->CTest->GetCTestConfiguration("SourceDirectory");
- if ( source_dir.empty() )
- {
- this->SetError("Source directory not specified. Either use SOURCE "
+ ctestConfigureCommand, this->Quiet);
+ } else {
+ const char* cmakeGeneratorName =
+ this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR");
+ if (cmakeGeneratorName && *cmakeGeneratorName) {
+ const std::string& source_dir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
+ if (source_dir.empty()) {
+ this->SetError(
+ "Source directory not specified. Either use SOURCE "
"argument to CTEST_CONFIGURE command or set CTEST_SOURCE_DIRECTORY "
"variable");
- return 0;
- }
+ return CM_NULLPTR;
+ }
const std::string cmakelists_file = source_dir + "/CMakeLists.txt";
- if ( !cmSystemTools::FileExists(cmakelists_file.c_str()) )
- {
- cmOStringStream e;
- e << "CMakeLists.txt file does not exist ["
- << cmakelists_file << "]";
- this->SetError(e.str().c_str());
- return 0;
- }
+ if (!cmSystemTools::FileExists(cmakelists_file.c_str())) {
+ std::ostringstream e;
+ e << "CMakeLists.txt file does not exist [" << cmakelists_file << "]";
+ this->SetError(e.str());
+ return CM_NULLPTR;
+ }
bool multiConfig = false;
bool cmakeBuildTypeInOptions = false;
- cmGlobalGenerator *gg =
+ cmGlobalGenerator* gg =
this->Makefile->GetCMakeInstance()->CreateGlobalGenerator(
cmakeGeneratorName);
- if(gg)
- {
+ if (gg) {
multiConfig = gg->IsMultiConfig();
delete gg;
- }
+ }
std::string cmakeConfigureCommand = "\"";
- cmakeConfigureCommand += this->CTest->GetCMakeExecutable();
+ cmakeConfigureCommand += cmSystemTools::GetCMakeCommand();
cmakeConfigureCommand += "\"";
std::vector<std::string>::const_iterator it;
std::string option;
- for (it= options.begin(); it!=options.end(); ++it)
- {
+ for (it = options.begin(); it != options.end(); ++it) {
option = *it;
cmakeConfigureCommand += " \"";
cmakeConfigureCommand += option;
cmakeConfigureCommand += "\"";
- if ((0 != strstr(option.c_str(), "CMAKE_BUILD_TYPE=")) ||
- (0 != strstr(option.c_str(), "CMAKE_BUILD_TYPE:STRING=")))
- {
+ if ((CM_NULLPTR != strstr(option.c_str(), "CMAKE_BUILD_TYPE=")) ||
+ (CM_NULLPTR !=
+ strstr(option.c_str(), "CMAKE_BUILD_TYPE:STRING="))) {
cmakeBuildTypeInOptions = true;
- }
}
+ }
if (!multiConfig && !cmakeBuildTypeInOptions &&
- !this->CTest->GetConfigType().empty())
- {
+ !this->CTest->GetConfigType().empty()) {
cmakeConfigureCommand += " \"-DCMAKE_BUILD_TYPE:STRING=";
cmakeConfigureCommand += this->CTest->GetConfigType();
cmakeConfigureCommand += "\"";
- }
+ }
+
+ if (this->Makefile->IsOn("CTEST_USE_LAUNCHERS")) {
+ cmakeConfigureCommand += " \"-DCTEST_USE_LAUNCHERS:BOOL=TRUE\"";
+ }
cmakeConfigureCommand += " \"-G";
cmakeConfigureCommand += cmakeGeneratorName;
cmakeConfigureCommand += "\"";
+ const char* cmakeGeneratorPlatform =
+ this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR_PLATFORM");
+ if (cmakeGeneratorPlatform && *cmakeGeneratorPlatform) {
+ cmakeConfigureCommand += " \"-A";
+ cmakeConfigureCommand += cmakeGeneratorPlatform;
+ cmakeConfigureCommand += "\"";
+ }
+
const char* cmakeGeneratorToolset =
this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR_TOOLSET");
- if(cmakeGeneratorToolset && *cmakeGeneratorToolset)
- {
+ if (cmakeGeneratorToolset && *cmakeGeneratorToolset) {
cmakeConfigureCommand += " \"-T";
cmakeConfigureCommand += cmakeGeneratorToolset;
cmakeConfigureCommand += "\"";
- }
+ }
cmakeConfigureCommand += " \"";
cmakeConfigureCommand += source_dir;
cmakeConfigureCommand += "\"";
- this->CTest->SetCTestConfiguration("ConfigureCommand",
- cmakeConfigureCommand.c_str());
- }
- else
- {
- this->SetError("Configure command is not specified. If this is a "
+ this->CTest->SetCTestConfiguration(
+ "ConfigureCommand", cmakeConfigureCommand.c_str(), this->Quiet);
+ } else {
+ this->SetError(
+ "Configure command is not specified. If this is a "
"\"built with CMake\" project, set CTEST_CMAKE_GENERATOR. If not, "
"set CTEST_CONFIGURE_COMMAND.");
- return 0;
- }
+ return CM_NULLPTR;
}
+ }
- cmCTestGenericHandler* handler
- = this->CTest->GetInitializedHandler("configure");
- if ( !handler )
- {
+ cmCTestGenericHandler* handler =
+ this->CTest->GetInitializedHandler("configure");
+ if (!handler) {
this->SetError(
"internal CTest error. Cannot instantiate configure handler");
- return 0;
- }
+ return CM_NULLPTR;
+ }
+ handler->SetQuiet(this->Quiet);
return handler;
}
diff --git a/Source/CTest/cmCTestConfigureCommand.h b/Source/CTest/cmCTestConfigureCommand.h
index b343fc1e9..917f5ab8b 100644
--- a/Source/CTest/cmCTestConfigureCommand.h
+++ b/Source/CTest/cmCTestConfigureCommand.h
@@ -1,19 +1,17 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestConfigureCommand_h
#define cmCTestConfigureCommand_h
+#include "cmConfigure.h"
+
#include "cmCTestHandlerCommand.h"
+#include <string>
+
+class cmCTestGenericHandler;
+class cmCommand;
+
/** \class cmCTestConfigure
* \brief Run a ctest script
*
@@ -27,58 +25,28 @@ public:
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestConfigureCommand* ni = new cmCTestConfigureCommand;
ni->CTest = this->CTest;
ni->CTestScriptHandler = this->CTestScriptHandler;
return ni;
- }
+ }
/**
* The name of the command as specified in CMakeList.txt.
*/
- 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);
+ std::string GetName() const CM_OVERRIDE { return "ctest_configure"; }
protected:
- cmCTestGenericHandler* InitializeHandler();
+ cmCTestGenericHandler* InitializeHandler() CM_OVERRIDE;
- enum {
+ enum
+ {
ctc_FIRST = ct_LAST,
ctc_OPTIONS,
ctc_LAST
};
};
-
#endif
diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx
index 7c4129864..5d87f3fb4 100644
--- a/Source/CTest/cmCTestConfigureHandler.cxx
+++ b/Source/CTest/cmCTestConfigureHandler.cxx
@@ -1,132 +1,104 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestConfigureHandler.h"
#include "cmCTest.h"
#include "cmGeneratedFileStream.h"
-#include "cmake.h"
-#include "cmXMLSafe.h"
-#include <cmsys/Process.h>
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+#include <ostream>
+#include <string>
-//----------------------------------------------------------------------
cmCTestConfigureHandler::cmCTestConfigureHandler()
{
}
-//----------------------------------------------------------------------
void cmCTestConfigureHandler::Initialize()
{
this->Superclass::Initialize();
}
-//----------------------------------------------------------------------
-//clearly it would be nice if this were broken up into a few smaller
-//functions and commented...
+// clearly it would be nice if this were broken up into a few smaller
+// functions and commented...
int cmCTestConfigureHandler::ProcessHandler()
{
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "Configure project" << std::endl);
- std::string cCommand
- = this->CTest->GetCTestConfiguration("ConfigureCommand");
- if ( cCommand.size() == 0 )
- {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "Configure project" << std::endl, this->Quiet);
+ std::string cCommand =
+ this->CTest->GetCTestConfiguration("ConfigureCommand");
+ if (cCommand.empty()) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot find ConfigureCommand key in the DartConfiguration.tcl"
- << std::endl);
+ "Cannot find ConfigureCommand key in the DartConfiguration.tcl"
+ << std::endl);
return -1;
- }
+ }
- std::string buildDirectory
- = this->CTest->GetCTestConfiguration("BuildDirectory");
- if ( buildDirectory.size() == 0 )
- {
+ std::string buildDirectory =
+ this->CTest->GetCTestConfiguration("BuildDirectory");
+ if (buildDirectory.empty()) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot find BuildDirectory key in the DartConfiguration.tcl"
- << std::endl);
+ "Cannot find BuildDirectory key in the DartConfiguration.tcl"
+ << std::endl);
return -1;
- }
+ }
double elapsed_time_start = cmSystemTools::GetTime();
std::string output;
int retVal = 0;
int res = 0;
- if ( !this->CTest->GetShowOnly() )
- {
+ if (!this->CTest->GetShowOnly()) {
cmGeneratedFileStream os;
- if(!this->StartResultingXML(cmCTest::PartConfigure, "Configure", os))
- {
+ if (!this->StartResultingXML(cmCTest::PartConfigure, "Configure", os)) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open configure file"
- << std::endl);
+ << std::endl);
return 1;
- }
+ }
std::string start_time = this->CTest->CurrentTime();
- unsigned int start_time_time = static_cast<unsigned int>(
- cmSystemTools::GetTime());
+ unsigned int start_time_time =
+ static_cast<unsigned int>(cmSystemTools::GetTime());
cmGeneratedFileStream ofs;
this->StartLogFile("Configure", ofs);
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Configure with command: "
- << cCommand.c_str() << std::endl);
- res = this->CTest->RunMakeCommand(cCommand.c_str(), &output,
- &retVal, buildDirectory.c_str(),
- 0, ofs);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Configure with command: " << cCommand << std::endl,
+ this->Quiet);
+ res = this->CTest->RunMakeCommand(cCommand.c_str(), output, &retVal,
+ buildDirectory.c_str(), 0, ofs);
- if ( ofs )
- {
+ if (ofs) {
ofs.close();
- }
-
- if ( os )
- {
- this->CTest->StartXML(os, this->AppendXML);
- os << "<Configure>\n"
- << "\t<StartDateTime>" << start_time << "</StartDateTime>"
- << std::endl
- << "\t<StartConfigureTime>" << start_time_time
- << "</StartConfigureTime>\n";
-
- if ( res == cmsysProcess_State_Exited && retVal )
- {
- os << retVal;
- }
- os << "<ConfigureCommand>" << cCommand.c_str() << "</ConfigureCommand>"
- << std::endl;
- cmCTestLog(this->CTest, DEBUG, "End" << std::endl);
- os << "<Log>" << cmXMLSafe(output) << "</Log>" << std::endl;
- std::string end_time = this->CTest->CurrentTime();
- os << "\t<ConfigureStatus>" << retVal << "</ConfigureStatus>\n"
- << "\t<EndDateTime>" << end_time << "</EndDateTime>\n"
- << "\t<EndConfigureTime>" <<
- static_cast<unsigned int>(cmSystemTools::GetTime())
- << "</EndConfigureTime>\n"
- << "<ElapsedMinutes>"
- << static_cast<int>(
- (cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0
- << "</ElapsedMinutes>"
- << "</Configure>" << std::endl;
- this->CTest->EndXML(os);
- }
}
- else
- {
- cmCTestLog(this->CTest, DEBUG, "Configure with command: " << cCommand
- << std::endl);
+
+ if (os) {
+ cmXMLWriter xml(os);
+ this->CTest->StartXML(xml, this->AppendXML);
+ xml.StartElement("Configure");
+ xml.Element("StartDateTime", start_time);
+ xml.Element("StartConfigureTime", start_time_time);
+ xml.Element("ConfigureCommand", cCommand);
+ cmCTestOptionalLog(this->CTest, DEBUG, "End" << std::endl, this->Quiet);
+ xml.Element("Log", output);
+ xml.Element("ConfigureStatus", retVal);
+ xml.Element("EndDateTime", this->CTest->CurrentTime());
+ xml.Element("EndConfigureTime",
+ static_cast<unsigned int>(cmSystemTools::GetTime()));
+ xml.Element(
+ "ElapsedMinutes",
+ static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start) / 6) /
+ 10.0);
+ xml.EndElement(); // Configure
+ this->CTest->EndXML(xml);
}
- if (! res || retVal )
- {
+ } else {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Configure with command: " << cCommand << std::endl,
+ this->Quiet);
+ }
+ if (!res || retVal) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error(s) when configuring the project" << std::endl);
+ "Error(s) when configuring the project" << std::endl);
return -1;
- }
+ }
return 0;
}
diff --git a/Source/CTest/cmCTestConfigureHandler.h b/Source/CTest/cmCTestConfigureHandler.h
index d880bd7df..2b452829c 100644
--- a/Source/CTest/cmCTestConfigureHandler.h
+++ b/Source/CTest/cmCTestConfigureHandler.h
@@ -1,21 +1,11 @@
-/*============================================================================
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestConfigureHandler_h
#define cmCTestConfigureHandler_h
+#include "cmConfigure.h"
#include "cmCTestGenericHandler.h"
-#include "cmListFileCache.h"
/** \class cmCTestConfigureHandler
* \brief A class that handles ctest -S invocations
@@ -24,16 +14,16 @@
class cmCTestConfigureHandler : public cmCTestGenericHandler
{
public:
- cmTypeMacro(cmCTestConfigureHandler, cmCTestGenericHandler);
+ typedef cmCTestGenericHandler Superclass;
/*
* The main entry point for this class
*/
- int ProcessHandler();
+ int ProcessHandler() CM_OVERRIDE;
cmCTestConfigureHandler();
- void Initialize();
+ void Initialize() CM_OVERRIDE;
};
#endif
diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx
index 72ff720d3..535da586d 100644
--- a/Source/CTest/cmCTestCoverageCommand.cxx
+++ b/Source/CTest/cmCTestCoverageCommand.cxx
@@ -1,72 +1,60 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestCoverageCommand.h"
#include "cmCTest.h"
#include "cmCTestCoverageHandler.h"
-//----------------------------------------------------------------------------
+class cmCTestGenericHandler;
+
cmCTestCoverageCommand::cmCTestCoverageCommand()
{
this->LabelsMentioned = false;
}
-//----------------------------------------------------------------------------
cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler()
{
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "CoverageCommand", "CTEST_COVERAGE_COMMAND");
-
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "CoverageCommand", "CTEST_COVERAGE_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "CoverageExtraFlags", "CTEST_COVERAGE_EXTRA_FLAGS",
+ this->Quiet);
cmCTestCoverageHandler* handler = static_cast<cmCTestCoverageHandler*>(
this->CTest->GetInitializedHandler("coverage"));
- if ( !handler )
- {
+ if (!handler) {
this->SetError("internal CTest error. Cannot instantiate test handler");
- return 0;
- }
+ return CM_NULLPTR;
+ }
// If a LABELS option was given, select only files with the labels.
- if(this->LabelsMentioned)
- {
+ if (this->LabelsMentioned) {
handler->SetLabelFilter(this->Labels);
- }
+ }
+ handler->SetQuiet(this->Quiet);
return handler;
}
-//----------------------------------------------------------------------------
bool cmCTestCoverageCommand::CheckArgumentKeyword(std::string const& arg)
{
// Look for arguments specific to this command.
- if(arg == "LABELS")
- {
+ if (arg == "LABELS") {
this->ArgumentDoing = ArgumentDoingLabels;
this->LabelsMentioned = true;
return true;
- }
+ }
// Look for other arguments.
return this->Superclass::CheckArgumentKeyword(arg);
}
-//----------------------------------------------------------------------------
bool cmCTestCoverageCommand::CheckArgumentValue(std::string const& arg)
{
// Handle states specific to this command.
- if(this->ArgumentDoing == ArgumentDoingLabels)
- {
+ if (this->ArgumentDoing == ArgumentDoingLabels) {
this->Labels.insert(arg);
return true;
- }
+ }
// Look for other arguments.
return this->Superclass::CheckArgumentValue(arg);
diff --git a/Source/CTest/cmCTestCoverageCommand.h b/Source/CTest/cmCTestCoverageCommand.h
index 2fe762c45..78c4f61f6 100644
--- a/Source/CTest/cmCTestCoverageCommand.h
+++ b/Source/CTest/cmCTestCoverageCommand.h
@@ -1,19 +1,18 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestCoverageCommand_h
#define cmCTestCoverageCommand_h
+#include "cmConfigure.h"
+
#include "cmCTestHandlerCommand.h"
+#include <set>
+#include <string>
+
+class cmCTestGenericHandler;
+class cmCommand;
+
/** \class cmCTestCoverage
* \brief Run a ctest script
*
@@ -22,58 +21,31 @@
class cmCTestCoverageCommand : public cmCTestHandlerCommand
{
public:
-
cmCTestCoverageCommand();
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestCoverageCommand* ni = new cmCTestCoverageCommand;
ni->CTest = this->CTest;
ni->CTestScriptHandler = this->CTestScriptHandler;
return ni;
- }
+ }
/**
* The name of the command as specified in CMakeList.txt.
*/
- virtual const char* GetName() const { return "ctest_coverage";}
+ std::string GetName() const CM_OVERRIDE { 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);
+ typedef cmCTestHandlerCommand Superclass;
protected:
- cmCTestGenericHandler* InitializeHandler();
+ cmCTestGenericHandler* InitializeHandler() CM_OVERRIDE;
- virtual bool CheckArgumentKeyword(std::string const& arg);
- virtual bool CheckArgumentValue(std::string const& arg);
+ bool CheckArgumentKeyword(std::string const& arg) CM_OVERRIDE;
+ bool CheckArgumentValue(std::string const& arg) CM_OVERRIDE;
enum
{
@@ -82,9 +54,7 @@ protected:
};
bool LabelsMentioned;
- std::set<cmStdString> Labels;
+ std::set<std::string> Labels;
};
-
#endif
-
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index 20aded2b5..28fae1c7e 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -1,124 +1,109 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestCoverageHandler.h"
-#include "cmParsePHPCoverage.h"
-#include "cmParseGTMCoverage.h"
-#include "cmParseCacheCoverage.h"
+
#include "cmCTest.h"
-#include "cmake.h"
-#include "cmMakefile.h"
-#include "cmSystemTools.h"
#include "cmGeneratedFileStream.h"
-#include "cmXMLSafe.h"
-
-#include <cmsys/Process.h>
-#include <cmsys/RegularExpression.hxx>
-#include <cmsys/Glob.hxx>
-#include <cmsys/stl/iterator>
-#include <cmsys/stl/algorithm>
+#include "cmParseBlanketJSCoverage.h"
+#include "cmParseCacheCoverage.h"
+#include "cmParseCoberturaCoverage.h"
+#include "cmParseDelphiCoverage.h"
+#include "cmParseGTMCoverage.h"
+#include "cmParseJacocoCoverage.h"
+#include "cmParsePHPCoverage.h"
+#include "cmSystemTools.h"
+#include "cmWorkingDirectory.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+#include "cmsys/Process.h"
+#include "cmsys/RegularExpression.hxx"
+#include <algorithm>
+#include <iomanip>
+#include <iterator>
+#include <sstream>
+#include <stdio.h>
#include <stdlib.h>
-#include <math.h>
-#include <float.h>
+#include <utility>
-#define SAFEDIV(x,y) (((y)!=0)?((x)/(y)):(0))
+class cmMakefile;
+
+#define SAFEDIV(x, y) (((y) != 0) ? ((x) / (y)) : (0))
class cmCTestRunProcess
{
public:
cmCTestRunProcess()
- {
- this->Process = cmsysProcess_New();
- this->PipeState = -1;
- this->TimeOut = -1;
- }
+ {
+ this->Process = cmsysProcess_New();
+ this->PipeState = -1;
+ this->TimeOut = -1;
+ }
~cmCTestRunProcess()
- {
- if(!(this->PipeState == -1)
- && !(this->PipeState == cmsysProcess_Pipe_None )
- && !(this->PipeState == cmsysProcess_Pipe_Timeout))
- {
- this->WaitForExit();
- }
- cmsysProcess_Delete(this->Process);
- }
+ {
+ if (!(this->PipeState == -1) &&
+ !(this->PipeState == cmsysProcess_Pipe_None) &&
+ !(this->PipeState == cmsysProcess_Pipe_Timeout)) {
+ this->WaitForExit();
+ }
+ cmsysProcess_Delete(this->Process);
+ }
void SetCommand(const char* command)
- {
- this->CommandLineStrings.clear();
- this->CommandLineStrings.push_back(command);;
- }
+ {
+ this->CommandLineStrings.clear();
+ this->CommandLineStrings.push_back(command);
+ ;
+ }
void AddArgument(const char* arg)
- {
- if(arg)
- {
- this->CommandLineStrings.push_back(arg);
- }
- }
- void SetWorkingDirectory(const char* dir)
- {
- this->WorkingDirectory = dir;
- }
- void SetTimeout(double t)
- {
- this->TimeOut = t;
+ {
+ if (arg) {
+ this->CommandLineStrings.push_back(arg);
}
+ }
+ void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; }
+ void SetTimeout(double t) { this->TimeOut = t; }
bool StartProcess()
- {
- std::vector<const char*> args;
- for(std::vector<std::string>::iterator i =
- this->CommandLineStrings.begin();
- i != this->CommandLineStrings.end(); ++i)
- {
- args.push_back(i->c_str());
- }
- args.push_back(0); // null terminate
- cmsysProcess_SetCommand(this->Process, &*args.begin());
- if(this->WorkingDirectory.size())
- {
- cmsysProcess_SetWorkingDirectory(this->Process,
- this->WorkingDirectory.c_str());
- }
-
- cmsysProcess_SetOption(this->Process,
- cmsysProcess_Option_HideWindow, 1);
- if(this->TimeOut != -1)
- {
- cmsysProcess_SetTimeout(this->Process, this->TimeOut);
- }
- cmsysProcess_Execute(this->Process);
- this->PipeState = cmsysProcess_GetState(this->Process);
- // if the process is running or exited return true
- if(this->PipeState == cmsysProcess_State_Executing
- || this->PipeState == cmsysProcess_State_Exited)
- {
- return true;
- }
- return false;
- }
+ {
+ std::vector<const char*> args;
+ for (std::vector<std::string>::iterator i =
+ this->CommandLineStrings.begin();
+ i != this->CommandLineStrings.end(); ++i) {
+ args.push_back(i->c_str());
+ }
+ args.push_back(CM_NULLPTR); // null terminate
+ cmsysProcess_SetCommand(this->Process, &*args.begin());
+ if (!this->WorkingDirectory.empty()) {
+ cmsysProcess_SetWorkingDirectory(this->Process,
+ this->WorkingDirectory.c_str());
+ }
+
+ cmsysProcess_SetOption(this->Process, cmsysProcess_Option_HideWindow, 1);
+ if (this->TimeOut != -1) {
+ cmsysProcess_SetTimeout(this->Process, this->TimeOut);
+ }
+ cmsysProcess_Execute(this->Process);
+ this->PipeState = cmsysProcess_GetState(this->Process);
+ // if the process is running or exited return true
+ return this->PipeState == cmsysProcess_State_Executing ||
+ this->PipeState == cmsysProcess_State_Exited;
+ }
void SetStdoutFile(const char* fname)
- {
+ {
cmsysProcess_SetPipeFile(this->Process, cmsysProcess_Pipe_STDOUT, fname);
- }
+ }
void SetStderrFile(const char* fname)
- {
+ {
cmsysProcess_SetPipeFile(this->Process, cmsysProcess_Pipe_STDERR, fname);
- }
- int WaitForExit(double* timeout =0)
- {
- this->PipeState = cmsysProcess_WaitForExit(this->Process,
- timeout);
- return this->PipeState;
- }
- int GetProcessState() { return this->PipeState;}
+ }
+ int WaitForExit(double* timeout = CM_NULLPTR)
+ {
+ this->PipeState = cmsysProcess_WaitForExit(this->Process, timeout);
+ return this->PipeState;
+ }
+ int GetProcessState() { return this->PipeState; }
+
private:
int PipeState;
cmsysProcess* Process;
@@ -127,26 +112,21 @@ private:
double TimeOut;
};
-
-//----------------------------------------------------------------------
-
-//----------------------------------------------------------------------
cmCTestCoverageHandler::cmCTestCoverageHandler()
{
}
-//----------------------------------------------------------------------
void cmCTestCoverageHandler::Initialize()
{
this->Superclass::Initialize();
this->CustomCoverageExclude.clear();
this->SourceLabels.clear();
+ this->TargetDirs.clear();
this->LabelIdMap.clear();
this->Labels.clear();
this->LabelFilter.clear();
}
-//----------------------------------------------------------------------------
void cmCTestCoverageHandler::CleanCoverageLogFiles(std::ostream& log)
{
std::string logGlob = this->CTest->GetCTestConfiguration("BuildDirectory");
@@ -154,195 +134,172 @@ void cmCTestCoverageHandler::CleanCoverageLogFiles(std::ostream& log)
logGlob += this->CTest->GetCurrentTag();
logGlob += "/CoverageLog*";
cmsys::Glob gl;
- gl.FindFiles(logGlob.c_str());
+ gl.FindFiles(logGlob);
std::vector<std::string> const& files = gl.GetFiles();
- for(std::vector<std::string>::const_iterator fi = files.begin();
- fi != files.end(); ++fi)
- {
+ for (std::vector<std::string>::const_iterator fi = files.begin();
+ fi != files.end(); ++fi) {
log << "Removing old coverage log: " << *fi << "\n";
- cmSystemTools::RemoveFile(fi->c_str());
- }
+ cmSystemTools::RemoveFile(*fi);
+ }
}
-//----------------------------------------------------------------------
bool cmCTestCoverageHandler::StartCoverageLogFile(
cmGeneratedFileStream& covLogFile, int logFileCount)
{
char covLogFilename[1024];
sprintf(covLogFilename, "CoverageLog-%d", logFileCount);
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Open file: "
- << covLogFilename << std::endl);
- if(!this->StartResultingXML(cmCTest::PartCoverage,
- covLogFilename, covLogFile))
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open log file: "
- << covLogFilename << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Open file: " << covLogFilename << std::endl,
+ this->Quiet);
+ if (!this->StartResultingXML(cmCTest::PartCoverage, covLogFilename,
+ covLogFile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open log file: " << covLogFilename << std::endl);
return false;
- }
- std::string local_start_time = this->CTest->CurrentTime();
- this->CTest->StartXML(covLogFile, this->AppendXML);
- covLogFile << "<CoverageLog>" << std::endl
- << "\t<StartDateTime>" << local_start_time << "</StartDateTime>"
- << "\t<StartTime>"
- << static_cast<unsigned int>(cmSystemTools::GetTime())
- << "</StartTime>"
- << std::endl;
+ }
return true;
}
-//----------------------------------------------------------------------
void cmCTestCoverageHandler::EndCoverageLogFile(cmGeneratedFileStream& ostr,
- int logFileCount)
+ int logFileCount)
{
- std::string local_end_time = this->CTest->CurrentTime();
- ostr << "\t<EndDateTime>" << local_end_time << "</EndDateTime>" << std::endl
- << "\t<EndTime>" <<
- static_cast<unsigned int>(cmSystemTools::GetTime())
- << "</EndTime>" << std::endl
- << "</CoverageLog>" << std::endl;
- this->CTest->EndXML(ostr);
char covLogFilename[1024];
sprintf(covLogFilename, "CoverageLog-%d.xml", logFileCount);
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Close file: "
- << covLogFilename << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Close file: " << covLogFilename << std::endl,
+ this->Quiet);
ostr.Close();
}
-//----------------------------------------------------------------------
+void cmCTestCoverageHandler::StartCoverageLogXML(cmXMLWriter& xml)
+{
+ this->CTest->StartXML(xml, this->AppendXML);
+ xml.StartElement("CoverageLog");
+ xml.Element("StartDateTime", this->CTest->CurrentTime());
+ xml.Element("StartTime",
+ static_cast<unsigned int>(cmSystemTools::GetTime()));
+}
+
+void cmCTestCoverageHandler::EndCoverageLogXML(cmXMLWriter& xml)
+{
+ xml.Element("EndDateTime", this->CTest->CurrentTime());
+ xml.Element("EndTime", static_cast<unsigned int>(cmSystemTools::GetTime()));
+ xml.EndElement(); // CoverageLog
+ this->CTest->EndXML(xml);
+}
+
bool cmCTestCoverageHandler::ShouldIDoCoverage(const char* file,
- const char* srcDir,
- const char* binDir)
+ const char* srcDir,
+ const char* binDir)
{
- if(this->IsFilteredOut(file))
- {
+ if (this->IsFilteredOut(file)) {
return false;
- }
+ }
std::vector<cmsys::RegularExpression>::iterator sit;
- for ( sit = this->CustomCoverageExcludeRegex.begin();
- sit != this->CustomCoverageExcludeRegex.end(); ++ sit )
- {
- if ( sit->find(file) )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " File " << file
- << " is excluded in CTestCustom.ctest" << std::endl;);
+ for (sit = this->CustomCoverageExcludeRegex.begin();
+ sit != this->CustomCoverageExcludeRegex.end(); ++sit) {
+ if (sit->find(file)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " File "
+ << file << " is excluded in CTestCustom.ctest"
+ << std::endl;
+ , this->Quiet);
return false;
- }
}
+ }
std::string fSrcDir = cmSystemTools::CollapseFullPath(srcDir);
std::string fBinDir = cmSystemTools::CollapseFullPath(binDir);
std::string fFile = cmSystemTools::CollapseFullPath(file);
- bool sourceSubDir = cmSystemTools::IsSubDirectory(fFile.c_str(),
- fSrcDir.c_str());
- bool buildSubDir = cmSystemTools::IsSubDirectory(fFile.c_str(),
- fBinDir.c_str());
+ bool sourceSubDir = cmSystemTools::IsSubDirectory(fFile, fSrcDir);
+ bool buildSubDir = cmSystemTools::IsSubDirectory(fFile, fBinDir);
// Always check parent directory of the file.
- std::string fileDir = cmSystemTools::GetFilenamePath(fFile.c_str());
+ std::string fileDir = cmSystemTools::GetFilenamePath(fFile);
std::string checkDir;
// We also need to check the binary/source directory pair.
- if ( sourceSubDir && buildSubDir )
- {
- if ( fSrcDir.size() > fBinDir.size() )
- {
+ if (sourceSubDir && buildSubDir) {
+ if (fSrcDir.size() > fBinDir.size()) {
checkDir = fSrcDir;
- }
- else
- {
+ } else {
checkDir = fBinDir;
- }
}
- else if ( sourceSubDir )
- {
+ } else if (sourceSubDir) {
checkDir = fSrcDir;
- }
- else if ( buildSubDir )
- {
+ } else if (buildSubDir) {
checkDir = fBinDir;
- }
- std::string ndc
- = cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage",
- fFile.c_str(), checkDir.c_str());
- if ( ndc.size() )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Found: " << ndc.c_str()
- << " so skip coverage of " << file << std::endl);
+ }
+ std::string ndc = cmSystemTools::FileExistsInParentDirectories(
+ ".NoDartCoverage", fFile.c_str(), checkDir.c_str());
+ if (!ndc.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found: " << ndc << " so skip coverage of " << file
+ << std::endl,
+ this->Quiet);
return false;
- }
+ }
// By now checkDir should be set to parent directory of the file.
// Get the relative path to the file an apply it to the opposite directory.
// If it is the same as fileDir, then ignore, otherwise check.
std::string relPath;
- if(checkDir.size() )
- {
- relPath = cmSystemTools::RelativePath(checkDir.c_str(),
- fFile.c_str());
- }
- else
- {
+ if (!checkDir.empty()) {
+ relPath = cmSystemTools::RelativePath(checkDir.c_str(), fFile.c_str());
+ } else {
relPath = fFile;
- }
- if ( checkDir == fSrcDir )
- {
+ }
+ if (checkDir == fSrcDir) {
checkDir = fBinDir;
- }
- else
- {
+ } else {
checkDir = fSrcDir;
- }
+ }
fFile = checkDir + "/" + relPath;
- fFile = cmSystemTools::GetFilenamePath(fFile.c_str());
+ fFile = cmSystemTools::GetFilenamePath(fFile);
- if ( fileDir == fFile )
- {
+ if (fileDir == fFile) {
// This is in-source build, so we trust the previous check.
return true;
- }
-
- ndc = cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage",
- fFile.c_str(), checkDir.c_str());
- if ( ndc.size() )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Found: " << ndc.c_str()
- << " so skip coverage of: " << file << std::endl);
+ }
+
+ ndc = cmSystemTools::FileExistsInParentDirectories(
+ ".NoDartCoverage", fFile.c_str(), checkDir.c_str());
+ if (!ndc.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found: " << ndc << " so skip coverage of: " << file
+ << std::endl,
+ this->Quiet);
return false;
- }
+ }
// Ok, nothing in source tree, nothing in binary tree
return true;
}
-//----------------------------------------------------------------------
-//clearly it would be nice if this were broken up into a few smaller
-//functions and commented...
+// clearly it would be nice if this were broken up into a few smaller
+// functions and commented...
int cmCTestCoverageHandler::ProcessHandler()
{
this->CTest->ClearSubmitFiles(cmCTest::PartCoverage);
int error = 0;
// do we have time for this
- if (this->CTest->GetRemainingTimeAllowed() < 120)
- {
+ if (this->CTest->GetRemainingTimeAllowed() < 120) {
return error;
- }
+ }
std::string coverage_start_time = this->CTest->CurrentTime();
- unsigned int coverage_start_time_time = static_cast<unsigned int>(
- cmSystemTools::GetTime());
- std::string sourceDir
- = this->CTest->GetCTestConfiguration("SourceDirectory");
- std::string binaryDir
- = this->CTest->GetCTestConfiguration("BuildDirectory");
+ unsigned int coverage_start_time_time =
+ static_cast<unsigned int>(cmSystemTools::GetTime());
+ std::string sourceDir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
+ std::string binaryDir = this->CTest->GetCTestConfiguration("BuildDirectory");
this->LoadLabels();
cmGeneratedFileStream ofs;
double elapsed_time_start = cmSystemTools::GetTime();
- if ( !this->StartLogFile("Coverage", ofs) )
- {
+ if (!this->StartLogFile("Coverage", ofs)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot create LastCoverage.log file" << std::endl);
- }
+ "Cannot create LastCoverage.log file" << std::endl);
+ }
ofs << "Performing coverage: " << elapsed_time_start << std::endl;
this->CleanCoverageLogFiles(ofs);
@@ -350,376 +307,384 @@ int cmCTestCoverageHandler::ProcessHandler()
cmSystemTools::ConvertToUnixSlashes(sourceDir);
cmSystemTools::ConvertToUnixSlashes(binaryDir);
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "Performing coverage" << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "Performing coverage" << std::endl, this->Quiet);
cmCTestCoverageHandlerContainer cont;
cont.Error = error;
cont.SourceDir = sourceDir;
cont.BinaryDir = binaryDir;
cont.OFS = &ofs;
+ cont.Quiet = this->Quiet;
// setup the regex exclude stuff
this->CustomCoverageExcludeRegex.clear();
- std::vector<cmStdString>::iterator rexIt;
- for ( rexIt = this->CustomCoverageExclude.begin();
- rexIt != this->CustomCoverageExclude.end();
- ++ rexIt )
- {
+ std::vector<std::string>::iterator rexIt;
+ for (rexIt = this->CustomCoverageExclude.begin();
+ rexIt != this->CustomCoverageExclude.end(); ++rexIt) {
this->CustomCoverageExcludeRegex.push_back(
cmsys::RegularExpression(rexIt->c_str()));
- }
+ }
- if(this->HandleBullseyeCoverage(&cont))
- {
+ if (this->HandleBullseyeCoverage(&cont)) {
return cont.Error;
- }
+ }
int file_count = 0;
file_count += this->HandleGCovCoverage(&cont);
error = cont.Error;
- if ( file_count < 0 )
- {
+ if (file_count < 0) {
return error;
- }
+ }
+ file_count += this->HandleLCovCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
file_count += this->HandleTracePyCoverage(&cont);
error = cont.Error;
- if ( file_count < 0 )
- {
+ if (file_count < 0) {
return error;
- }
+ }
file_count += this->HandlePHPCoverage(&cont);
error = cont.Error;
- if ( file_count < 0 )
- {
+ if (file_count < 0) {
return error;
- }
+ }
+ file_count += this->HandleCoberturaCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+
file_count += this->HandleMumpsCoverage(&cont);
error = cont.Error;
- if ( file_count < 0 )
- {
+ if (file_count < 0) {
return error;
- }
+ }
+ file_count += this->HandleJacocoCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+
+ file_count += this->HandleBlanketJSCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
+
+ file_count += this->HandleDelphiCoverage(&cont);
+ error = cont.Error;
+ if (file_count < 0) {
+ return error;
+ }
std::set<std::string> uncovered = this->FindUncoveredFiles(&cont);
- if ( file_count == 0 )
- {
- cmCTestLog(this->CTest, WARNING,
+ if (file_count == 0 && this->ExtraCoverageGlobs.empty()) {
+ cmCTestOptionalLog(
+ this->CTest, WARNING,
" Cannot find any coverage files. Ignoring Coverage request."
- << std::endl);
+ << std::endl,
+ this->Quiet);
return error;
- }
+ }
cmGeneratedFileStream covSumFile;
cmGeneratedFileStream covLogFile;
+ cmXMLWriter covSumXML(covSumFile);
+ cmXMLWriter covLogXML(covLogFile);
- if(!this->StartResultingXML(cmCTest::PartCoverage, "Coverage", covSumFile))
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot open coverage summary file." << std::endl);
+ if (!this->StartResultingXML(cmCTest::PartCoverage, "Coverage",
+ covSumFile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open coverage summary file."
+ << std::endl);
return -1;
- }
+ }
+ covSumFile.setf(std::ios::fixed, std::ios::floatfield);
+ covSumFile.precision(2);
- this->CTest->StartXML(covSumFile, this->AppendXML);
+ this->CTest->StartXML(covSumXML, this->AppendXML);
// Produce output xml files
- covSumFile << "<Coverage>" << std::endl
- << "\t<StartDateTime>" << coverage_start_time << "</StartDateTime>"
- << std::endl
- << "\t<StartTime>" << coverage_start_time_time << "</StartTime>"
- << std::endl;
+ covSumXML.StartElement("Coverage");
+ covSumXML.Element("StartDateTime", coverage_start_time);
+ covSumXML.Element("StartTime", coverage_start_time_time);
int logFileCount = 0;
- if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )
- {
+ if (!this->StartCoverageLogFile(covLogFile, logFileCount)) {
return -1;
- }
+ }
+ this->StartCoverageLogXML(covLogXML);
cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator fileIterator;
int cnt = 0;
long total_tested = 0;
long total_untested = 0;
- //std::string fullSourceDir = sourceDir + "/";
- //std::string fullBinaryDir = binaryDir + "/";
- cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- " Accumulating results (each . represents one file):" << std::endl);
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
+ // std::string fullSourceDir = sourceDir + "/";
+ // std::string fullBinaryDir = binaryDir + "/";
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, std::endl, this->Quiet);
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ " Accumulating results (each . represents one file):" << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
std::vector<std::string> errorsWhileAccumulating;
file_count = 0;
- for ( fileIterator = cont.TotalCoverage.begin();
- fileIterator != cont.TotalCoverage.end();
- ++fileIterator )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
- file_count ++;
- if ( file_count % 50 == 0 )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " processed: " << file_count
- << " out of "
- << cont.TotalCoverage.size() << std::endl);
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
- }
+ for (fileIterator = cont.TotalCoverage.begin();
+ fileIterator != cont.TotalCoverage.end(); ++fileIterator) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "." << std::flush,
+ this->Quiet);
+ file_count++;
+ if (file_count % 50 == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " processed: "
+ << file_count << " out of "
+ << cont.TotalCoverage.size() << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ }
const std::string fullFileName = fileIterator->first;
- bool shouldIDoCoverage
- = this->ShouldIDoCoverage(fullFileName.c_str(),
- sourceDir.c_str(), binaryDir.c_str());
- if ( !shouldIDoCoverage )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- ".NoDartCoverage found, so skip coverage check for: "
- << fullFileName.c_str()
- << std::endl);
+ bool shouldIDoCoverage = this->ShouldIDoCoverage(
+ fullFileName.c_str(), sourceDir.c_str(), binaryDir.c_str());
+ if (!shouldIDoCoverage) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ ".NoDartCoverage found, so skip coverage check for: "
+ << fullFileName << std::endl,
+ this->Quiet);
continue;
- }
+ }
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Process file: " << fullFileName << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Process file: " << fullFileName << std::endl,
+ this->Quiet);
- if ( !cmSystemTools::FileExists(fullFileName.c_str()) )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find file: "
- << fullFileName.c_str() << std::endl);
+ if (!cmSystemTools::FileExists(fullFileName.c_str())) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find file: " << fullFileName << std::endl);
continue;
- }
+ }
- if ( ++cnt % 100 == 0 )
- {
+ if (++cnt % 100 == 0) {
+ this->EndCoverageLogXML(covLogXML);
this->EndCoverageLogFile(covLogFile, logFileCount);
- logFileCount ++;
- if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )
- {
+ logFileCount++;
+ if (!this->StartCoverageLogFile(covLogFile, logFileCount)) {
return -1;
- }
}
+ this->StartCoverageLogXML(covLogXML);
+ }
- const std::string fileName
- = cmSystemTools::GetFilenameName(fullFileName.c_str());
+ const std::string fileName = cmSystemTools::GetFilenameName(fullFileName);
std::string shortFileName =
this->CTest->GetShortPathToFile(fullFileName.c_str());
- const cmCTestCoverageHandlerContainer::SingleFileCoverageVector& fcov
- = fileIterator->second;
- covLogFile << "\t<File Name=\"" << cmXMLSafe(fileName)
- << "\" FullPath=\"" << cmXMLSafe(shortFileName) << "\">\n"
- << "\t\t<Report>" << std::endl;
-
- std::ifstream ifs(fullFileName.c_str());
- if ( !ifs)
- {
- cmOStringStream ostr;
- ostr << "Cannot open source file: " << fullFileName.c_str();
+ const cmCTestCoverageHandlerContainer::SingleFileCoverageVector& fcov =
+ fileIterator->second;
+ covLogXML.StartElement("File");
+ covLogXML.Attribute("Name", fileName);
+ covLogXML.Attribute("FullPath", shortFileName);
+ covLogXML.StartElement("Report");
+
+ cmsys::ifstream ifs(fullFileName.c_str());
+ if (!ifs) {
+ std::ostringstream ostr;
+ ostr << "Cannot open source file: " << fullFileName;
errorsWhileAccumulating.push_back(ostr.str());
- error ++;
+ error++;
continue;
- }
+ }
int tested = 0;
int untested = 0;
cmCTestCoverageHandlerContainer::SingleFileCoverageVector::size_type cc;
std::string line;
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Actually performing coverage for: " << fullFileName << std::endl);
- for ( cc= 0; cc < fcov.size(); cc ++ )
- {
- if ( !cmSystemTools::GetLineFromStream(ifs, line) &&
- cc != fcov.size() -1 )
- {
- cmOStringStream ostr;
- ostr << "Problem reading source file: " << fullFileName.c_str()
- << " line:" << cc << " out total: " << fcov.size()-1;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Actually performing coverage for: " << fullFileName
+ << std::endl,
+ this->Quiet);
+ for (cc = 0; cc < fcov.size(); cc++) {
+ if (!cmSystemTools::GetLineFromStream(ifs, line) &&
+ cc != fcov.size() - 1) {
+ std::ostringstream ostr;
+ ostr << "Problem reading source file: " << fullFileName
+ << " line:" << cc << " out total: " << fcov.size() - 1;
errorsWhileAccumulating.push_back(ostr.str());
- error ++;
+ error++;
break;
- }
- covLogFile << "\t\t<Line Number=\"" << cc << "\" Count=\"" << fcov[cc]
- << "\">"
- << cmXMLSafe(line) << "</Line>" << std::endl;
- if ( fcov[cc] == 0 )
- {
- untested ++;
- }
- else if ( fcov[cc] > 0 )
- {
- tested ++;
- }
}
- if ( cmSystemTools::GetLineFromStream(ifs, line) )
- {
- cmOStringStream ostr;
- ostr << "Looks like there are more lines in the file: " << line;
- errorsWhileAccumulating.push_back(ostr.str());
+ covLogXML.StartElement("Line");
+ covLogXML.Attribute("Number", cc);
+ covLogXML.Attribute("Count", fcov[cc]);
+ covLogXML.Content(line);
+ covLogXML.EndElement(); // Line
+ if (fcov[cc] == 0) {
+ untested++;
+ } else if (fcov[cc] > 0) {
+ tested++;
}
+ }
+ if (cmSystemTools::GetLineFromStream(ifs, line)) {
+ std::ostringstream ostr;
+ ostr << "Looks like there are more lines in the file: " << fullFileName;
+ errorsWhileAccumulating.push_back(ostr.str());
+ }
float cper = 0;
float cmet = 0;
- if ( tested + untested > 0 )
- {
+ if (tested + untested > 0) {
cper = (100 * SAFEDIV(static_cast<float>(tested),
- static_cast<float>(tested + untested)));
- cmet = ( SAFEDIV(static_cast<float>(tested + 10),
- static_cast<float>(tested + untested + 10)));
- }
+ static_cast<float>(tested + untested)));
+ cmet = (SAFEDIV(static_cast<float>(tested + 10),
+ static_cast<float>(tested + untested + 10)));
+ }
total_tested += tested;
total_untested += untested;
- covLogFile << "\t\t</Report>" << std::endl
- << "\t</File>" << std::endl;
- covSumFile << "\t<File Name=\"" << cmXMLSafe(fileName)
- << "\" FullPath=\"" << cmXMLSafe(
- this->CTest->GetShortPathToFile(fullFileName.c_str()))
- << "\" Covered=\"" << (tested+untested > 0 ? "true":"false") << "\">\n"
- << "\t\t<LOCTested>" << tested << "</LOCTested>\n"
- << "\t\t<LOCUnTested>" << untested << "</LOCUnTested>\n"
- << "\t\t<PercentCoverage>";
- covSumFile.setf(std::ios::fixed, std::ios::floatfield);
- covSumFile.precision(2);
- covSumFile << (cper) << "</PercentCoverage>\n"
- << "\t\t<CoverageMetric>";
- covSumFile.setf(std::ios::fixed, std::ios::floatfield);
- covSumFile.precision(2);
- covSumFile << (cmet) << "</CoverageMetric>\n";
- this->WriteXMLLabels(covSumFile, shortFileName);
- covSumFile << "\t</File>" << std::endl;
- }
-
- //Handle all the files in the extra coverage globs that have no cov data
- for(std::set<std::string>::iterator i = uncovered.begin();
- i != uncovered.end(); ++i)
- {
+ covLogXML.EndElement(); // Report
+ covLogXML.EndElement(); // File
+ covSumXML.StartElement("File");
+ covSumXML.Attribute("Name", fileName);
+ covSumXML.Attribute("FullPath",
+ this->CTest->GetShortPathToFile(fullFileName.c_str()));
+ covSumXML.Attribute("Covered", tested + untested > 0 ? "true" : "false");
+ covSumXML.Element("LOCTested", tested);
+ covSumXML.Element("LOCUnTested", untested);
+ covSumXML.Element("PercentCoverage", cper);
+ covSumXML.Element("CoverageMetric", cmet);
+ this->WriteXMLLabels(covSumXML, shortFileName);
+ covSumXML.EndElement(); // File
+ }
+
+ // Handle all the files in the extra coverage globs that have no cov data
+ for (std::set<std::string>::iterator i = uncovered.begin();
+ i != uncovered.end(); ++i) {
std::string fileName = cmSystemTools::GetFilenameName(*i);
std::string fullPath = cont.SourceDir + "/" + *i;
- covLogFile << "\t<File Name=\"" << cmXMLSafe(fileName)
- << "\" FullPath=\"" << cmXMLSafe(*i) << "\">\n"
- << "\t\t<Report>" << std::endl;
+ covLogXML.StartElement("File");
+ covLogXML.Attribute("Name", fileName);
+ covLogXML.Attribute("FullPath", *i);
+ covLogXML.StartElement("Report");
- std::ifstream ifs(fullPath.c_str());
- if (!ifs)
- {
- cmOStringStream ostr;
- ostr << "Cannot open source file: " << fullPath.c_str();
+ cmsys::ifstream ifs(fullPath.c_str());
+ if (!ifs) {
+ std::ostringstream ostr;
+ ostr << "Cannot open source file: " << fullPath;
errorsWhileAccumulating.push_back(ostr.str());
- error ++;
+ error++;
+ covLogXML.EndElement(); // Report
+ covLogXML.EndElement(); // File
continue;
- }
+ }
int untested = 0;
std::string line;
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Actually performing coverage for: " << i->c_str() << std::endl);
- while (cmSystemTools::GetLineFromStream(ifs, line))
- {
- covLogFile << "\t\t<Line Number=\"" << untested << "\" Count=\"0\">"
- << cmXMLSafe(line) << "</Line>" << std::endl;
- untested ++;
- }
- covLogFile << "\t\t</Report>\n\t</File>" << std::endl;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Actually performing coverage for: " << *i << std::endl,
+ this->Quiet);
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ covLogXML.StartElement("Line");
+ covLogXML.Attribute("Number", untested);
+ covLogXML.Attribute("Count", 0);
+ covLogXML.Content(line);
+ covLogXML.EndElement(); // Line
+ untested++;
+ }
+ covLogXML.EndElement(); // Report
+ covLogXML.EndElement(); // File
total_untested += untested;
- covSumFile << "\t<File Name=\"" << cmXMLSafe(fileName)
- << "\" FullPath=\"" << cmXMLSafe(i->c_str())
- << "\" Covered=\"true\">\n"
- << "\t\t<LOCTested>0</LOCTested>\n"
- << "\t\t<LOCUnTested>" << untested << "</LOCUnTested>\n"
- << "\t\t<PercentCoverage>0</PercentCoverage>\n"
- << "\t\t<CoverageMetric>0</CoverageMetric>\n";
- this->WriteXMLLabels(covSumFile, *i);
- covSumFile << "\t</File>" << std::endl;
- }
-
+ covSumXML.StartElement("File");
+ covSumXML.Attribute("Name", fileName);
+ covSumXML.Attribute("FullPath", *i);
+ covSumXML.Attribute("Covered", "true");
+ covSumXML.Element("LOCTested", 0);
+ covSumXML.Element("LOCUnTested", untested);
+ covSumXML.Element("PercentCoverage", 0);
+ covSumXML.Element("CoverageMetric", 0);
+ this->WriteXMLLabels(covSumXML, *i);
+ covSumXML.EndElement(); // File
+ }
+
+ this->EndCoverageLogXML(covLogXML);
this->EndCoverageLogFile(covLogFile, logFileCount);
- if ( errorsWhileAccumulating.size() > 0 )
- {
+ if (!errorsWhileAccumulating.empty()) {
cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl);
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error(s) while accumulating results:" << std::endl);
+ "Error(s) while accumulating results:" << std::endl);
std::vector<std::string>::iterator erIt;
- for ( erIt = errorsWhileAccumulating.begin();
- erIt != errorsWhileAccumulating.end();
- ++ erIt )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- " " << erIt->c_str() << std::endl);
- }
+ for (erIt = errorsWhileAccumulating.begin();
+ erIt != errorsWhileAccumulating.end(); ++erIt) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, " " << *erIt << std::endl);
}
+ }
long total_lines = total_tested + total_untested;
- float percent_coverage = 100 * SAFEDIV(static_cast<float>(total_tested),
- static_cast<float>(total_lines));
- if ( total_lines == 0 )
- {
+ float percent_coverage = 100 *
+ SAFEDIV(static_cast<float>(total_tested), static_cast<float>(total_lines));
+ if (total_lines == 0) {
percent_coverage = 0;
- }
+ }
std::string end_time = this->CTest->CurrentTime();
- covSumFile << "\t<LOCTested>" << total_tested << "</LOCTested>\n"
- << "\t<LOCUntested>" << total_untested << "</LOCUntested>\n"
- << "\t<LOC>" << total_lines << "</LOC>\n"
- << "\t<PercentCoverage>";
- covSumFile.setf(std::ios::fixed, std::ios::floatfield);
- covSumFile.precision(2);
- covSumFile << (percent_coverage)<< "</PercentCoverage>\n"
- << "\t<EndDateTime>" << end_time << "</EndDateTime>\n"
- << "\t<EndTime>" <<
- static_cast<unsigned int>(cmSystemTools::GetTime())
- << "</EndTime>\n";
- covSumFile << "<ElapsedMinutes>" <<
- static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0
- << "</ElapsedMinutes>"
- << "</Coverage>" << std::endl;
- this->CTest->EndXML(covSumFile);
-
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "" << std::endl
- << "\tCovered LOC: "
- << total_tested << std::endl
- << "\tNot covered LOC: " << total_untested << std::endl
- << "\tTotal LOC: " << total_lines << std::endl
- << "\tPercentage Coverage: "
- << std::setiosflags(std::ios::fixed)
- << std::setprecision(2)
- << (percent_coverage) << "%" << std::endl);
+ covSumXML.Element("LOCTested", total_tested);
+ covSumXML.Element("LOCUntested", total_untested);
+ covSumXML.Element("LOC", total_lines);
+ covSumXML.Element("PercentCoverage", percent_coverage);
+ covSumXML.Element("EndDateTime", end_time);
+ covSumXML.Element("EndTime",
+ static_cast<unsigned int>(cmSystemTools::GetTime()));
+ covSumXML.Element(
+ "ElapsedMinutes",
+ static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start) / 6) /
+ 10.0);
+ covSumXML.EndElement(); // Coverage
+ this->CTest->EndXML(covSumXML);
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, ""
+ << std::endl
+ << "\tCovered LOC: " << total_tested << std::endl
+ << "\tNot covered LOC: " << total_untested << std::endl
+ << "\tTotal LOC: " << total_lines << std::endl
+ << "\tPercentage Coverage: "
+ << std::setiosflags(std::ios::fixed) << std::setprecision(2)
+ << (percent_coverage) << "%" << std::endl);
ofs << "\tCovered LOC: " << total_tested << std::endl
- << "\tNot covered LOC: " << total_untested << std::endl
- << "\tTotal LOC: " << total_lines << std::endl
- << "\tPercentage Coverage: "
- << std::setiosflags(std::ios::fixed)
- << std::setprecision(2)
- << (percent_coverage) << "%" << std::endl;
-
+ << "\tNot covered LOC: " << total_untested << std::endl
+ << "\tTotal LOC: " << total_lines << std::endl
+ << "\tPercentage Coverage: " << std::setiosflags(std::ios::fixed)
+ << std::setprecision(2) << (percent_coverage) << "%" << std::endl;
- if ( error )
- {
+ if (error) {
return -1;
- }
+ }
return 0;
}
-//----------------------------------------------------------------------
-void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile *mf)
+void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile* mf)
{
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " Add coverage exclude regular expressions." << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Add coverage exclude regular expressions." << std::endl,
+ this->Quiet);
this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_COVERAGE_EXCLUDE",
- this->CustomCoverageExclude);
+ this->CustomCoverageExclude);
this->CTest->PopulateCustomVector(mf, "CTEST_EXTRA_COVERAGE_GLOB",
- this->ExtraCoverageGlobs);
- std::vector<cmStdString>::iterator it;
- for ( it = this->CustomCoverageExclude.begin();
- it != this->CustomCoverageExclude.end();
- ++ it )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Add coverage exclude: "
- << it->c_str() << std::endl);
- }
- for ( it = this->ExtraCoverageGlobs.begin();
- it != this->ExtraCoverageGlobs.end(); ++it)
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Add coverage glob: "
- << it->c_str() << std::endl);
- }
+ this->ExtraCoverageGlobs);
+ std::vector<std::string>::iterator it;
+ for (it = this->CustomCoverageExclude.begin();
+ it != this->CustomCoverageExclude.end(); ++it) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Add coverage exclude: " << *it << std::endl,
+ this->Quiet);
+ }
+ for (it = this->ExtraCoverageGlobs.begin();
+ it != this->ExtraCoverageGlobs.end(); ++it) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Add coverage glob: " << *it << std::endl,
+ this->Quiet);
+ }
}
-//----------------------------------------------------------------------
// Fix for issue #4971 where the case of the drive letter component of
// the filenames might be different when analyzing gcov output.
//
@@ -731,130 +696,262 @@ void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile *mf)
#define fnc(s) s
#endif
-//----------------------------------------------------------------------
-bool IsFileInDir(const std::string &infile, const std::string &indir)
+bool IsFileInDir(const std::string& infile, const std::string& indir)
{
- std::string file = cmSystemTools::CollapseFullPath(infile.c_str());
- std::string dir = cmSystemTools::CollapseFullPath(indir.c_str());
-
- if (
- file.size() > dir.size() &&
- (fnc(file.substr(0, dir.size())) == fnc(dir)) &&
- file[dir.size()] == '/'
- )
- {
- return true;
- }
+ std::string file = cmSystemTools::CollapseFullPath(infile);
+ std::string dir = cmSystemTools::CollapseFullPath(indir);
- return false;
+ return file.size() > dir.size() &&
+ fnc(file.substr(0, dir.size())) == fnc(dir) && file[dir.size()] == '/';
}
-//----------------------------------------------------------------------
int cmCTestCoverageHandler::HandlePHPCoverage(
cmCTestCoverageHandlerContainer* cont)
{
cmParsePHPCoverage cov(*cont, this->CTest);
std::string coverageDir = this->CTest->GetBinaryDir() + "/xdebugCoverage";
- if(cmSystemTools::FileIsDirectory(coverageDir.c_str()))
- {
+ if (cmSystemTools::FileIsDirectory(coverageDir)) {
cov.ReadPHPCoverageDirectory(coverageDir.c_str());
- }
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+
+int cmCTestCoverageHandler::HandleCoberturaCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParseCoberturaCoverage cov(*cont, this->CTest);
+
+ // Assume the coverage.xml is in the binary directory
+ // check for the COBERTURADIR environment variable,
+ // if it doesn't exist or is empty, assume the
+ // binary directory is used.
+ std::string coverageXMLFile;
+ if (!cmSystemTools::GetEnv("COBERTURADIR", coverageXMLFile) ||
+ coverageXMLFile.empty()) {
+ coverageXMLFile = this->CTest->GetBinaryDir();
+ }
+ // build the find file string with the directory from above
+ coverageXMLFile += "/coverage.xml";
+
+ if (cmSystemTools::FileExists(coverageXMLFile.c_str())) {
+ // If file exists, parse it
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Parsing Cobertura XML file: " << coverageXMLFile
+ << std::endl,
+ this->Quiet);
+ cov.ReadCoverageXML(coverageXMLFile.c_str());
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find Cobertura XML file: " << coverageXMLFile
+ << std::endl,
+ this->Quiet);
+ }
return static_cast<int>(cont->TotalCoverage.size());
}
-//----------------------------------------------------------------------
+
int cmCTestCoverageHandler::HandleMumpsCoverage(
cmCTestCoverageHandlerContainer* cont)
{
// try gtm coverage
cmParseGTMCoverage cov(*cont, this->CTest);
- std::string coverageFile = this->CTest->GetBinaryDir() +
- "/gtm_coverage.mcov";
- if(cmSystemTools::FileExists(coverageFile.c_str()))
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Parsing Cache Coverage: " << coverageFile
- << std::endl);
+ std::string coverageFile =
+ this->CTest->GetBinaryDir() + "/gtm_coverage.mcov";
+ if (cmSystemTools::FileExists(coverageFile.c_str())) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Parsing Cache Coverage: " << coverageFile << std::endl,
+ this->Quiet);
cov.ReadCoverageFile(coverageFile.c_str());
return static_cast<int>(cont->TotalCoverage.size());
- }
- else
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " Cannot find foobar GTM coverage file: " << coverageFile
- << std::endl);
- }
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find GTM coverage file: " << coverageFile
+ << std::endl,
+ this->Quiet);
cmParseCacheCoverage ccov(*cont, this->CTest);
- coverageFile = this->CTest->GetBinaryDir() +
- "/cache_coverage.cmcov";
- if(cmSystemTools::FileExists(coverageFile.c_str()))
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Parsing Cache Coverage: " << coverageFile
- << std::endl);
+ coverageFile = this->CTest->GetBinaryDir() + "/cache_coverage.cmcov";
+ if (cmSystemTools::FileExists(coverageFile.c_str())) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Parsing Cache Coverage: " << coverageFile << std::endl,
+ this->Quiet);
ccov.ReadCoverageFile(coverageFile.c_str());
- }
- else
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " Cannot find Cache coverage file: " << coverageFile
- << std::endl);
- }
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find Cache coverage file: " << coverageFile
+ << std::endl,
+ this->Quiet);
+ }
return static_cast<int>(cont->TotalCoverage.size());
}
struct cmCTestCoverageHandlerLocale
{
cmCTestCoverageHandlerLocale()
- {
- if(const char* l = cmSystemTools::GetEnv("LC_ALL"))
- {
+ {
+ std::string l;
+ if (cmSystemTools::GetEnv("LC_ALL", l)) {
lc_all = l;
- }
- if(lc_all != "C")
- {
+ }
+ if (lc_all != "C") {
cmSystemTools::PutEnv("LC_ALL=C");
- }
}
+ }
~cmCTestCoverageHandlerLocale()
- {
- if(!lc_all.empty())
- {
- cmSystemTools::PutEnv(("LC_ALL=" + lc_all).c_str());
- }
- else
- {
+ {
+ if (!lc_all.empty()) {
+ cmSystemTools::PutEnv("LC_ALL=" + lc_all);
+ } else {
cmSystemTools::UnsetEnv("LC_ALL");
- }
}
+ }
std::string lc_all;
};
-//----------------------------------------------------------------------
+int cmCTestCoverageHandler::HandleJacocoCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParseJacocoCoverage cov = cmParseJacocoCoverage(*cont, this->CTest);
+
+ // Search in the source directory.
+ cmsys::Glob g1;
+ std::vector<std::string> files;
+ g1.SetRecurse(true);
+
+ std::string SourceDir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
+ std::string coverageFile = SourceDir + "/*jacoco.xml";
+
+ g1.FindFiles(coverageFile);
+ files = g1.GetFiles();
+
+ // ...and in the binary directory.
+ cmsys::Glob g2;
+ std::vector<std::string> binFiles;
+ g2.SetRecurse(true);
+ std::string binaryDir = this->CTest->GetCTestConfiguration("BuildDirectory");
+ std::string binCoverageFile = binaryDir + "/*jacoco.xml";
+ g2.FindFiles(binCoverageFile);
+ binFiles = g2.GetFiles();
+ if (!binFiles.empty()) {
+ files.insert(files.end(), binFiles.begin(), binFiles.end());
+ }
+
+ if (!files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found Jacoco Files, Performing Coverage" << std::endl,
+ this->Quiet);
+ cov.LoadCoverageData(files);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find Jacoco coverage files: " << coverageFile
+ << std::endl,
+ this->Quiet);
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+
+int cmCTestCoverageHandler::HandleDelphiCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParseDelphiCoverage cov = cmParseDelphiCoverage(*cont, this->CTest);
+ cmsys::Glob g;
+ std::vector<std::string> files;
+ g.SetRecurse(true);
+
+ std::string BinDir = this->CTest->GetBinaryDir();
+ std::string coverageFile = BinDir + "/*(*.pas).html";
+
+ g.FindFiles(coverageFile);
+ files = g.GetFiles();
+ if (!files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found Delphi HTML Files, Performing Coverage"
+ << std::endl,
+ this->Quiet);
+ cov.LoadCoverageData(files);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find Delphi coverage files: " << coverageFile
+ << std::endl,
+ this->Quiet);
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+
+int cmCTestCoverageHandler::HandleBlanketJSCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParseBlanketJSCoverage cov = cmParseBlanketJSCoverage(*cont, this->CTest);
+ std::string SourceDir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
+
+ // Look for something other than output.json, still JSON extension.
+ std::string coverageFile = SourceDir + "/*.json";
+ cmsys::Glob g;
+ std::vector<std::string> files;
+ std::vector<std::string> blanketFiles;
+ g.FindFiles(coverageFile);
+ files = g.GetFiles();
+ // Ensure that the JSON files found are the result of the
+ // Blanket.js output. Check for the "node-jscoverage"
+ // string on the second line
+ std::string line;
+ for (unsigned int fileEntry = 0; fileEntry < files.size(); fileEntry++) {
+ cmsys::ifstream in(files[fileEntry].c_str());
+ cmSystemTools::GetLineFromStream(in, line);
+ cmSystemTools::GetLineFromStream(in, line);
+ if (line.find("node-jscoverage") != std::string::npos) {
+ blanketFiles.push_back(files[fileEntry]);
+ }
+ }
+ // Take all files with the node-jscoverage string and parse those
+ if (!blanketFiles.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found BlanketJS output JSON, Performing Coverage"
+ << std::endl,
+ this->Quiet);
+ cov.LoadCoverageData(files);
+ } else {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find BlanketJS coverage files: " << coverageFile << std::endl,
+ this->Quiet);
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
int cmCTestCoverageHandler::HandleGCovCoverage(
cmCTestCoverageHandlerContainer* cont)
{
- std::string gcovCommand
- = this->CTest->GetCTestConfiguration("CoverageCommand");
- std::string gcovExtraFlags
- = this->CTest->GetCTestConfiguration("CoverageExtraFlags");
+ std::string gcovCommand =
+ this->CTest->GetCTestConfiguration("CoverageCommand");
+ if (gcovCommand.empty()) {
+ cmCTestLog(this->CTest, WARNING, "Could not find gcov." << std::endl);
+ return 0;
+ }
+ std::string gcovExtraFlags =
+ this->CTest->GetCTestConfiguration("CoverageExtraFlags");
+
+ // Immediately skip to next coverage option since codecov is only for Intel
+ // compiler
+ if (gcovCommand == "codecov") {
+ return 0;
+ }
// Style 1
- std::string st1gcovOutputRex1
- = "[0-9]+\\.[0-9]+% of [0-9]+ (source |)lines executed in file (.*)$";
+ std::string st1gcovOutputRex1 =
+ "[0-9]+\\.[0-9]+% of [0-9]+ (source |)lines executed in file (.*)$";
std::string st1gcovOutputRex2 = "^Creating (.*\\.gcov)\\.";
cmsys::RegularExpression st1re1(st1gcovOutputRex1.c_str());
cmsys::RegularExpression st1re2(st1gcovOutputRex2.c_str());
-
// Style 2
std::string st2gcovOutputRex1 = "^File *[`'](.*)'$";
- std::string st2gcovOutputRex2
- = "Lines executed: *[0-9]+\\.[0-9]+% of [0-9]+$";
+ std::string st2gcovOutputRex2 =
+ "Lines executed: *[0-9]+\\.[0-9]+% of [0-9]+$";
std::string st2gcovOutputRex3 = "^(.*)reating [`'](.*\\.gcov)'";
std::string st2gcovOutputRex4 = "^(.*):unexpected EOF *$";
std::string st2gcovOutputRex5 = "^(.*):cannot open source file*$";
- std::string st2gcovOutputRex6
- = "^(.*):source file is newer than graph file `(.*)'$";
+ std::string st2gcovOutputRex6 =
+ "^(.*):source file is newer than graph file `(.*)'$";
cmsys::RegularExpression st2re1(st2gcovOutputRex1.c_str());
cmsys::RegularExpression st2re2(st2gcovOutputRex2.c_str());
cmsys::RegularExpression st2re3(st2gcovOutputRex3.c_str());
@@ -866,29 +963,29 @@ int cmCTestCoverageHandler::HandleGCovCoverage(
this->FindGCovFiles(files);
std::vector<std::string>::iterator it;
- if ( files.size() == 0 )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " Cannot find any GCov coverage files."
- << std::endl);
+ if (files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find any GCov coverage files." << std::endl,
+ this->Quiet);
// No coverage files is a valid thing, so the exit code is 0
return 0;
- }
+ }
std::string testingDir = this->CTest->GetBinaryDir() + "/Testing";
std::string tempDir = testingDir + "/CoverageInfo";
- std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory();
cmSystemTools::MakeDirectory(tempDir.c_str());
- cmSystemTools::ChangeDirectory(tempDir.c_str());
+ cmWorkingDirectory workdir(tempDir);
int gcovStyle = 0;
std::set<std::string> missingFiles;
- std::string actualSourceFile = "";
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- " Processing coverage (each . represents one file):" << std::endl);
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
+ std::string actualSourceFile;
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ " Processing coverage (each . represents one file):" << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
int file_count = 0;
// make sure output from gcov is in English!
@@ -899,257 +996,216 @@ int cmCTestCoverageHandler::HandleGCovCoverage(
// These are binary files that you give as input to gcov so that it will
// give us text output we can analyze to summarize coverage.
//
- for ( it = files.begin(); it != files.end(); ++ it )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
+ for (it = files.begin(); it != files.end(); ++it) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "." << std::flush,
+ this->Quiet);
// Call gcov to get coverage data for this *.gcda file:
//
- std::string fileDir = cmSystemTools::GetFilenamePath(it->c_str());
- std::string command = "\"" + gcovCommand + "\" " +
- gcovExtraFlags + " " +
- "-o \"" + fileDir + "\" " +
- "\"" + *it + "\"";
+ std::string fileDir = cmSystemTools::GetFilenamePath(*it);
+ std::string command = "\"" + gcovCommand + "\" " + gcovExtraFlags + " " +
+ "-o \"" + fileDir + "\" " + "\"" + *it + "\"";
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, command.c_str()
- << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ command << std::endl, this->Quiet);
- std::string output = "";
- std::string errors = "";
+ std::string output;
+ std::string errors;
int retVal = 0;
- *cont->OFS << "* Run coverage for: " << fileDir.c_str() << std::endl;
- *cont->OFS << " Command: " << command.c_str() << std::endl;
- int res = this->CTest->RunCommand(command.c_str(), &output, &errors,
- &retVal, tempDir.c_str(), 0 /*this->TimeOut*/);
-
- *cont->OFS << " Output: " << output.c_str() << std::endl;
- *cont->OFS << " Errors: " << errors.c_str() << std::endl;
- if ( ! res )
- {
+ *cont->OFS << "* Run coverage for: " << fileDir << std::endl;
+ *cont->OFS << " Command: " << command << std::endl;
+ int res =
+ this->CTest->RunCommand(command.c_str(), &output, &errors, &retVal,
+ tempDir.c_str(), 0 /*this->TimeOut*/);
+
+ *cont->OFS << " Output: " << output << std::endl;
+ *cont->OFS << " Errors: " << errors << std::endl;
+ if (!res) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Problem running coverage on file: " << it->c_str() << std::endl);
+ "Problem running coverage on file: " << *it << std::endl);
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Command produced error: " << errors << std::endl);
- cont->Error ++;
+ "Command produced error: " << errors << std::endl);
+ cont->Error++;
continue;
- }
- if ( retVal != 0 )
- {
+ }
+ if (retVal != 0) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Coverage command returned: "
- << retVal << " while processing: " << it->c_str() << std::endl);
+ << retVal << " while processing: " << *it << std::endl);
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Command produced error: " << cont->Error << std::endl);
- }
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Command produced error: " << cont->Error << std::endl);
+ }
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
"--------------------------------------------------------------"
- << std::endl
- << output << std::endl
- << "--------------------------------------------------------------"
- << std::endl);
+ << std::endl
+ << output << std::endl
+ << "--------------------------------------------------------------"
+ << std::endl,
+ this->Quiet);
- std::vector<cmStdString> lines;
- std::vector<cmStdString>::iterator line;
+ std::vector<std::string> lines;
+ std::vector<std::string>::iterator line;
cmSystemTools::Split(output.c_str(), lines);
- for ( line = lines.begin(); line != lines.end(); ++line)
- {
+ for (line = lines.begin(); line != lines.end(); ++line) {
std::string sourceFile;
std::string gcovFile;
- cmCTestLog(this->CTest, DEBUG, "Line: [" << line->c_str() << "]"
- << std::endl);
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Line: [" << *line << "]" << std::endl, this->Quiet);
- if ( line->size() == 0 )
- {
+ if (line->empty()) {
// Ignore empty line; probably style 2
- }
- else if ( st1re1.find(line->c_str()) )
- {
- if ( gcovStyle == 0 )
- {
+ } else if (st1re1.find(line->c_str())) {
+ if (gcovStyle == 0) {
gcovStyle = 1;
- }
- if ( gcovStyle != 1 )
- {
+ }
+ if (gcovStyle != 1) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e1"
- << std::endl);
- cont->Error ++;
+ << std::endl);
+ cont->Error++;
break;
- }
+ }
actualSourceFile = "";
sourceFile = st1re1.match(2);
- }
- else if ( st1re2.find(line->c_str() ) )
- {
- if ( gcovStyle == 0 )
- {
+ } else if (st1re2.find(line->c_str())) {
+ if (gcovStyle == 0) {
gcovStyle = 1;
- }
- if ( gcovStyle != 1 )
- {
+ }
+ if (gcovStyle != 1) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e2"
- << std::endl);
- cont->Error ++;
+ << std::endl);
+ cont->Error++;
break;
- }
+ }
gcovFile = st1re2.match(1);
- }
- else if ( st2re1.find(line->c_str() ) )
- {
- if ( gcovStyle == 0 )
- {
+ } else if (st2re1.find(line->c_str())) {
+ if (gcovStyle == 0) {
gcovStyle = 2;
- }
- if ( gcovStyle != 2 )
- {
+ }
+ if (gcovStyle != 2) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e3"
- << std::endl);
- cont->Error ++;
+ << std::endl);
+ cont->Error++;
break;
- }
+ }
actualSourceFile = "";
sourceFile = st2re1.match(1);
- }
- else if ( st2re2.find(line->c_str() ) )
- {
- if ( gcovStyle == 0 )
- {
+ } else if (st2re2.find(line->c_str())) {
+ if (gcovStyle == 0) {
gcovStyle = 2;
- }
- if ( gcovStyle != 2 )
- {
+ }
+ if (gcovStyle != 2) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e4"
- << std::endl);
- cont->Error ++;
+ << std::endl);
+ cont->Error++;
break;
- }
}
- else if ( st2re3.find(line->c_str() ) )
- {
- if ( gcovStyle == 0 )
- {
+ } else if (st2re3.find(line->c_str())) {
+ if (gcovStyle == 0) {
gcovStyle = 2;
- }
- if ( gcovStyle != 2 )
- {
+ }
+ if (gcovStyle != 2) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e5"
- << std::endl);
- cont->Error ++;
+ << std::endl);
+ cont->Error++;
break;
- }
+ }
gcovFile = st2re3.match(2);
- }
- else if ( st2re4.find(line->c_str() ) )
- {
- if ( gcovStyle == 0 )
- {
+ } else if (st2re4.find(line->c_str())) {
+ if (gcovStyle == 0) {
gcovStyle = 2;
- }
- if ( gcovStyle != 2 )
- {
+ }
+ if (gcovStyle != 2) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e6"
- << std::endl);
- cont->Error ++;
+ << std::endl);
+ cont->Error++;
break;
- }
-
- cmCTestLog(this->CTest, WARNING, "Warning: " << st2re4.match(1)
- << " had unexpected EOF" << std::endl);
}
- else if ( st2re5.find(line->c_str() ) )
- {
- if ( gcovStyle == 0 )
- {
+
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "Warning: " << st2re4.match(1)
+ << " had unexpected EOF" << std::endl,
+ this->Quiet);
+ } else if (st2re5.find(line->c_str())) {
+ if (gcovStyle == 0) {
gcovStyle = 2;
- }
- if ( gcovStyle != 2 )
- {
+ }
+ if (gcovStyle != 2) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e7"
- << std::endl);
- cont->Error ++;
+ << std::endl);
+ cont->Error++;
break;
- }
-
- cmCTestLog(this->CTest, WARNING, "Warning: Cannot open file: "
- << st2re5.match(1) << std::endl);
}
- else if ( st2re6.find(line->c_str() ) )
- {
- if ( gcovStyle == 0 )
- {
+
+ cmCTestOptionalLog(this->CTest, WARNING, "Warning: Cannot open file: "
+ << st2re5.match(1) << std::endl,
+ this->Quiet);
+ } else if (st2re6.find(line->c_str())) {
+ if (gcovStyle == 0) {
gcovStyle = 2;
- }
- if ( gcovStyle != 2 )
- {
+ }
+ if (gcovStyle != 2) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e8"
- << std::endl);
- cont->Error ++;
+ << std::endl);
+ cont->Error++;
break;
- }
-
- cmCTestLog(this->CTest, WARNING, "Warning: File: " << st2re6.match(1)
- << " is newer than " << st2re6.match(2) << std::endl);
}
- else
- {
+
+ cmCTestOptionalLog(this->CTest, WARNING, "Warning: File: "
+ << st2re6.match(1) << " is newer than "
+ << st2re6.match(2) << std::endl,
+ this->Quiet);
+ } else {
// gcov 4.7 can have output lines saying "No executable lines" and
// "Removing 'filename.gcov'"... Don't log those as "errors."
- if(*line != "No executable lines" &&
- !cmSystemTools::StringStartsWith(line->c_str(), "Removing "))
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Unknown gcov output line: [" << line->c_str() << "]"
- << std::endl);
- cont->Error ++;
- //abort();
- }
+ if (*line != "No executable lines" &&
+ !cmSystemTools::StringStartsWith(line->c_str(), "Removing ")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output line: ["
+ << *line << "]" << std::endl);
+ cont->Error++;
+ // abort();
}
-
+ }
// If the last line of gcov output gave us a valid value for gcovFile,
// and we have an actualSourceFile, then insert a (or add to existing)
// SingleFileCoverageVector for actualSourceFile:
//
- if ( !gcovFile.empty() && !actualSourceFile.empty() )
- {
- cmCTestCoverageHandlerContainer::SingleFileCoverageVector& vec
- = cont->TotalCoverage[actualSourceFile];
-
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " in gcovFile: "
- << gcovFile << std::endl);
-
- std::ifstream ifile(gcovFile.c_str());
- if ( ! ifile )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open file: "
- << gcovFile << std::endl);
- }
- else
- {
+ if (!gcovFile.empty() && !actualSourceFile.empty()) {
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& vec =
+ cont->TotalCoverage[actualSourceFile];
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " in gcovFile: " << gcovFile << std::endl,
+ this->Quiet);
+
+ cmsys::ifstream ifile(gcovFile.c_str());
+ if (!ifile) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open file: " << gcovFile << std::endl);
+ } else {
long cnt = -1;
std::string nl;
- while ( cmSystemTools::GetLineFromStream(ifile, nl) )
- {
- cnt ++;
+ while (cmSystemTools::GetLineFromStream(ifile, nl)) {
+ cnt++;
- //TODO: Handle gcov 3.0 non-coverage lines
+ // TODO: Handle gcov 3.0 non-coverage lines
// Skip empty lines
- if ( !nl.size() )
- {
+ if (nl.empty()) {
continue;
- }
+ }
// Skip unused lines
- if ( nl.size() < 12 )
- {
+ if (nl.size() < 12) {
continue;
- }
+ }
// Read the coverage count from the beginning of the gcov output
// line
@@ -1160,120 +1216,364 @@ int cmCTestCoverageHandler::HandleGCovCoverage(
// output line
std::string lineNumber = nl.substr(10, 5);
- int lineIdx = atoi(lineNumber.c_str())-1;
- if ( lineIdx >= 0 )
- {
- while ( vec.size() <= static_cast<size_t>(lineIdx) )
- {
+ int lineIdx = atoi(lineNumber.c_str()) - 1;
+ if (lineIdx >= 0) {
+ while (vec.size() <= static_cast<size_t>(lineIdx)) {
vec.push_back(-1);
- }
+ }
// Initially all entries are -1 (not used). If we get coverage
// information, increment it to 0 first.
- if ( vec[lineIdx] < 0 )
- {
- if ( cov > 0 || prefix.find("#") != prefix.npos )
- {
+ if (vec[lineIdx] < 0) {
+ if (cov > 0 || prefix.find('#') != std::string::npos) {
vec[lineIdx] = 0;
- }
}
+ }
vec[lineIdx] += cov;
- }
}
}
-
- actualSourceFile = "";
}
+ actualSourceFile = "";
+ }
- if ( !sourceFile.empty() && actualSourceFile.empty() )
- {
+ if (!sourceFile.empty() && actualSourceFile.empty()) {
gcovFile = "";
// Is it in the source dir or the binary dir?
//
- if ( IsFileInDir(sourceFile, cont->SourceDir) )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " produced s: "
- << sourceFile.c_str() << std::endl);
- *cont->OFS << " produced in source dir: " << sourceFile.c_str()
- << std::endl;
- actualSourceFile
- = cmSystemTools::CollapseFullPath(sourceFile.c_str());
- }
- else if ( IsFileInDir(sourceFile, cont->BinaryDir) )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " produced b: "
- << sourceFile.c_str() << std::endl);
- *cont->OFS << " produced in binary dir: " << sourceFile.c_str()
- << std::endl;
- actualSourceFile
- = cmSystemTools::CollapseFullPath(sourceFile.c_str());
- }
+ if (IsFileInDir(sourceFile, cont->SourceDir)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " produced s: " << sourceFile << std::endl,
+ this->Quiet);
+ *cont->OFS << " produced in source dir: " << sourceFile
+ << std::endl;
+ actualSourceFile = cmSystemTools::CollapseFullPath(sourceFile);
+ } else if (IsFileInDir(sourceFile, cont->BinaryDir)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " produced b: " << sourceFile << std::endl,
+ this->Quiet);
+ *cont->OFS << " produced in binary dir: " << sourceFile
+ << std::endl;
+ actualSourceFile = cmSystemTools::CollapseFullPath(sourceFile);
+ }
- if ( actualSourceFile.empty() )
- {
- if ( missingFiles.find(sourceFile) == missingFiles.end() )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Something went wrong" << std::endl);
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Cannot find file: ["
- << sourceFile.c_str() << "]" << std::endl);
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " in source dir: ["
- << cont->SourceDir.c_str() << "]"
- << std::endl);
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " or binary dir: ["
- << cont->BinaryDir.size() << "]"
- << std::endl);
+ if (actualSourceFile.empty()) {
+ if (missingFiles.find(sourceFile) == missingFiles.end()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Something went wrong" << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Cannot find file: [" << sourceFile << "]"
+ << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " in source dir: [" << cont->SourceDir << "]"
+ << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " or binary dir: [" << cont->BinaryDir.size()
+ << "]" << std::endl,
+ this->Quiet);
*cont->OFS << " Something went wrong. Cannot find file: "
- << sourceFile.c_str()
- << " in source dir: " << cont->SourceDir.c_str()
- << " or binary dir: " << cont->BinaryDir.c_str() << std::endl;
+ << sourceFile << " in source dir: " << cont->SourceDir
+ << " or binary dir: " << cont->BinaryDir << std::endl;
missingFiles.insert(sourceFile);
- }
}
}
}
+ }
file_count++;
- if ( file_count % 50 == 0 )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " processed: " << file_count
- << " out of " << files.size() << std::endl);
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
+ if (file_count % 50 == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " processed: " << file_count << " out of "
+ << files.size() << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ }
+ }
+
+ return file_count;
+}
+
+int cmCTestCoverageHandler::HandleLCovCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ std::string lcovCommand =
+ this->CTest->GetCTestConfiguration("CoverageCommand");
+ std::string lcovExtraFlags =
+ this->CTest->GetCTestConfiguration("CoverageExtraFlags");
+ if (lcovCommand != "codecov") {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Not a valid Intel Coverage command." << std::endl,
+ this->Quiet);
+ return 0;
+ }
+ // There is only percentage completed output from LCOV
+ std::string st2lcovOutputRex3 = "[0-9]+%";
+ cmsys::RegularExpression st2re3(st2lcovOutputRex3.c_str());
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " This is coverage command: " << lcovCommand << std::endl,
+ this->Quiet);
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " These are coverage command flags: " << lcovExtraFlags
+ << std::endl,
+ this->Quiet);
+
+ std::vector<std::string> files;
+ if (!this->FindLCovFiles(files)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error while finding LCov files.\n");
+ return 0;
+ }
+ std::vector<std::string>::iterator it;
+
+ if (files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find any LCov coverage files." << std::endl,
+ this->Quiet);
+ // No coverage files is a valid thing, so the exit code is 0
+ return 0;
+ }
+ std::string testingDir = this->CTest->GetBinaryDir();
+
+ std::set<std::string> missingFiles;
+
+ std::string actualSourceFile;
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ " Processing coverage (each . represents one file):" << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ int file_count = 0;
+
+ // make sure output from lcov is in English!
+ cmCTestCoverageHandlerLocale locale_C;
+ static_cast<void>(locale_C);
+
+ // In intel compiler we have to call codecov only once in each executable
+ // directory. It collects all *.dyn files to generate .dpi file.
+ for (it = files.begin(); it != files.end(); ++it) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "." << std::flush,
+ this->Quiet);
+ std::string fileDir = cmSystemTools::GetFilenamePath(*it);
+ cmWorkingDirectory workdir(fileDir);
+ std::string command = "\"" + lcovCommand + "\" " + lcovExtraFlags + " ";
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Current coverage dir: " << fileDir << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ command << std::endl, this->Quiet);
+
+ std::string output;
+ std::string errors;
+ int retVal = 0;
+ *cont->OFS << "* Run coverage for: " << fileDir << std::endl;
+ *cont->OFS << " Command: " << command << std::endl;
+ int res =
+ this->CTest->RunCommand(command.c_str(), &output, &errors, &retVal,
+ fileDir.c_str(), 0 /*this->TimeOut*/);
+
+ *cont->OFS << " Output: " << output << std::endl;
+ *cont->OFS << " Errors: " << errors << std::endl;
+ if (!res) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem running coverage on file: " << *it << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Command produced error: " << errors << std::endl);
+ cont->Error++;
+ continue;
+ }
+ if (retVal != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Coverage command returned: "
+ << retVal << " while processing: " << *it << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Command produced error: " << cont->Error << std::endl);
+ }
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "--------------------------------------------------------------"
+ << std::endl
+ << output << std::endl
+ << "--------------------------------------------------------------"
+ << std::endl,
+ this->Quiet);
+
+ std::vector<std::string> lines;
+ std::vector<std::string>::iterator line;
+
+ cmSystemTools::Split(output.c_str(), lines);
+
+ for (line = lines.begin(); line != lines.end(); ++line) {
+ std::string sourceFile;
+ std::string lcovFile;
+
+ if (line->empty()) {
+ // Ignore empty line
+ }
+ // Look for LCOV files in binary directory
+ // Intel Compiler creates a CodeCoverage dir for each subfolder and
+ // each subfolder has LCOV files
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOff();
+ std::string dir;
+ std::vector<std::string> lcovFiles;
+ dir = this->CTest->GetBinaryDir();
+ std::string daGlob;
+ daGlob = dir;
+ daGlob += "/*.LCOV";
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " looking for LCOV files in: " << daGlob << std::endl, this->Quiet);
+ gl.FindFiles(daGlob);
+ // Keep a list of all LCOV files
+ lcovFiles.insert(lcovFiles.end(), gl.GetFiles().begin(),
+ gl.GetFiles().end());
+
+ for (std::vector<std::string>::iterator a = lcovFiles.begin();
+ a != lcovFiles.end(); ++a) {
+ lcovFile = *a;
+ cmsys::ifstream srcead(lcovFile.c_str());
+ if (!srcead) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open file: " << lcovFile << std::endl);
+ }
+ std::string srcname;
+
+ int success = cmSystemTools::GetLineFromStream(srcead, srcname);
+ if (!success) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error while parsing lcov file '"
+ << lcovFile << "':"
+ << " No source file name found!" << std::endl);
+ return 0;
+ }
+ srcname = srcname.substr(18);
+ // We can directly read found LCOV files to determine the source
+ // files
+ sourceFile = srcname;
+ actualSourceFile = srcname;
+
+ for (std::vector<std::string>::iterator t = lcovFiles.begin();
+ t != lcovFiles.end(); ++t) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found LCOV File: " << *t << std::endl,
+ this->Quiet);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "SourceFile: " << sourceFile << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "lCovFile: " << lcovFile << std::endl, this->Quiet);
+
+ // If we have some LCOV files to process
+ if (!lcovFile.empty() && !actualSourceFile.empty()) {
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& vec =
+ cont->TotalCoverage[actualSourceFile];
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " in lcovFile: " << lcovFile << std::endl,
+ this->Quiet);
+
+ cmsys::ifstream ifile(lcovFile.c_str());
+ if (!ifile) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open file: " << lcovFile << std::endl);
+ } else {
+ long cnt = -1;
+ std::string nl;
+
+ // Skip the first line
+ cmSystemTools::GetLineFromStream(ifile, nl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "File is ready, start reading." << std::endl,
+ this->Quiet);
+ while (cmSystemTools::GetLineFromStream(ifile, nl)) {
+ cnt++;
+
+ // Skip empty lines
+ if (nl.empty()) {
+ continue;
+ }
+
+ // Skip unused lines
+ if (nl.size() < 12) {
+ continue;
+ }
+
+ // Read the coverage count from the beginning of the lcov
+ // output line
+ std::string prefix = nl.substr(0, 17);
+ int cov = atoi(prefix.c_str());
+
+ // Read the line number starting at the 17th character of the
+ // lcov output line
+ std::string lineNumber = nl.substr(17, 7);
+
+ int lineIdx = atoi(lineNumber.c_str()) - 1;
+ if (lineIdx >= 0) {
+ while (vec.size() <= static_cast<size_t>(lineIdx)) {
+ vec.push_back(-1);
+ }
+
+ // Initially all entries are -1 (not used). If we get coverage
+ // information, increment it to 0 first.
+ if (vec[lineIdx] < 0) {
+ if (cov > 0 || prefix.find('#') != std::string::npos) {
+ vec[lineIdx] = 0;
+ }
+ }
+
+ vec[lineIdx] += cov;
+ }
+ }
+ }
+
+ actualSourceFile = "";
+ }
}
}
- cmSystemTools::ChangeDirectory(currentDirectory.c_str());
+ file_count++;
+
+ if (file_count % 50 == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " processed: " << file_count << " out of "
+ << files.size() << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
+ }
+ }
+
return file_count;
}
-//----------------------------------------------------------------------------
void cmCTestCoverageHandler::FindGCovFiles(std::vector<std::string>& files)
{
cmsys::Glob gl;
gl.RecurseOn();
gl.RecurseThroughSymlinksOff();
- for(LabelMapType::const_iterator lmi = this->TargetDirs.begin();
- lmi != this->TargetDirs.end(); ++lmi)
- {
+ for (LabelMapType::const_iterator lmi = this->TargetDirs.begin();
+ lmi != this->TargetDirs.end(); ++lmi) {
// Skip targets containing no interesting labels.
- if(!this->IntersectsFilter(lmi->second))
- {
+ if (!this->IntersectsFilter(lmi->second)) {
continue;
- }
+ }
// Coverage files appear next to their object files in the target
// support directory.
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " globbing for coverage in: " << lmi->first << std::endl);
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " globbing for coverage in: " << lmi->first << std::endl, this->Quiet);
std::string daGlob = lmi->first;
daGlob += "/*.da";
gl.FindFiles(daGlob);
@@ -1282,10 +1582,42 @@ void cmCTestCoverageHandler::FindGCovFiles(std::vector<std::string>& files)
daGlob += "/*.gcda";
gl.FindFiles(daGlob);
files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
- }
+ }
+}
+
+bool cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files)
+{
+ cmsys::Glob gl;
+ gl.RecurseOff(); // No need of recurse if -prof_dir${BUILD_DIR} flag is
+ // used while compiling.
+ gl.RecurseThroughSymlinksOff();
+ std::string buildDir = this->CTest->GetCTestConfiguration("BuildDirectory");
+ cmWorkingDirectory workdir(buildDir);
+
+ // Run profmerge to merge all *.dyn files into dpi files
+ if (!cmSystemTools::RunSingleCommand("profmerge")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Error while running profmerge.\n");
+ return false;
+ }
+
+ // DPI file should appear in build directory
+ std::string daGlob;
+ daGlob = buildDir;
+ daGlob += "/*.dpi";
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " looking for dpi files in: " << daGlob << std::endl,
+ this->Quiet);
+ if (!gl.FindFiles(daGlob)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error while finding files matching " << daGlob << std::endl);
+ return false;
+ }
+ files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Now searching in: " << daGlob << std::endl, this->Quiet);
+ return true;
}
-//----------------------------------------------------------------------
int cmCTestCoverageHandler::HandleTracePyCoverage(
cmCTestCoverageHandlerContainer* cont)
{
@@ -1296,338 +1628,290 @@ int cmCTestCoverageHandler::HandleTracePyCoverage(
gl.FindFiles(daGlob);
std::vector<std::string> files = gl.GetFiles();
- if ( files.size() == 0 )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " Cannot find any Python Trace.py coverage files."
- << std::endl);
+ if (files.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find any Python Trace.py coverage files."
+ << std::endl,
+ this->Quiet);
// No coverage files is a valid thing, so the exit code is 0
return 0;
- }
+ }
std::string testingDir = this->CTest->GetBinaryDir() + "/Testing";
std::string tempDir = testingDir + "/CoverageInfo";
- std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory();
cmSystemTools::MakeDirectory(tempDir.c_str());
- cmSystemTools::ChangeDirectory(tempDir.c_str());
-
- cmSystemTools::ChangeDirectory(currentDirectory.c_str());
std::vector<std::string>::iterator fileIt;
int file_count = 0;
- for ( fileIt = files.begin(); fileIt != files.end(); ++ fileIt )
- {
+ for (fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
std::string fileName = this->FindFile(cont, *fileIt);
- if ( fileName.empty() )
- {
+ if (fileName.empty()) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot find source Python file corresponding to: "
- << fileIt->c_str() << std::endl);
+ "Cannot find source Python file corresponding to: "
+ << *fileIt << std::endl);
continue;
- }
+ }
- std::string actualSourceFile
- = cmSystemTools::CollapseFullPath(fileName.c_str());
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " Check coverage for file: " << actualSourceFile.c_str()
- << std::endl);
- cmCTestCoverageHandlerContainer::SingleFileCoverageVector* vec
- = &cont->TotalCoverage[actualSourceFile];
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " in file: " << fileIt->c_str() << std::endl);
- std::ifstream ifile(fileIt->c_str());
- if ( ! ifile )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open file: "
- << fileIt->c_str() << std::endl);
- }
- else
- {
+ std::string actualSourceFile = cmSystemTools::CollapseFullPath(fileName);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Check coverage for file: " << actualSourceFile
+ << std::endl,
+ this->Quiet);
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector* vec =
+ &cont->TotalCoverage[actualSourceFile];
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " in file: " << *fileIt << std::endl, this->Quiet);
+ cmsys::ifstream ifile(fileIt->c_str());
+ if (!ifile) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open file: " << *fileIt << std::endl);
+ } else {
long cnt = -1;
std::string nl;
- while ( cmSystemTools::GetLineFromStream(ifile, nl) )
- {
- cnt ++;
+ while (cmSystemTools::GetLineFromStream(ifile, nl)) {
+ cnt++;
// Skip empty lines
- if ( !nl.size() )
- {
+ if (nl.empty()) {
continue;
- }
+ }
// Skip unused lines
- if ( nl.size() < 12 )
- {
+ if (nl.size() < 12) {
continue;
- }
+ }
// Read the coverage count from the beginning of the Trace.py output
// line
std::string prefix = nl.substr(0, 6);
- if ( prefix[5] != ' ' && prefix[5] != ':' )
- {
+ if (prefix[5] != ' ' && prefix[5] != ':') {
// This is a hack. We should really do something more elaborate
prefix = nl.substr(0, 7);
- if ( prefix[6] != ' ' && prefix[6] != ':' )
- {
+ if (prefix[6] != ' ' && prefix[6] != ':') {
prefix = nl.substr(0, 8);
- if ( prefix[7] != ' ' && prefix[7] != ':' )
- {
+ if (prefix[7] != ' ' && prefix[7] != ':') {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Currently the limit is maximum coverage of 999999"
- << std::endl);
- }
+ "Currently the limit is maximum coverage of 999999"
+ << std::endl);
}
}
+ }
int cov = atoi(prefix.c_str());
- if ( prefix[prefix.size()-1] != ':' )
- {
+ if (prefix[prefix.size() - 1] != ':') {
// This line does not have ':' so no coverage here. That said,
// Trace.py does not handle not covered lines versus comments etc.
// So, this will be set to 0.
cov = 0;
- }
- cmCTestLog(this->CTest, DEBUG, "Prefix: " << prefix.c_str()
- << " cov: " << cov
- << std::endl);
+ }
+ cmCTestOptionalLog(
+ this->CTest, DEBUG,
+ "Prefix: " << prefix << " cov: " << cov << std::endl, this->Quiet);
// Read the line number starting at the 10th character of the gcov
// output line
long lineIdx = cnt;
- if ( lineIdx >= 0 )
- {
- while ( vec->size() <=
- static_cast<size_t>(lineIdx) )
- {
+ if (lineIdx >= 0) {
+ while (vec->size() <= static_cast<size_t>(lineIdx)) {
vec->push_back(-1);
- }
+ }
// Initially all entries are -1 (not used). If we get coverage
// information, increment it to 0 first.
- if ( (*vec)[lineIdx] < 0 )
- {
- if ( cov >= 0 )
- {
+ if ((*vec)[lineIdx] < 0) {
+ if (cov >= 0) {
(*vec)[lineIdx] = 0;
- }
}
- (*vec)[lineIdx] += cov;
}
+ (*vec)[lineIdx] += cov;
}
}
- ++ file_count;
}
- cmSystemTools::ChangeDirectory(currentDirectory.c_str());
+ ++file_count;
+ }
return file_count;
}
-//----------------------------------------------------------------------
std::string cmCTestCoverageHandler::FindFile(
- cmCTestCoverageHandlerContainer* cont,
- std::string fileName)
+ cmCTestCoverageHandlerContainer* cont, std::string const& fileName)
{
- std::string fileNameNoE
- = cmSystemTools::GetFilenameWithoutLastExtension(fileName);
+ std::string fileNameNoE =
+ cmSystemTools::GetFilenameWithoutLastExtension(fileName);
// First check in source and binary directory
std::string fullName = cont->SourceDir + "/" + fileNameNoE + ".py";
- if ( cmSystemTools::FileExists(fullName.c_str()) )
- {
+ if (cmSystemTools::FileExists(fullName.c_str())) {
return fullName;
- }
+ }
fullName = cont->BinaryDir + "/" + fileNameNoE + ".py";
- if ( cmSystemTools::FileExists(fullName.c_str()) )
- {
+ if (cmSystemTools::FileExists(fullName.c_str())) {
return fullName;
- }
+ }
return "";
}
// This is a header put on each marked up source file
-namespace
-{
- const char* bullseyeHelp[] =
- {" Coverage produced by bullseye covbr tool: ",
- " www.bullseye.com/help/ref_covbr.html",
- " * An arrow --> indicates incomplete coverage.",
- " * An X indicates a function that was invoked, a switch label that ",
- " was exercised, a try-block that finished, or an exception handler ",
- " that was invoked.",
- " * A T or F indicates a boolean decision that evaluated true or false,",
- " respectively.",
- " * A t or f indicates a boolean condition within a decision if the ",
- " condition evaluated true or false, respectively.",
- " * A k indicates a constant decision or condition.",
- " * The slash / means this probe is excluded from summary results. ",
- 0};
+namespace {
+const char* bullseyeHelp[] = {
+ " Coverage produced by bullseye covbr tool: ",
+ " www.bullseye.com/help/ref_covbr.html",
+ " * An arrow --> indicates incomplete coverage.",
+ " * An X indicates a function that was invoked, a switch label that ",
+ " was exercised, a try-block that finished, or an exception handler ",
+ " that was invoked.",
+ " * A T or F indicates a boolean decision that evaluated true or false,",
+ " respectively.",
+ " * A t or f indicates a boolean condition within a decision if the ",
+ " condition evaluated true or false, respectively.",
+ " * A k indicates a constant decision or condition.",
+ " * The slash / means this probe is excluded from summary results. ",
+ CM_NULLPTR
+};
}
-//----------------------------------------------------------------------
int cmCTestCoverageHandler::RunBullseyeCoverageBranch(
cmCTestCoverageHandlerContainer* cont,
- std::set<cmStdString>& coveredFileNames,
- std::vector<std::string>& files,
+ std::set<std::string>& coveredFileNames, std::vector<std::string>& files,
std::vector<std::string>& filesFullPath)
{
- if(files.size() != filesFullPath.size())
- {
+ if (files.size() != filesFullPath.size()) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Files and full path files not the same size?:\n");
return 0;
- }
+ }
// create the output stream for the CoverageLog-N.xml file
cmGeneratedFileStream covLogFile;
+ cmXMLWriter covLogXML(covLogFile);
int logFileCount = 0;
- if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )
- {
+ if (!this->StartCoverageLogFile(covLogFile, logFileCount)) {
return -1;
- }
+ }
+ this->StartCoverageLogXML(covLogXML);
// for each file run covbr on that file to get the coverage
// information for that file
std::string outputFile;
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "run covbr: "
- << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "run covbr: " << std::endl, this->Quiet);
- if(!this->RunBullseyeCommand(cont, "covbr", 0, outputFile))
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "error running covbr for." << "\n");
+ if (!this->RunBullseyeCommand(cont, "covbr", CM_NULLPTR, outputFile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "error running covbr for."
+ << "\n");
return -1;
- }
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "covbr output in " << outputFile
- << std::endl);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "covbr output in " << outputFile << std::endl,
+ this->Quiet);
// open the output file
- std::ifstream fin(outputFile.c_str());
- if(!fin)
- {
+ cmsys::ifstream fin(outputFile.c_str());
+ if (!fin) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot open coverage file: " <<
- outputFile.c_str() << std::endl);
+ "Cannot open coverage file: " << outputFile << std::endl);
return 0;
- }
- std::map<cmStdString, cmStdString> fileMap;
+ }
+ std::map<std::string, std::string> fileMap;
std::vector<std::string>::iterator fp = filesFullPath.begin();
- for(std::vector<std::string>::iterator f = files.begin();
- f != files.end(); ++f, ++fp)
- {
+ for (std::vector<std::string>::iterator f = files.begin(); f != files.end();
+ ++f, ++fp) {
fileMap[*f] = *fp;
- }
+ }
- int count =0; // keep count of the number of files
+ int count = 0; // keep count of the number of files
// Now parse each line from the bullseye cov log file
std::string lineIn;
bool valid = false; // are we in a valid output file
- int line = 0; // line of the current file
- cmStdString file;
- while(cmSystemTools::GetLineFromStream(fin, lineIn))
- {
+ int line = 0; // line of the current file
+ std::string file;
+ while (cmSystemTools::GetLineFromStream(fin, lineIn)) {
bool startFile = false;
- if(lineIn.size() > 1 && lineIn[lineIn.size()-1] == ':')
- {
- file = lineIn.substr(0, lineIn.size()-1);
- if(coveredFileNames.find(file) != coveredFileNames.end())
- {
+ if (lineIn.size() > 1 && lineIn[lineIn.size() - 1] == ':') {
+ file = lineIn.substr(0, lineIn.size() - 1);
+ if (coveredFileNames.find(file) != coveredFileNames.end()) {
startFile = true;
- }
}
- if(startFile)
- {
+ }
+ if (startFile) {
// if we are in a valid file close it because a new one started
- if(valid)
- {
- covLogFile << "\t\t</Report>" << std::endl
- << "\t</File>" << std::endl;
- }
+ if (valid) {
+ covLogXML.EndElement(); // Report
+ covLogXML.EndElement(); // File
+ }
// only allow 100 files in each log file
- if ( count != 0 && count % 100 == 0 )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "start a new log file: "
- << count
- << std::endl);
+ if (count != 0 && count % 100 == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "start a new log file: " << count << std::endl,
+ this->Quiet);
+ this->EndCoverageLogXML(covLogXML);
this->EndCoverageLogFile(covLogFile, logFileCount);
- logFileCount ++;
- if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )
- {
+ logFileCount++;
+ if (!this->StartCoverageLogFile(covLogFile, logFileCount)) {
return -1;
- }
- count++; // move on one
}
- std::map<cmStdString, cmStdString>::iterator
- i = fileMap.find(file);
+ this->StartCoverageLogXML(covLogXML);
+ count++; // move on one
+ }
+ std::map<std::string, std::string>::iterator i = fileMap.find(file);
// if the file should be covered write out the header for that file
- if(i != fileMap.end())
- {
+ if (i != fileMap.end()) {
// we have a new file so count it in the output
count++;
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Produce coverage for file: "
- << file.c_str() << " " << count
- << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Produce coverage for file: " << file << " "
+ << count << std::endl,
+ this->Quiet);
// start the file output
- covLogFile << "\t<File Name=\""
- << cmXMLSafe(i->first)
- << "\" FullPath=\"" << cmXMLSafe(
- this->CTest->GetShortPathToFile(
- i->second.c_str())) << "\">" << std::endl
- << "\t\t<Report>" << std::endl;
+ covLogXML.StartElement("File");
+ covLogXML.Attribute("Name", i->first);
+ covLogXML.Attribute(
+ "FullPath", this->CTest->GetShortPathToFile(i->second.c_str()));
+ covLogXML.StartElement("Report");
// write the bullseye header
- line =0;
- for(int k =0; bullseyeHelp[k] != 0; ++k)
- {
- covLogFile << "\t\t<Line Number=\"" << line << "\" Count=\"-1\">"
- << cmXMLSafe(bullseyeHelp[k])
- << "</Line>" << std::endl;
+ line = 0;
+ for (int k = 0; bullseyeHelp[k] != CM_NULLPTR; ++k) {
+ covLogXML.StartElement("Line");
+ covLogXML.Attribute("Number", line);
+ covLogXML.Attribute("Count", -1);
+ covLogXML.Content(bullseyeHelp[k]);
+ covLogXML.EndElement(); // Line
line++;
- }
- valid = true; // we are in a valid file section
}
- else
- {
+ valid = true; // we are in a valid file section
+ } else {
// this is not a file that we want coverage for
valid = false;
- }
}
+ }
// we are not at a start file, and we are in a valid file output the line
- else if(valid)
- {
- covLogFile << "\t\t<Line Number=\"" << line << "\" Count=\"-1\">"
- << cmXMLSafe(lineIn)
- << "</Line>" << std::endl;
+ else if (valid) {
+ covLogXML.StartElement("Line");
+ covLogXML.Attribute("Number", line);
+ covLogXML.Attribute("Count", -1);
+ covLogXML.Content(lineIn);
+ covLogXML.EndElement(); // Line
line++;
- }
}
+ }
// if we ran out of lines a valid file then close that file
- if(valid)
- {
- covLogFile << "\t\t</Report>" << std::endl
- << "\t</File>" << std::endl;
- }
+ if (valid) {
+ covLogXML.EndElement(); // Report
+ covLogXML.EndElement(); // File
+ }
+ this->EndCoverageLogXML(covLogXML);
this->EndCoverageLogFile(covLogFile, logFileCount);
return 1;
}
-//----------------------------------------------------------------------
int cmCTestCoverageHandler::RunBullseyeCommand(
- cmCTestCoverageHandlerContainer* cont,
- const char* cmd,
- const char* arg,
+ cmCTestCoverageHandlerContainer* cont, const char* cmd, const char* arg,
std::string& outputFile)
{
std::string program = cmSystemTools::FindProgram(cmd);
- if(program.size() == 0)
- {
+ if (program.empty()) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find :" << cmd << "\n");
return 0;
- }
- if(arg)
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Run : " << program.c_str() << " " << arg << "\n");
- }
- else
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Run : " << program.c_str() << "\n");
- }
+ }
+ if (arg) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run : " << program << " " << arg << "\n", this->Quiet);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run : " << program << "\n", this->Quiet);
+ }
// create a process object and start it
cmCTestRunProcess runCoverageSrc;
runCoverageSrc.SetCommand(program.c_str());
@@ -1641,52 +1925,46 @@ int cmCTestCoverageHandler::RunBullseyeCommand(
stderrFile += ".stderr";
runCoverageSrc.SetStdoutFile(stdoutFile.c_str());
runCoverageSrc.SetStderrFile(stderrFile.c_str());
- if(!runCoverageSrc.StartProcess())
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Could not run : "
- << program.c_str() << " " << arg << "\n"
- << "kwsys process state : "
- << runCoverageSrc.GetProcessState());
+ if (!runCoverageSrc.StartProcess()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Could not run : " << program << " " << arg << "\n"
+ << "kwsys process state : "
+ << runCoverageSrc.GetProcessState());
return 0;
- }
+ }
// since we set the output file names wait for it to end
runCoverageSrc.WaitForExit();
outputFile = stdoutFile;
return 1;
}
-//----------------------------------------------------------------------
int cmCTestCoverageHandler::RunBullseyeSourceSummary(
cmCTestCoverageHandlerContainer* cont)
{
// Run the covsrc command and create a temp outputfile
std::string outputFile;
- if(!this->RunBullseyeCommand(cont, "covsrc", "-c", outputFile))
- {
+ if (!this->RunBullseyeCommand(cont, "covsrc", "-c", outputFile)) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "error running covsrc:\n");
return 0;
- }
+ }
std::ostream& tmpLog = *cont->OFS;
// copen the Coverage.xml file in the Testing directory
cmGeneratedFileStream covSumFile;
- if(!this->StartResultingXML(cmCTest::PartCoverage, "Coverage", covSumFile))
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot open coverage summary file." << std::endl);
+ cmXMLWriter xml(covSumFile);
+ if (!this->StartResultingXML(cmCTest::PartCoverage, "Coverage",
+ covSumFile)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open coverage summary file."
+ << std::endl);
return 0;
- }
- this->CTest->StartXML(covSumFile, this->AppendXML);
+ }
+ this->CTest->StartXML(xml, this->AppendXML);
double elapsed_time_start = cmSystemTools::GetTime();
std::string coverage_start_time = this->CTest->CurrentTime();
- covSumFile << "<Coverage>" << std::endl
- << "\t<StartDateTime>"
- << coverage_start_time << "</StartDateTime>"
- << std::endl
- << "\t<StartTime>"
- << static_cast<unsigned int>(cmSystemTools::GetTime())
- << "</StartTime>"
- << std::endl;
+ xml.StartElement("Coverage");
+ xml.Element("StartDateTime", coverage_start_time);
+ xml.Element("StartTime",
+ static_cast<unsigned int>(cmSystemTools::GetTime()));
std::string stdline;
std::string errline;
// expected output:
@@ -1703,66 +1981,53 @@ int cmCTestCoverageHandler::RunBullseyeSourceSummary(
double total_tested = 0;
double total_untested = 0;
double total_functions = 0;
- double percent_coverage =0;
- double number_files = 0;
+ double percent_coverage = 0;
+ double number_files = 0;
std::vector<std::string> coveredFiles;
std::vector<std::string> coveredFilesFullPath;
// Read and parse the summary output file
- std::ifstream fin(outputFile.c_str());
- if(!fin)
- {
+ cmsys::ifstream fin(outputFile.c_str());
+ if (!fin) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot open coverage summary file: " <<
- outputFile.c_str() << std::endl);
+ "Cannot open coverage summary file: " << outputFile
+ << std::endl);
return 0;
- }
- std::set<cmStdString> coveredFileNames;
- while(cmSystemTools::GetLineFromStream(fin, stdline))
- {
+ }
+ std::set<std::string> coveredFileNames;
+ while (cmSystemTools::GetLineFromStream(fin, stdline)) {
// if we have a line of output from stdout
- if(stdline.size())
- {
+ if (!stdline.empty()) {
// parse the comma separated output
- this->ParseBullsEyeCovsrcLine(stdline,
- sourceFile,
- functionsCalled,
- totalFunctions,
- percentFunction,
- branchCovered,
- totalBranches,
- percentBranch);
+ this->ParseBullsEyeCovsrcLine(
+ stdline, sourceFile, functionsCalled, totalFunctions, percentFunction,
+ branchCovered, totalBranches, percentBranch);
// The first line is the header
- if(sourceFile == "Source" || sourceFile == "Total")
- {
+ if (sourceFile == "Source" || sourceFile == "Total") {
continue;
- }
+ }
std::string file = sourceFile;
coveredFileNames.insert(file);
- if(!cmSystemTools::FileIsFullPath(sourceFile.c_str()))
- {
+ if (!cmSystemTools::FileIsFullPath(sourceFile.c_str())) {
// file will be relative to the binary dir
file = cont->BinaryDir;
file += "/";
file += sourceFile;
- }
- file = cmSystemTools::CollapseFullPath(file.c_str());
- bool shouldIDoCoverage
- = this->ShouldIDoCoverage(file.c_str(),
- cont->SourceDir.c_str(),
- cont->BinaryDir.c_str());
- if ( !shouldIDoCoverage )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- ".NoDartCoverage found, so skip coverage check for: "
- << file.c_str()
- << std::endl);
+ }
+ file = cmSystemTools::CollapseFullPath(file);
+ bool shouldIDoCoverage = this->ShouldIDoCoverage(
+ file.c_str(), cont->SourceDir.c_str(), cont->BinaryDir.c_str());
+ if (!shouldIDoCoverage) {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ ".NoDartCoverage found, so skip coverage check for: " << file
+ << std::endl,
+ this->Quiet);
continue;
- }
+ }
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Doing coverage for: "
- << file.c_str()
- << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Doing coverage for: " << file << std::endl,
+ this->Quiet);
coveredFiles.push_back(sourceFile);
coveredFilesFullPath.push_back(file);
@@ -1772,116 +2037,89 @@ int cmCTestCoverageHandler::RunBullseyeSourceSummary(
total_tested += functionsCalled;
total_untested += (totalFunctions - functionsCalled);
- std::string fileName = cmSystemTools::GetFilenameName(file.c_str());
+ std::string fileName = cmSystemTools::GetFilenameName(file);
std::string shortFileName =
this->CTest->GetShortPathToFile(file.c_str());
float cper = static_cast<float>(percentBranch + percentFunction);
- if(totalBranches > 0)
- {
+ if (totalBranches > 0) {
cper /= 2.0f;
- }
- percent_coverage += cper;
+ }
+ percent_coverage += static_cast<double>(cper);
float cmet = static_cast<float>(percentFunction + percentBranch);
- if(totalBranches > 0)
- {
+ if (totalBranches > 0) {
cmet /= 2.0f;
- }
+ }
cmet /= 100.0f;
- tmpLog << stdline.c_str() << "\n";
+ tmpLog << stdline << "\n";
tmpLog << fileName << "\n";
- tmpLog << "functionsCalled: " << functionsCalled/100 << "\n";
- tmpLog << "totalFunctions: " << totalFunctions/100 << "\n";
+ tmpLog << "functionsCalled: " << functionsCalled / 100 << "\n";
+ tmpLog << "totalFunctions: " << totalFunctions / 100 << "\n";
tmpLog << "percentFunction: " << percentFunction << "\n";
tmpLog << "branchCovered: " << branchCovered << "\n";
tmpLog << "totalBranches: " << totalBranches << "\n";
tmpLog << "percentBranch: " << percentBranch << "\n";
tmpLog << "percentCoverage: " << percent_coverage << "\n";
tmpLog << "coverage metric: " << cmet << "\n";
- covSumFile << "\t<File Name=\"" << cmXMLSafe(sourceFile)
- << "\" FullPath=\"" << cmXMLSafe(shortFileName)
- << "\" Covered=\"" << (cmet>0?"true":"false") << "\">\n"
- << "\t\t<BranchesTested>"
- << branchCovered
- << "</BranchesTested>\n"
- << "\t\t<BranchesUnTested>"
- << totalBranches - branchCovered
- << "</BranchesUnTested>\n"
- << "\t\t<FunctionsTested>"
- << functionsCalled
- << "</FunctionsTested>\n"
- << "\t\t<FunctionsUnTested>"
- << totalFunctions - functionsCalled
- << "</FunctionsUnTested>\n"
- // Hack for conversion of function to loc assume a function
- // has 100 lines of code
- << "\t\t<LOCTested>" << functionsCalled *100
- << "</LOCTested>\n"
- << "\t\t<LOCUnTested>"
- << (totalFunctions - functionsCalled)*100
- << "</LOCUnTested>\n"
- << "\t\t<PercentCoverage>";
- covSumFile.setf(std::ios::fixed, std::ios::floatfield);
- covSumFile.precision(2);
- covSumFile << (cper) << "</PercentCoverage>\n"
- << "\t\t<CoverageMetric>";
- covSumFile.setf(std::ios::fixed, std::ios::floatfield);
- covSumFile.precision(2);
- covSumFile << (cmet) << "</CoverageMetric>\n";
- this->WriteXMLLabels(covSumFile, shortFileName);
- covSumFile << "\t</File>" << std::endl;
- }
- }
+ xml.StartElement("File");
+ xml.Attribute("Name", sourceFile);
+ xml.Attribute("FullPath", shortFileName);
+ xml.Attribute("Covered", cmet > 0 ? "true" : "false");
+ xml.Element("BranchesTested", branchCovered);
+ xml.Element("BranchesUnTested", totalBranches - branchCovered);
+ xml.Element("FunctionsTested", functionsCalled);
+ xml.Element("FunctionsUnTested", totalFunctions - functionsCalled);
+ // Hack for conversion of function to loc assume a function
+ // has 100 lines of code
+ xml.Element("LOCTested", functionsCalled * 100);
+ xml.Element("LOCUnTested", (totalFunctions - functionsCalled) * 100);
+ xml.Element("PercentCoverage", cper);
+ xml.Element("CoverageMetric", cmet);
+ this->WriteXMLLabels(xml, shortFileName);
+ xml.EndElement(); // File
+ }
+ }
std::string end_time = this->CTest->CurrentTime();
- covSumFile << "\t<LOCTested>" << total_tested << "</LOCTested>\n"
- << "\t<LOCUntested>" << total_untested << "</LOCUntested>\n"
- << "\t<LOC>" << total_functions << "</LOC>\n"
- << "\t<PercentCoverage>";
- covSumFile.setf(std::ios::fixed, std::ios::floatfield);
- covSumFile.precision(2);
- covSumFile
- << SAFEDIV(percent_coverage,number_files)<< "</PercentCoverage>\n"
- << "\t<EndDateTime>" << end_time << "</EndDateTime>\n"
- << "\t<EndTime>" << static_cast<unsigned int>(cmSystemTools::GetTime())
- << "</EndTime>\n";
- covSumFile
- << "<ElapsedMinutes>" <<
- static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0
- << "</ElapsedMinutes>"
- << "</Coverage>" << std::endl;
- this->CTest->EndXML(covSumFile);
+ xml.Element("LOCTested", total_tested);
+ xml.Element("LOCUntested", total_untested);
+ xml.Element("LOC", total_functions);
+ xml.Element("PercentCoverage", SAFEDIV(percent_coverage, number_files));
+ xml.Element("EndDateTime", end_time);
+ xml.Element("EndTime", static_cast<unsigned int>(cmSystemTools::GetTime()));
+ xml.Element(
+ "ElapsedMinutes",
+ static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start) / 6) /
+ 10.0);
+ xml.EndElement(); // Coverage
+ this->CTest->EndXML(xml);
// Now create the coverage information for each file
- return this->RunBullseyeCoverageBranch(cont,
- coveredFileNames,
- coveredFiles,
+ return this->RunBullseyeCoverageBranch(cont, coveredFileNames, coveredFiles,
coveredFilesFullPath);
}
-//----------------------------------------------------------------------
int cmCTestCoverageHandler::HandleBullseyeCoverage(
cmCTestCoverageHandlerContainer* cont)
{
- const char* covfile = cmSystemTools::GetEnv("COVFILE");
- if(!covfile || strlen(covfile) == 0)
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " COVFILE environment variable not found, not running "
- " bullseye\n");
+ std::string covfile;
+ if (!cmSystemTools::GetEnv("COVFILE", covfile) || covfile.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " COVFILE environment variable not found, not running "
+ " bullseye\n",
+ this->Quiet);
return 0;
- }
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " run covsrc with COVFILE=["
- << covfile
- << "]" << std::endl);
- if(!this->RunBullseyeSourceSummary(cont))
- {
+ }
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " run covsrc with COVFILE=[" << covfile << "]" << std::endl, this->Quiet);
+ if (!this->RunBullseyeSourceSummary(cont)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Error running bullseye summary.\n");
return 0;
- }
- cmCTestLog(this->CTest, DEBUG, "HandleBullseyeCoverage return 1 "
- << std::endl);
+ }
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "HandleBullseyeCoverage return 1 " << std::endl,
+ this->Quiet);
return 1;
}
@@ -1892,141 +2130,113 @@ bool cmCTestCoverageHandler::GetNextInt(std::string const& inputLine,
std::string::size_type start = pos;
pos = inputLine.find(',', start);
value = atoi(inputLine.substr(start, pos).c_str());
- if(pos == inputLine.npos)
- {
+ if (pos == std::string::npos) {
return true;
- }
+ }
pos++;
return true;
}
bool cmCTestCoverageHandler::ParseBullsEyeCovsrcLine(
- std::string const& inputLine,
- std::string& sourceFile,
- int& functionsCalled,
- int& totalFunctions,
- int& percentFunction,
- int& branchCovered,
- int& totalBranches,
- int& percentBranch)
+ std::string const& inputLine, std::string& sourceFile, int& functionsCalled,
+ int& totalFunctions, int& percentFunction, int& branchCovered,
+ int& totalBranches, int& percentBranch)
{
// find the first comma
std::string::size_type pos = inputLine.find(',');
- if(pos == inputLine.npos)
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Error parsing string : "
- << inputLine.c_str() << "\n");
+ if (pos == std::string::npos) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error parsing string : " << inputLine << "\n");
return false;
- }
+ }
// the source file has "" around it so extract out the file name
- sourceFile = inputLine.substr(1,pos-2);
+ sourceFile = inputLine.substr(1, pos - 2);
pos++;
- if(!this->GetNextInt(inputLine, pos, functionsCalled))
- {
+ if (!this->GetNextInt(inputLine, pos, functionsCalled)) {
return false;
- }
- if(!this->GetNextInt(inputLine, pos, totalFunctions))
- {
+ }
+ if (!this->GetNextInt(inputLine, pos, totalFunctions)) {
return false;
- }
- if(!this->GetNextInt(inputLine, pos, percentFunction))
- {
+ }
+ if (!this->GetNextInt(inputLine, pos, percentFunction)) {
return false;
- }
- if(!this->GetNextInt(inputLine, pos, branchCovered))
- {
+ }
+ if (!this->GetNextInt(inputLine, pos, branchCovered)) {
return false;
- }
- if(!this->GetNextInt(inputLine, pos, totalBranches))
- {
+ }
+ if (!this->GetNextInt(inputLine, pos, totalBranches)) {
return false;
- }
- if(!this->GetNextInt(inputLine, pos, percentBranch))
- {
+ }
+ if (!this->GetNextInt(inputLine, pos, percentBranch)) {
return false;
- }
+ }
// should be at the end now
- if(pos != inputLine.npos)
- {
+ if (pos != std::string::npos) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Error parsing input : "
- << inputLine.c_str() << " last pos not npos = " << pos <<
- "\n");
- }
+ << inputLine << " last pos not npos = " << pos << "\n");
+ }
return true;
}
-//----------------------------------------------------------------------
int cmCTestCoverageHandler::GetLabelId(std::string const& label)
{
LabelIdMapType::iterator i = this->LabelIdMap.find(label);
- if(i == this->LabelIdMap.end())
- {
+ if (i == this->LabelIdMap.end()) {
int n = int(this->Labels.size());
this->Labels.push_back(label);
LabelIdMapType::value_type entry(label, n);
i = this->LabelIdMap.insert(entry).first;
- }
+ }
return i->second;
}
-//----------------------------------------------------------------------
void cmCTestCoverageHandler::LoadLabels()
{
std::string fileList = this->CTest->GetBinaryDir();
fileList += cmake::GetCMakeFilesDirectory();
fileList += "/TargetDirectories.txt";
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " target directory list [" << fileList << "]\n");
- std::ifstream finList(fileList.c_str());
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " target directory list [" << fileList << "]\n",
+ this->Quiet);
+ cmsys::ifstream finList(fileList.c_str());
std::string line;
- while(cmSystemTools::GetLineFromStream(finList, line))
- {
+ while (cmSystemTools::GetLineFromStream(finList, line)) {
this->LoadLabels(line.c_str());
- }
+ }
}
-//----------------------------------------------------------------------
void cmCTestCoverageHandler::LoadLabels(const char* dir)
{
LabelSet& dirLabels = this->TargetDirs[dir];
std::string fname = dir;
fname += "/Labels.txt";
- std::ifstream fin(fname.c_str());
- if(!fin)
- {
+ cmsys::ifstream fin(fname.c_str());
+ if (!fin) {
return;
- }
+ }
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " loading labels from [" << fname << "]\n");
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " loading labels from [" << fname << "]\n", this->Quiet);
bool inTarget = true;
std::string source;
std::string line;
std::vector<int> targetLabels;
- while(cmSystemTools::GetLineFromStream(fin, line))
- {
- if(line.empty() || line[0] == '#')
- {
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (line.empty() || line[0] == '#') {
// Ignore blank and comment lines.
continue;
- }
- else if(line[0] == ' ')
- {
+ }
+ if (line[0] == ' ') {
// Label lines appear indented by one space.
std::string label = line.substr(1);
int id = this->GetLabelId(label);
dirLabels.insert(id);
- if(inTarget)
- {
+ if (inTarget) {
targetLabels.push_back(id);
- }
- else
- {
+ } else {
this->SourceLabels[source].insert(id);
- }
}
- else
- {
+ } else {
// Non-indented lines specify a source file name. The first one
// is the end of the target-wide labels.
inTarget = false;
@@ -2035,117 +2245,96 @@ void cmCTestCoverageHandler::LoadLabels(const char* dir)
// Label the source with the target labels.
LabelSet& labelSet = this->SourceLabels[source];
- for(std::vector<int>::const_iterator li = targetLabels.begin();
- li != targetLabels.end(); ++li)
- {
- labelSet.insert(*li);
- }
- }
+ labelSet.insert(targetLabels.begin(), targetLabels.end());
}
+ }
}
-//----------------------------------------------------------------------
-void cmCTestCoverageHandler::WriteXMLLabels(std::ofstream& os,
+void cmCTestCoverageHandler::WriteXMLLabels(cmXMLWriter& xml,
std::string const& source)
{
LabelMapType::const_iterator li = this->SourceLabels.find(source);
- if(li != this->SourceLabels.end() && !li->second.empty())
- {
- os << "\t\t<Labels>\n";
- for(LabelSet::const_iterator lsi = li->second.begin();
- lsi != li->second.end(); ++lsi)
- {
- os << "\t\t\t<Label>" << cmXMLSafe(this->Labels[*lsi]) << "</Label>\n";
- }
- os << "\t\t</Labels>\n";
- }
+ if (li != this->SourceLabels.end() && !li->second.empty()) {
+ xml.StartElement("Labels");
+ for (LabelSet::const_iterator lsi = li->second.begin();
+ lsi != li->second.end(); ++lsi) {
+ xml.Element("Label", this->Labels[*lsi]);
+ }
+ xml.EndElement(); // Labels
+ }
}
-//----------------------------------------------------------------------------
-void
-cmCTestCoverageHandler::SetLabelFilter(std::set<cmStdString> const& labels)
+void cmCTestCoverageHandler::SetLabelFilter(
+ std::set<std::string> const& labels)
{
this->LabelFilter.clear();
- for(std::set<cmStdString>::const_iterator li = labels.begin();
- li != labels.end(); ++li)
- {
+ for (std::set<std::string>::const_iterator li = labels.begin();
+ li != labels.end(); ++li) {
this->LabelFilter.insert(this->GetLabelId(*li));
- }
+ }
}
-//----------------------------------------------------------------------
bool cmCTestCoverageHandler::IntersectsFilter(LabelSet const& labels)
{
// If there is no label filter then nothing is filtered out.
- if(this->LabelFilter.empty())
- {
+ if (this->LabelFilter.empty()) {
return true;
- }
+ }
std::vector<int> ids;
- cmsys_stl::set_intersection
- (labels.begin(), labels.end(),
- this->LabelFilter.begin(), this->LabelFilter.end(),
- cmsys_stl::back_inserter(ids));
+ std::set_intersection(labels.begin(), labels.end(),
+ this->LabelFilter.begin(), this->LabelFilter.end(),
+ std::back_inserter(ids));
return !ids.empty();
}
-//----------------------------------------------------------------------
bool cmCTestCoverageHandler::IsFilteredOut(std::string const& source)
{
// If there is no label filter then nothing is filtered out.
- if(this->LabelFilter.empty())
- {
+ if (this->LabelFilter.empty()) {
return false;
- }
+ }
// The source is filtered out if it does not have any labels in
// common with the filter set.
std::string shortSrc = this->CTest->GetShortPathToFile(source.c_str());
LabelMapType::const_iterator li = this->SourceLabels.find(shortSrc);
- if(li != this->SourceLabels.end())
- {
+ if (li != this->SourceLabels.end()) {
return !this->IntersectsFilter(li->second);
- }
+ }
return true;
}
-//----------------------------------------------------------------------
std::set<std::string> cmCTestCoverageHandler::FindUncoveredFiles(
cmCTestCoverageHandlerContainer* cont)
{
std::set<std::string> extraMatches;
- for(std::vector<cmStdString>::iterator i = this->ExtraCoverageGlobs.begin();
- i != this->ExtraCoverageGlobs.end(); ++i)
- {
+ for (std::vector<std::string>::iterator i = this->ExtraCoverageGlobs.begin();
+ i != this->ExtraCoverageGlobs.end(); ++i) {
cmsys::Glob gl;
gl.RecurseOn();
gl.RecurseThroughSymlinksOff();
std::string glob = cont->SourceDir + "/" + *i;
gl.FindFiles(glob);
std::vector<std::string> files = gl.GetFiles();
- for(std::vector<std::string>::iterator f = files.begin();
- f != files.end(); ++f)
- {
- if(this->ShouldIDoCoverage(f->c_str(),
- cont->SourceDir.c_str(), cont->BinaryDir.c_str()))
- {
- extraMatches.insert(this->CTest->GetShortPathToFile(
- f->c_str()));
- }
+ for (std::vector<std::string>::iterator f = files.begin();
+ f != files.end(); ++f) {
+ if (this->ShouldIDoCoverage(f->c_str(), cont->SourceDir.c_str(),
+ cont->BinaryDir.c_str())) {
+ extraMatches.insert(this->CTest->GetShortPathToFile(f->c_str()));
}
}
+ }
- if(extraMatches.size())
- {
- for(cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator i =
- cont->TotalCoverage.begin(); i != cont->TotalCoverage.end(); ++i)
- {
- std::string shortPath = this->CTest->GetShortPathToFile(
- i->first.c_str());
+ if (!extraMatches.empty()) {
+ for (cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator i =
+ cont->TotalCoverage.begin();
+ i != cont->TotalCoverage.end(); ++i) {
+ std::string shortPath =
+ this->CTest->GetShortPathToFile(i->first.c_str());
extraMatches.erase(shortPath);
- }
}
+ }
return extraMatches;
}
diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h
index 92b0b2285..933f60660 100644
--- a/Source/CTest/cmCTestCoverageHandler.h
+++ b/Source/CTest/cmCTestCoverageHandler.h
@@ -1,25 +1,23 @@
-/*============================================================================
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestCoverageHandler_h
#define cmCTestCoverageHandler_h
+#include "cmConfigure.h"
#include "cmCTestGenericHandler.h"
-#include "cmListFileCache.h"
-#include <cmsys/RegularExpression.hxx>
+#include "cmsys/RegularExpression.hxx"
+#include <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
class cmGeneratedFileStream;
+class cmMakefile;
+class cmXMLWriter;
+
class cmCTestCoverageHandlerContainer
{
public:
@@ -30,73 +28,87 @@ public:
typedef std::map<std::string, SingleFileCoverageVector> TotalCoverageMap;
TotalCoverageMap TotalCoverage;
std::ostream* OFS;
+ bool Quiet;
};
/** \class cmCTestCoverageHandler
- * \brief A class that handles coverage computaiton for ctest
+ * \brief A class that handles coverage computation for ctest
*
*/
class cmCTestCoverageHandler : public cmCTestGenericHandler
{
public:
- cmTypeMacro(cmCTestCoverageHandler, cmCTestGenericHandler);
+ typedef cmCTestGenericHandler Superclass;
/*
* The main entry point for this class
*/
- int ProcessHandler();
+ int ProcessHandler() CM_OVERRIDE;
cmCTestCoverageHandler();
- virtual void Initialize();
+ void Initialize() CM_OVERRIDE;
/**
* This method is called when reading CTest custom file
*/
- void PopulateCustomVectors(cmMakefile *mf);
+ void PopulateCustomVectors(cmMakefile* mf) CM_OVERRIDE;
/** Report coverage only for sources with these labels. */
- void SetLabelFilter(std::set<cmStdString> const& labels);
+ void SetLabelFilter(std::set<std::string> const& labels);
private:
bool ShouldIDoCoverage(const char* file, const char* srcDir,
- const char* binDir);
+ const char* binDir);
void CleanCoverageLogFiles(std::ostream& log);
bool StartCoverageLogFile(cmGeneratedFileStream& ostr, int logFileCount);
void EndCoverageLogFile(cmGeneratedFileStream& ostr, int logFileCount);
+ void StartCoverageLogXML(cmXMLWriter& xml);
+ void EndCoverageLogXML(cmXMLWriter& xml);
+
//! Handle coverage using GCC's GCov
int HandleGCovCoverage(cmCTestCoverageHandlerContainer* cont);
void FindGCovFiles(std::vector<std::string>& files);
+ //! Handle coverage using Intel's LCov
+ int HandleLCovCoverage(cmCTestCoverageHandlerContainer* cont);
+ bool FindLCovFiles(std::vector<std::string>& files);
+
//! Handle coverage using xdebug php coverage
int HandlePHPCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage for Python with coverage.py
+ int HandleCoberturaCoverage(cmCTestCoverageHandlerContainer* cont);
+
//! Handle coverage for mumps
int HandleMumpsCoverage(cmCTestCoverageHandlerContainer* cont);
+ //! Handle coverage for Jacoco
+ int HandleJacocoCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage for Delphi (Pascal)
+ int HandleDelphiCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ //! Handle coverage for Jacoco
+ int HandleBlanketJSCoverage(cmCTestCoverageHandlerContainer* cont);
+
//! Handle coverage using Bullseye
int HandleBullseyeCoverage(cmCTestCoverageHandlerContainer* cont);
int RunBullseyeSourceSummary(cmCTestCoverageHandlerContainer* cont);
int RunBullseyeCoverageBranch(cmCTestCoverageHandlerContainer* cont,
- std::set<cmStdString>& coveredFileNames,
+ std::set<std::string>& coveredFileNames,
std::vector<std::string>& files,
std::vector<std::string>& filesFullPath);
- int RunBullseyeCommand(
- cmCTestCoverageHandlerContainer* cont,
- const char* cmd,
- const char* arg,
- std::string& outputFile);
- bool ParseBullsEyeCovsrcLine(
- std::string const& inputLine,
- std::string& sourceFile,
- int& functionsCalled,
- int& totalFunctions,
- int& percentFunction,
- int& branchCovered,
- int& totalBranches,
- int& percentBranch);
- bool GetNextInt(std::string const& inputLine,
- std::string::size_type& pos,
+ int RunBullseyeCommand(cmCTestCoverageHandlerContainer* cont,
+ const char* cmd, const char* arg,
+ std::string& outputFile);
+ bool ParseBullsEyeCovsrcLine(std::string const& inputLine,
+ std::string& sourceFile, int& functionsCalled,
+ int& totalFunctions, int& percentFunction,
+ int& branchCovered, int& totalBranches,
+ int& percentBranch);
+ bool GetNextInt(std::string const& inputLine, std::string::size_type& pos,
int& value);
//! Handle Python coverage using Python's Trace.py
int HandleTracePyCoverage(cmCTestCoverageHandlerContainer* cont);
@@ -104,23 +116,24 @@ private:
// Find the source file based on the source and build tree. This is used for
// Trace.py mode, since that one does not tell us where the source file is.
std::string FindFile(cmCTestCoverageHandlerContainer* cont,
- std::string fileName);
+ std::string const& fileName);
std::set<std::string> FindUncoveredFiles(
cmCTestCoverageHandlerContainer* cont);
- std::vector<cmStdString> CustomCoverageExclude;
+ std::vector<std::string> CustomCoverageExclude;
std::vector<cmsys::RegularExpression> CustomCoverageExcludeRegex;
- std::vector<cmStdString> ExtraCoverageGlobs;
-
+ std::vector<std::string> ExtraCoverageGlobs;
// Map from source file to label ids.
- class LabelSet: public std::set<int> {};
- typedef std::map<cmStdString, LabelSet> LabelMapType;
+ class LabelSet : public std::set<int>
+ {
+ };
+ typedef std::map<std::string, LabelSet> LabelMapType;
LabelMapType SourceLabels;
LabelMapType TargetDirs;
// Map from label name to label id.
- typedef std::map<cmStdString, int> LabelIdMapType;
+ typedef std::map<std::string, int> LabelIdMapType;
LabelIdMapType LabelIdMap;
std::vector<std::string> Labels;
int GetLabelId(std::string const& label);
@@ -128,7 +141,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(cmXMLWriter& xml, std::string const& source);
// Label-based filtering.
std::set<int> LabelFilter;
diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx
new file mode 100644
index 000000000..b80ea5ade
--- /dev/null
+++ b/Source/CTest/cmCTestCurl.cxx
@@ -0,0 +1,276 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestCurl.h"
+
+#include "cmCTest.h"
+#include "cmSystemTools.h"
+
+#include "cmConfigure.h"
+#include <ostream>
+#include <stdio.h>
+
+cmCTestCurl::cmCTestCurl(cmCTest* ctest)
+{
+ this->CTest = ctest;
+ this->SetProxyType();
+ this->UseHttp10 = false;
+ // In windows, this will init the winsock stuff
+ ::curl_global_init(CURL_GLOBAL_ALL);
+ // default is to verify https
+ this->VerifyPeerOff = false;
+ this->VerifyHostOff = false;
+ this->Quiet = false;
+ this->TimeOutSeconds = 0;
+ this->Curl = curl_easy_init();
+}
+
+cmCTestCurl::~cmCTestCurl()
+{
+ ::curl_easy_cleanup(this->Curl);
+ ::curl_global_cleanup();
+}
+
+std::string cmCTestCurl::Escape(std::string const& source)
+{
+ char* data1 = curl_easy_escape(this->Curl, source.c_str(), 0);
+ std::string ret = data1;
+ curl_free(data1);
+ return ret;
+}
+
+namespace {
+size_t curlWriteMemoryCallback(void* ptr, size_t size, size_t nmemb,
+ void* data)
+{
+ int realsize = (int)(size * nmemb);
+
+ std::vector<char>* vec = static_cast<std::vector<char>*>(data);
+ const char* chPtr = static_cast<char*>(ptr);
+ vec->insert(vec->end(), chPtr, chPtr + realsize);
+ return realsize;
+}
+
+size_t curlDebugCallback(CURL* /*unused*/, curl_infotype /*unused*/,
+ char* chPtr, size_t size, void* data)
+{
+ std::vector<char>* vec = static_cast<std::vector<char>*>(data);
+ vec->insert(vec->end(), chPtr, chPtr + size);
+
+ return size;
+}
+}
+
+void cmCTestCurl::SetCurlOptions(std::vector<std::string> const& args)
+{
+ for (std::vector<std::string>::const_iterator i = args.begin();
+ i != args.end(); ++i) {
+ if (*i == "CURLOPT_SSL_VERIFYPEER_OFF") {
+ this->VerifyPeerOff = true;
+ }
+ if (*i == "CURLOPT_SSL_VERIFYHOST_OFF") {
+ this->VerifyHostOff = true;
+ }
+ }
+}
+
+bool cmCTestCurl::InitCurl()
+{
+ if (!this->Curl) {
+ return false;
+ }
+ if (this->VerifyPeerOff) {
+ curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYPEER, 0);
+ }
+ if (this->VerifyHostOff) {
+ curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYHOST, 0);
+ }
+ if (!this->HTTPProxy.empty()) {
+ curl_easy_setopt(this->Curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
+ curl_easy_setopt(this->Curl, CURLOPT_PROXYTYPE, this->HTTPProxyType);
+ if (!this->HTTPProxyAuth.empty()) {
+ curl_easy_setopt(this->Curl, CURLOPT_PROXYUSERPWD,
+ this->HTTPProxyAuth.c_str());
+ }
+ }
+ if (this->UseHttp10) {
+ curl_easy_setopt(this->Curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ }
+ // enable HTTP ERROR parsing
+ curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+
+ // if there is little to no activity for too long stop submitting
+ if (this->TimeOutSeconds) {
+ curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_LIMIT, 1);
+ curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_TIME, this->TimeOutSeconds);
+ }
+
+ return true;
+}
+
+bool cmCTestCurl::UploadFile(std::string const& local_file,
+ std::string const& url, std::string const& fields,
+ std::string& response)
+{
+ response = "";
+ if (!this->InitCurl()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
+ return false;
+ }
+ /* enable uploading */
+ curl_easy_setopt(this->Curl, CURLOPT_UPLOAD, 1);
+
+ /* HTTP PUT please */
+ ::curl_easy_setopt(this->Curl, CURLOPT_PUT, 1);
+ ::curl_easy_setopt(this->Curl, CURLOPT_VERBOSE, 1);
+
+ FILE* ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
+ if (!ftpfile) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Could not open file for upload: " << local_file << "\n");
+ return false;
+ }
+ // set the url
+ std::string upload_url = url;
+ upload_url += "?";
+ upload_url += fields;
+ ::curl_easy_setopt(this->Curl, CURLOPT_URL, upload_url.c_str());
+ // now specify which file to upload
+ ::curl_easy_setopt(this->Curl, CURLOPT_INFILE, ftpfile);
+ unsigned long filelen = cmSystemTools::FileLength(local_file);
+ // and give the size of the upload (optional)
+ ::curl_easy_setopt(this->Curl, CURLOPT_INFILESIZE,
+ static_cast<long>(filelen));
+ ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,
+ curlWriteMemoryCallback);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION, curlDebugCallback);
+ // Set Content-Type to satisfy fussy modsecurity rules.
+ struct curl_slist* headers =
+ ::curl_slist_append(CM_NULLPTR, "Content-Type: text/xml");
+ // Add any additional headers that the user specified.
+ for (std::vector<std::string>::const_iterator h = this->HttpHeaders.begin();
+ h != this->HttpHeaders.end(); ++h) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Add HTTP Header: \"" << *h << "\"" << std::endl,
+ this->Quiet);
+ headers = ::curl_slist_append(headers, h->c_str());
+ }
+ ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, headers);
+ std::vector<char> responseData;
+ std::vector<char> debugData;
+ ::curl_easy_setopt(this->Curl, CURLOPT_FILE, (void*)&responseData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, (void*)&debugData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+ // Now run off and do what you've been told!
+ ::curl_easy_perform(this->Curl);
+ ::fclose(ftpfile);
+ ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, NULL);
+ ::curl_slist_free_all(headers);
+
+ if (!responseData.empty()) {
+ response = std::string(responseData.begin(), responseData.end());
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Curl response: [" << response << "]\n", this->Quiet);
+ }
+ std::string curlDebug;
+ if (!debugData.empty()) {
+ curlDebug = std::string(debugData.begin(), debugData.end());
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Curl debug: [" << curlDebug << "]\n", this->Quiet);
+ }
+ if (response.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "No response from server.\n"
+ << curlDebug);
+ return false;
+ }
+ return true;
+}
+
+bool cmCTestCurl::HttpRequest(std::string const& url,
+ std::string const& fields, std::string& response)
+{
+ response = "";
+ cmCTestOptionalLog(this->CTest, DEBUG, "HttpRequest\n"
+ << "url: " << url << "\n"
+ << "fields " << fields << "\n",
+ this->Quiet);
+ if (!this->InitCurl()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
+ return false;
+ }
+ curl_easy_setopt(this->Curl, CURLOPT_POST, 1);
+ curl_easy_setopt(this->Curl, CURLOPT_POSTFIELDS, fields.c_str());
+ ::curl_easy_setopt(this->Curl, CURLOPT_URL, url.c_str());
+ ::curl_easy_setopt(this->Curl, CURLOPT_FOLLOWLOCATION, 1);
+ // set response options
+ ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,
+ curlWriteMemoryCallback);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION, curlDebugCallback);
+ std::vector<char> responseData;
+ std::vector<char> debugData;
+ ::curl_easy_setopt(this->Curl, CURLOPT_FILE, (void*)&responseData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, (void*)&debugData);
+ ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
+
+ // Add headers if any were specified.
+ struct curl_slist* headers = CM_NULLPTR;
+ if (!this->HttpHeaders.empty()) {
+ for (std::vector<std::string>::const_iterator h =
+ this->HttpHeaders.begin();
+ h != this->HttpHeaders.end(); ++h) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Add HTTP Header: \"" << *h << "\"" << std::endl,
+ this->Quiet);
+ headers = ::curl_slist_append(headers, h->c_str());
+ }
+ }
+
+ ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, headers);
+ CURLcode res = ::curl_easy_perform(this->Curl);
+ ::curl_slist_free_all(headers);
+
+ if (!responseData.empty()) {
+ response = std::string(responseData.begin(), responseData.end());
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Curl response: [" << response << "]\n", this->Quiet);
+ }
+ if (!debugData.empty()) {
+ std::string curlDebug = std::string(debugData.begin(), debugData.end());
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Curl debug: [" << curlDebug << "]\n", this->Quiet);
+ }
+ cmCTestOptionalLog(this->CTest, DEBUG, "Curl res: " << res << "\n",
+ this->Quiet);
+ return (res == 0);
+}
+
+void cmCTestCurl::SetProxyType()
+{
+ this->HTTPProxy = "";
+ // this is the default
+ this->HTTPProxyType = CURLPROXY_HTTP;
+ this->HTTPProxyAuth = "";
+ if (cmSystemTools::GetEnv("HTTP_PROXY", this->HTTPProxy)) {
+ std::string port;
+ if (cmSystemTools::GetEnv("HTTP_PROXY_PORT", port)) {
+ this->HTTPProxy += ":";
+ this->HTTPProxy += port;
+ }
+ std::string type;
+ if (cmSystemTools::GetEnv("HTTP_PROXY_TYPE", type)) {
+ // HTTP/SOCKS4/SOCKS5
+ if (type == "HTTP") {
+ this->HTTPProxyType = CURLPROXY_HTTP;
+ } else if (type == "SOCKS4") {
+ this->HTTPProxyType = CURLPROXY_SOCKS4;
+ } else if (type == "SOCKS5") {
+ this->HTTPProxyType = CURLPROXY_SOCKS5;
+ }
+ }
+ cmSystemTools::GetEnv("HTTP_PROXY_USER", this->HTTPProxyAuth);
+ std::string passwd;
+ if (cmSystemTools::GetEnv("HTTP_PROXY_PASSWD", passwd)) {
+ this->HTTPProxyAuth += ":";
+ this->HTTPProxyAuth += passwd;
+ }
+ }
+}
diff --git a/Source/CTest/cmCTestCurl.h b/Source/CTest/cmCTestCurl.h
new file mode 100644
index 000000000..427a39232
--- /dev/null
+++ b/Source/CTest/cmCTestCurl.h
@@ -0,0 +1,53 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmCTestCurl_h
+#define cmCTestCurl_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cm_curl.h"
+#include <string>
+#include <vector>
+
+class cmCTest;
+
+class cmCTestCurl
+{
+public:
+ cmCTestCurl(cmCTest*);
+ ~cmCTestCurl();
+ bool UploadFile(std::string const& url, std::string const& file,
+ std::string const& fields, std::string& response);
+ bool HttpRequest(std::string const& url, std::string const& fields,
+ std::string& response);
+ // currently only supports CURLOPT_SSL_VERIFYPEER_OFF
+ // and CURLOPT_SSL_VERIFYHOST_OFF
+ void SetCurlOptions(std::vector<std::string> const& args);
+ void SetHttpHeaders(std::vector<std::string> const& v)
+ {
+ this->HttpHeaders = v;
+ }
+ void SetUseHttp10On() { this->UseHttp10 = true; }
+ void SetTimeOutSeconds(int s) { this->TimeOutSeconds = s; }
+ void SetQuiet(bool b) { this->Quiet = b; }
+ std::string Escape(std::string const& source);
+
+protected:
+ void SetProxyType();
+ bool InitCurl();
+
+private:
+ cmCTest* CTest;
+ CURL* Curl;
+ std::vector<std::string> HttpHeaders;
+ std::string HTTPProxyAuth;
+ std::string HTTPProxy;
+ curl_proxytype HTTPProxyType;
+ bool VerifyHostOff;
+ bool VerifyPeerOff;
+ bool UseHttp10;
+ bool Quiet;
+ int TimeOutSeconds;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
index abc33de68..f4531a1ee 100644
--- a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
+++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
@@ -1,36 +1,27 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestEmptyBinaryDirectoryCommand.h"
#include "cmCTestScriptHandler.h"
-bool cmCTestEmptyBinaryDirectoryCommand
-::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
+#include <sstream>
+
+class cmExecutionStatus;
+
+bool cmCTestEmptyBinaryDirectoryCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus& /*unused*/)
{
- if(args.size() != 1 )
- {
+ if (args.size() != 1) {
this->SetError("called with incorrect number of arguments");
return false;
- }
+ }
- if ( !cmCTestScriptHandler::EmptyBinaryDirectory(args[0].c_str()) )
- {
- cmOStringStream ostr;
- ostr << "problem removing the binary directory: " << args[0].c_str();
- this->SetError(ostr.str().c_str());
+ if (!cmCTestScriptHandler::EmptyBinaryDirectory(args[0].c_str())) {
+ std::ostringstream ostr;
+ ostr << "problem removing the binary directory: " << args[0];
+ this->SetError(ostr.str());
return false;
- }
+ }
return true;
}
-
-
diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h
index a763fe9e9..503ed234d 100644
--- a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h
+++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h
@@ -1,19 +1,18 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestEmptyBinaryDirectoryCommand_h
#define cmCTestEmptyBinaryDirectoryCommand_h
+#include "cmConfigure.h"
+
#include "cmCTestCommand.h"
+#include <string>
+#include <vector>
+
+class cmCommand;
+class cmExecutionStatus;
+
/** \class cmCTestEmptyBinaryDirectory
* \brief Run a ctest script
*
@@ -23,56 +22,26 @@
class cmCTestEmptyBinaryDirectoryCommand : public cmCTestCommand
{
public:
-
cmCTestEmptyBinaryDirectoryCommand() {}
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
- cmCTestEmptyBinaryDirectoryCommand* ni
- = new cmCTestEmptyBinaryDirectoryCommand;
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestEmptyBinaryDirectoryCommand* ni =
+ new cmCTestEmptyBinaryDirectoryCommand;
ni->CTest = this->CTest;
ni->CTestScriptHandler = this->CTestScriptHandler;
return ni;
- }
+ }
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
- virtual bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus &status);
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- 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);
-
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
};
-
#endif
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
index 5b3449181..230aedf3b 100644
--- a/Source/CTest/cmCTestGIT.cxx
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -1,74 +1,65 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestGIT.h"
+#include "cmsys/FStream.hxx"
+#include "cmsys/Process.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <vector>
+
+#include "cmAlgorithms.h"
#include "cmCTest.h"
+#include "cmCTestVC.h"
+#include "cmProcessOutput.h"
+#include "cmProcessTools.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>
-
-//----------------------------------------------------------------------------
static unsigned int cmCTestGITVersion(unsigned int epic, unsigned int major,
unsigned int minor, unsigned int fix)
{
// 1.6.5.0 maps to 10605000
- return fix + minor*1000 + major*100000 + epic*10000000;
+ return fix + minor * 1000 + major * 100000 + epic * 10000000;
}
-//----------------------------------------------------------------------------
-cmCTestGIT::cmCTestGIT(cmCTest* ct, std::ostream& log):
- cmCTestGlobalVC(ct, log)
+cmCTestGIT::cmCTestGIT(cmCTest* ct, std::ostream& log)
+ : cmCTestGlobalVC(ct, log)
{
this->PriorRev = this->Unknown;
this->CurrentGitVersion = 0;
}
-//----------------------------------------------------------------------------
cmCTestGIT::~cmCTestGIT()
{
}
-//----------------------------------------------------------------------------
-class cmCTestGIT::OneLineParser: public cmCTestVC::LineParser
+class cmCTestGIT::OneLineParser : public cmCTestVC::LineParser
{
public:
- OneLineParser(cmCTestGIT* git, const char* prefix,
- std::string& l): Line1(l)
- {
+ OneLineParser(cmCTestGIT* git, const char* prefix, std::string& l)
+ : Line1(l)
+ {
this->SetLog(&git->Log, prefix);
- }
+ }
+
private:
std::string& Line1;
- virtual bool ProcessLine()
- {
+ bool ProcessLine() CM_OVERRIDE
+ {
// Only the first line is of interest.
this->Line1 = this->Line;
return false;
- }
+ }
};
-//----------------------------------------------------------------------------
std::string cmCTestGIT::GetWorkingRevision()
{
// Run plumbing "git rev-list" to get work tree revision.
const char* git = this->CommandLineTool.c_str();
- const char* git_rev_list[] = {git, "rev-list", "-n", "1", "HEAD", "--", 0};
+ const char* git_rev_list[] = { git, "rev-list", "-n", "1",
+ "HEAD", "--", CM_NULLPTR };
std::string rev;
OneLineParser out(this, "rl-out> ", rev);
OutputLogger err(this->Log, "rl-err> ");
@@ -76,93 +67,88 @@ std::string cmCTestGIT::GetWorkingRevision()
return rev;
}
-//----------------------------------------------------------------------------
-void cmCTestGIT::NoteOldRevision()
+bool cmCTestGIT::NoteOldRevision()
{
this->OldRevision = this->GetWorkingRevision();
cmCTestLog(this->CTest, HANDLER_OUTPUT, " Old revision of repository is: "
- << this->OldRevision << "\n");
+ << this->OldRevision << "\n");
this->PriorRev.Rev = this->OldRevision;
+ return true;
}
-//----------------------------------------------------------------------------
-void cmCTestGIT::NoteNewRevision()
+bool cmCTestGIT::NoteNewRevision()
{
this->NewRevision = this->GetWorkingRevision();
cmCTestLog(this->CTest, HANDLER_OUTPUT, " New revision of repository is: "
- << this->NewRevision << "\n");
+ << this->NewRevision << "\n");
+ return true;
}
-//----------------------------------------------------------------------------
std::string cmCTestGIT::FindGitDir()
{
std::string git_dir;
// Run "git rev-parse --git-dir" to locate the real .git directory.
const char* git = this->CommandLineTool.c_str();
- char const* git_rev_parse[] = {git, "rev-parse", "--git-dir", 0};
+ char const* git_rev_parse[] = { git, "rev-parse", "--git-dir", CM_NULLPTR };
std::string git_dir_line;
OneLineParser rev_parse_out(this, "rev-parse-out> ", git_dir_line);
OutputLogger rev_parse_err(this->Log, "rev-parse-err> ");
- if(this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err))
- {
+ if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, CM_NULLPTR,
+ cmProcessOutput::UTF8)) {
git_dir = git_dir_line;
- }
- if(git_dir.empty())
- {
+ }
+ if (git_dir.empty()) {
git_dir = ".git";
- }
+ }
// Git reports a relative path only when the .git directory is in
// the current directory.
- if(git_dir[0] == '.')
- {
+ if (git_dir[0] == '.') {
git_dir = this->SourceDirectory + "/" + git_dir;
- }
+ }
#if defined(_WIN32) && !defined(__CYGWIN__)
- else if(git_dir[0] == '/')
- {
+ else if (git_dir[0] == '/') {
// Cygwin Git reports a full path that Cygwin understands, but we
// are a Windows application. Run "cygpath" to get Windows path.
std::string cygpath_exe = cmSystemTools::GetFilenamePath(git);
cygpath_exe += "/cygpath.exe";
- if(cmSystemTools::FileExists(cygpath_exe.c_str()))
- {
- char const* cygpath[] = {cygpath_exe.c_str(), "-w", git_dir.c_str(), 0};
+ if (cmSystemTools::FileExists(cygpath_exe.c_str())) {
+ char const* cygpath[] = { cygpath_exe.c_str(), "-w", git_dir.c_str(),
+ 0 };
OneLineParser cygpath_out(this, "cygpath-out> ", git_dir_line);
OutputLogger cygpath_err(this->Log, "cygpath-err> ");
- if(this->RunChild(cygpath, &cygpath_out, &cygpath_err))
- {
+ if (this->RunChild(cygpath, &cygpath_out, &cygpath_err, CM_NULLPTR,
+ cmProcessOutput::UTF8)) {
git_dir = git_dir_line;
- }
}
}
+ }
#endif
return git_dir;
}
-//----------------------------------------------------------------------------
std::string cmCTestGIT::FindTopDir()
{
std::string top_dir = this->SourceDirectory;
// Run "git rev-parse --show-cdup" to locate the top of the tree.
const char* git = this->CommandLineTool.c_str();
- char const* git_rev_parse[] = {git, "rev-parse", "--show-cdup", 0};
+ char const* git_rev_parse[] = { git, "rev-parse", "--show-cdup",
+ CM_NULLPTR };
std::string cdup;
OneLineParser rev_parse_out(this, "rev-parse-out> ", cdup);
OutputLogger rev_parse_err(this->Log, "rev-parse-err> ");
- if(this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err) &&
- !cdup.empty())
- {
+ if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, CM_NULLPTR,
+ cmProcessOutput::UTF8) &&
+ !cdup.empty()) {
top_dir += "/";
top_dir += cdup;
- top_dir = cmSystemTools::CollapseFullPath(top_dir.c_str());
- }
+ top_dir = cmSystemTools::CollapseFullPath(top_dir);
+ }
return top_dir;
}
-//----------------------------------------------------------------------------
bool cmCTestGIT::UpdateByFetchAndReset()
{
const char* git = this->CommandLineTool.c_str();
@@ -174,146 +160,163 @@ bool cmCTestGIT::UpdateByFetchAndReset()
// Add user-specified update options.
std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
- if(opts.empty())
- {
+ if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("GITUpdateOptions");
- }
- std::vector<cmStdString> args = cmSystemTools::ParseArguments(opts.c_str());
- for(std::vector<cmStdString>::const_iterator ai = args.begin();
- ai != args.end(); ++ai)
- {
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ for (std::vector<std::string>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai) {
git_fetch.push_back(ai->c_str());
- }
+ }
// Sentinel argument.
- git_fetch.push_back(0);
+ git_fetch.push_back(CM_NULLPTR);
// Fetch upstream refs.
OutputLogger fetch_out(this->Log, "fetch-out> ");
OutputLogger fetch_err(this->Log, "fetch-err> ");
- if(!this->RunUpdateCommand(&git_fetch[0], &fetch_out, &fetch_err))
- {
+ if (!this->RunUpdateCommand(&git_fetch[0], &fetch_out, &fetch_err)) {
return false;
- }
+ }
// Identify the merge head that would be used by "git pull".
std::string sha1;
{
- std::string fetch_head = this->FindGitDir() + "/FETCH_HEAD";
- std::ifstream fin(fetch_head.c_str(), std::ios::in | std::ios::binary);
- if(!fin)
- {
- this->Log << "Unable to open " << fetch_head << "\n";
- return false;
+ std::string fetch_head = this->FindGitDir() + "/FETCH_HEAD";
+ cmsys::ifstream fin(fetch_head.c_str(), std::ios::in | std::ios::binary);
+ if (!fin) {
+ this->Log << "Unable to open " << fetch_head << "\n";
+ return false;
}
- std::string line;
- while(sha1.empty() && cmSystemTools::GetLineFromStream(fin, line))
- {
- this->Log << "FETCH_HEAD> " << line << "\n";
- if(line.find("\tnot-for-merge\t") == line.npos)
- {
- std::string::size_type pos = line.find('\t');
- if(pos != line.npos)
- {
- sha1 = line.substr(0, pos);
+ std::string line;
+ while (sha1.empty() && cmSystemTools::GetLineFromStream(fin, line)) {
+ this->Log << "FETCH_HEAD> " << line << "\n";
+ if (line.find("\tnot-for-merge\t") == std::string::npos) {
+ std::string::size_type pos = line.find('\t');
+ if (pos != std::string::npos) {
+ sha1 = line.substr(0, pos);
}
}
}
- if(sha1.empty())
- {
- this->Log << "FETCH_HEAD has no upstream branch candidate!\n";
- return false;
+ if (sha1.empty()) {
+ this->Log << "FETCH_HEAD has no upstream branch candidate!\n";
+ return false;
}
}
// Reset the local branch to point at that tracked from upstream.
- char const* git_reset[] = {git, "reset", "--hard", sha1.c_str(), 0};
+ char const* git_reset[] = { git, "reset", "--hard", sha1.c_str(),
+ CM_NULLPTR };
OutputLogger reset_out(this->Log, "reset-out> ");
OutputLogger reset_err(this->Log, "reset-err> ");
return this->RunChild(&git_reset[0], &reset_out, &reset_err);
}
-//----------------------------------------------------------------------------
bool cmCTestGIT::UpdateByCustom(std::string const& custom)
{
std::vector<std::string> git_custom_command;
cmSystemTools::ExpandListArgument(custom, git_custom_command, true);
std::vector<char const*> git_custom;
- for(std::vector<std::string>::const_iterator
- i = git_custom_command.begin(); i != git_custom_command.end(); ++i)
- {
+ for (std::vector<std::string>::const_iterator i = git_custom_command.begin();
+ i != git_custom_command.end(); ++i) {
git_custom.push_back(i->c_str());
- }
- git_custom.push_back(0);
+ }
+ git_custom.push_back(CM_NULLPTR);
OutputLogger custom_out(this->Log, "custom-out> ");
OutputLogger custom_err(this->Log, "custom-err> ");
return this->RunUpdateCommand(&git_custom[0], &custom_out, &custom_err);
}
-//----------------------------------------------------------------------------
bool cmCTestGIT::UpdateInternal()
{
std::string custom = this->CTest->GetCTestConfiguration("GITUpdateCustom");
- if(!custom.empty())
- {
+ if (!custom.empty()) {
return this->UpdateByCustom(custom);
- }
+ }
return this->UpdateByFetchAndReset();
}
-//----------------------------------------------------------------------------
bool cmCTestGIT::UpdateImpl()
{
- if(!this->UpdateInternal())
- {
+ if (!this->UpdateInternal()) {
return false;
- }
+ }
std::string top_dir = this->FindTopDir();
const char* git = this->CommandLineTool.c_str();
const char* recursive = "--recursive";
+ const char* sync_recursive = "--recursive";
+
+ // Git < 1.6.5 did not support submodule --recursive
+ if (this->GetGitVersion() < cmCTestGITVersion(1, 6, 5, 0)) {
+ recursive = CM_NULLPTR;
+ // No need to require >= 1.6.5 if there are no submodules.
+ if (cmSystemTools::FileExists((top_dir + "/.gitmodules").c_str())) {
+ this->Log << "Git < 1.6.5 cannot update submodules recursively\n";
+ }
+ }
- // Git < 1.6.5.0 did not support --recursive
- if(this->GetGitVersion() < cmCTestGITVersion(1,6,5,0))
- {
- recursive = 0;
- // No need to require >= 1.6.5.0 if there are no submodules.
- if(cmSystemTools::FileExists((top_dir + "/.gitmodules").c_str()))
- {
- this->Log << "Git < 1.6.5.0 cannot update submodules recursively\n";
- }
+ // Git < 1.8.1 did not support sync --recursive
+ if (this->GetGitVersion() < cmCTestGITVersion(1, 8, 1, 0)) {
+ sync_recursive = CM_NULLPTR;
+ // No need to require >= 1.8.1 if there are no submodules.
+ if (cmSystemTools::FileExists((top_dir + "/.gitmodules").c_str())) {
+ this->Log << "Git < 1.8.1 cannot synchronize submodules recursively\n";
}
+ }
- char const* git_submodule[] = {git, "submodule", "update", recursive, 0};
OutputLogger submodule_out(this->Log, "submodule-out> ");
OutputLogger submodule_err(this->Log, "submodule-err> ");
+
+ bool ret;
+
+ std::string init_submodules =
+ this->CTest->GetCTestConfiguration("GITInitSubmodules");
+ if (cmSystemTools::IsOn(init_submodules.c_str())) {
+ char const* git_submodule_init[] = { git, "submodule", "init",
+ CM_NULLPTR };
+ ret = this->RunChild(git_submodule_init, &submodule_out, &submodule_err,
+ top_dir.c_str());
+
+ if (!ret) {
+ return false;
+ }
+ }
+
+ char const* git_submodule_sync[] = { git, "submodule", "sync",
+ sync_recursive, CM_NULLPTR };
+ ret = this->RunChild(git_submodule_sync, &submodule_out, &submodule_err,
+ top_dir.c_str());
+
+ if (!ret) {
+ return false;
+ }
+
+ char const* git_submodule[] = { git, "submodule", "update", recursive,
+ CM_NULLPTR };
return this->RunChild(git_submodule, &submodule_out, &submodule_err,
top_dir.c_str());
}
-//----------------------------------------------------------------------------
unsigned int cmCTestGIT::GetGitVersion()
{
- if(!this->CurrentGitVersion)
- {
+ if (!this->CurrentGitVersion) {
const char* git = this->CommandLineTool.c_str();
- char const* git_version[] = {git, "--version", 0};
+ char const* git_version[] = { git, "--version", CM_NULLPTR };
std::string version;
OneLineParser version_out(this, "version-out> ", version);
OutputLogger version_err(this->Log, "version-err> ");
- unsigned int v[4] = {0,0,0,0};
- if(this->RunChild(git_version, &version_out, &version_err) &&
- sscanf(version.c_str(), "git version %u.%u.%u.%u",
- &v[0], &v[1], &v[2], &v[3]) >= 3)
- {
+ unsigned int v[4] = { 0, 0, 0, 0 };
+ if (this->RunChild(git_version, &version_out, &version_err) &&
+ sscanf(version.c_str(), "git version %u.%u.%u.%u", &v[0], &v[1], &v[2],
+ &v[3]) >= 3) {
this->CurrentGitVersion = cmCTestGITVersion(v[0], v[1], v[2], v[3]);
- }
}
+ }
return this->CurrentGitVersion;
}
-//----------------------------------------------------------------------------
/* Diff format:
:src-mode dst-mode src-sha1 dst-sha1 status\0
@@ -324,76 +327,73 @@ unsigned int cmCTestGIT::GetGitVersion()
line appears only for lines with status 'C' or 'R'. See 'git help
diff-tree' for details.
*/
-class cmCTestGIT::DiffParser: public cmCTestVC::LineParser
+class cmCTestGIT::DiffParser : public cmCTestVC::LineParser
{
public:
- DiffParser(cmCTestGIT* git, const char* prefix):
- LineParser('\0', false), GIT(git), DiffField(DiffFieldNone)
- {
+ DiffParser(cmCTestGIT* git, const char* prefix)
+ : LineParser('\0', false)
+ , GIT(git)
+ , DiffField(DiffFieldNone)
+ {
this->SetLog(&git->Log, prefix);
- }
+ }
typedef cmCTestGIT::Change Change;
std::vector<Change> Changes;
+
protected:
cmCTestGIT* GIT;
- enum DiffFieldType { DiffFieldNone, DiffFieldChange,
- DiffFieldSrc, DiffFieldDst };
+ enum DiffFieldType
+ {
+ DiffFieldNone,
+ DiffFieldChange,
+ DiffFieldSrc,
+ DiffFieldDst
+ };
DiffFieldType DiffField;
Change CurChange;
void DiffReset()
- {
+ {
this->DiffField = DiffFieldNone;
this->Changes.clear();
- }
+ }
- virtual bool ProcessLine()
- {
- if(this->Line[0] == ':')
- {
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->Line[0] == ':') {
this->DiffField = DiffFieldChange;
this->CurChange = Change();
- }
- if(this->DiffField == DiffFieldChange)
- {
+ }
+ if (this->DiffField == DiffFieldChange) {
// :src-mode dst-mode src-sha1 dst-sha1 status
- if(this->Line[0] != ':')
- {
+ if (this->Line[0] != ':') {
this->DiffField = DiffFieldNone;
return true;
- }
- const char* src_mode_first = this->Line.c_str()+1;
- const char* src_mode_last = this->ConsumeField(src_mode_first);
+ }
+ const char* src_mode_first = this->Line.c_str() + 1;
+ const char* src_mode_last = this->ConsumeField(src_mode_first);
const char* dst_mode_first = this->ConsumeSpace(src_mode_last);
- const char* dst_mode_last = this->ConsumeField(dst_mode_first);
+ const char* dst_mode_last = this->ConsumeField(dst_mode_first);
const char* src_sha1_first = this->ConsumeSpace(dst_mode_last);
- const char* src_sha1_last = this->ConsumeField(src_sha1_first);
+ const char* src_sha1_last = this->ConsumeField(src_sha1_first);
const char* dst_sha1_first = this->ConsumeSpace(src_sha1_last);
- const char* dst_sha1_last = this->ConsumeField(dst_sha1_first);
- const char* status_first = this->ConsumeSpace(dst_sha1_last);
- const char* status_last = this->ConsumeField(status_first);
- if(status_first != status_last)
- {
+ const char* dst_sha1_last = this->ConsumeField(dst_sha1_first);
+ const char* status_first = this->ConsumeSpace(dst_sha1_last);
+ const char* status_last = this->ConsumeField(status_first);
+ if (status_first != status_last) {
this->CurChange.Action = *status_first;
this->DiffField = DiffFieldSrc;
- }
- else
- {
+ } else {
this->DiffField = DiffFieldNone;
- }
}
- else if(this->DiffField == DiffFieldSrc)
- {
+ } else if (this->DiffField == DiffFieldSrc) {
// src-path
- if(this->CurChange.Action == 'C')
- {
+ if (this->CurChange.Action == 'C') {
// Convert copy to addition of destination.
this->CurChange.Action = 'A';
this->DiffField = DiffFieldDst;
- }
- else if(this->CurChange.Action == 'R')
- {
+ } else if (this->CurChange.Action == 'R') {
// Convert rename to deletion of source and addition of destination.
this->CurChange.Action = 'D';
this->CurChange.Path = this->Line;
@@ -401,37 +401,36 @@ protected:
this->CurChange = Change('A');
this->DiffField = DiffFieldDst;
- }
- else
- {
+ } else {
this->CurChange.Path = this->Line;
this->Changes.push_back(this->CurChange);
this->DiffField = this->DiffFieldNone;
- }
}
- else if(this->DiffField == DiffFieldDst)
- {
+ } else if (this->DiffField == DiffFieldDst) {
// dst-path
this->CurChange.Path = this->Line;
this->Changes.push_back(this->CurChange);
this->DiffField = this->DiffFieldNone;
- }
- return true;
}
+ return true;
+ }
const char* ConsumeSpace(const char* c)
- {
- while(*c && isspace(*c)) { ++c; }
- return c;
+ {
+ while (*c && isspace(*c)) {
+ ++c;
}
- const char* ConsumeField(const char* c)
- {
- while(*c && !isspace(*c)) { ++c; }
return c;
+ }
+ const char* ConsumeField(const char* c)
+ {
+ while (*c && !isspace(*c)) {
+ ++c;
}
+ return c;
+ }
};
-//----------------------------------------------------------------------------
/* Commit format:
commit ...\n
@@ -451,18 +450,25 @@ protected:
The header may have more fields. See 'git help diff-tree'.
*/
-class cmCTestGIT::CommitParser: public cmCTestGIT::DiffParser
+class cmCTestGIT::CommitParser : public cmCTestGIT::DiffParser
{
public:
- CommitParser(cmCTestGIT* git, const char* prefix):
- DiffParser(git, prefix), Section(SectionHeader)
- {
+ CommitParser(cmCTestGIT* git, const char* prefix)
+ : DiffParser(git, prefix)
+ , Section(SectionHeader)
+ {
this->Separator = SectionSep[this->Section];
- }
+ }
private:
typedef cmCTestGIT::Revision Revision;
- enum SectionType { SectionHeader, SectionBody, SectionDiff, SectionCount };
+ enum SectionType
+ {
+ SectionHeader,
+ SectionBody,
+ SectionDiff,
+ SectionCount
+ };
static char const SectionSep[SectionCount];
SectionType Section;
Revision Rev;
@@ -473,142 +479,147 @@ private:
std::string EMail;
unsigned long Time;
long TimeZone;
- Person(): Name(), EMail(), Time(0), TimeZone(0) {}
+ Person()
+ : Name()
+ , EMail()
+ , Time(0)
+ , TimeZone(0)
+ {
+ }
};
void ParsePerson(const char* str, Person& person)
- {
+ {
// Person Name <person@domain.com> 1234567890 +0000
const char* c = str;
- while(*c && isspace(*c)) { ++c; }
+ while (*c && isspace(*c)) {
+ ++c;
+ }
const char* name_first = c;
- while(*c && *c != '<') { ++c; }
+ while (*c && *c != '<') {
+ ++c;
+ }
const char* name_last = c;
- while(name_last != name_first && isspace(*(name_last-1))) { --name_last; }
- person.Name.assign(name_first, name_last-name_first);
+ while (name_last != name_first && isspace(*(name_last - 1))) {
+ --name_last;
+ }
+ person.Name.assign(name_first, name_last - name_first);
- const char* email_first = *c? ++c : c;
- while(*c && *c != '>') { ++c; }
- const char* email_last = *c? c++ : c;
- person.EMail.assign(email_first, email_last-email_first);
+ const char* email_first = *c ? ++c : c;
+ while (*c && *c != '>') {
+ ++c;
+ }
+ const char* email_last = *c ? c++ : c;
+ person.EMail.assign(email_first, email_last - email_first);
person.Time = strtoul(c, (char**)&c, 10);
person.TimeZone = strtol(c, (char**)&c, 10);
- }
+ }
- virtual bool ProcessLine()
- {
- if(this->Line.empty())
- {
- if(this->Section == SectionBody && this->LineEnd == '\0')
- {
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->Line.empty()) {
+ if (this->Section == SectionBody && this->LineEnd == '\0') {
// Skip SectionDiff
this->NextSection();
- }
- this->NextSection();
}
- else
- {
- switch(this->Section)
- {
- case SectionHeader: this->DoHeaderLine(); break;
- case SectionBody: this->DoBodyLine(); break;
- case SectionDiff: this->DiffParser::ProcessLine(); break;
- case SectionCount: break; // never happens
- }
+ this->NextSection();
+ } else {
+ switch (this->Section) {
+ case SectionHeader:
+ this->DoHeaderLine();
+ break;
+ case SectionBody:
+ this->DoBodyLine();
+ break;
+ case SectionDiff:
+ this->DiffParser::ProcessLine();
+ break;
+ case SectionCount:
+ break; // never happens
}
- return true;
}
+ return true;
+ }
void NextSection()
- {
- this->Section = SectionType((this->Section+1) % SectionCount);
+ {
+ this->Section = SectionType((this->Section + 1) % SectionCount);
this->Separator = SectionSep[this->Section];
- if(this->Section == SectionHeader)
- {
+ if (this->Section == SectionHeader) {
this->GIT->DoRevision(this->Rev, this->Changes);
this->Rev = Revision();
this->DiffReset();
- }
}
+ }
void DoHeaderLine()
- {
+ {
// Look for header fields that we need.
- if(strncmp(this->Line.c_str(), "commit ", 7) == 0)
- {
- this->Rev.Rev = this->Line.c_str()+7;
- }
- else if(strncmp(this->Line.c_str(), "author ", 7) == 0)
- {
+ if (cmHasLiteralPrefix(this->Line.c_str(), "commit ")) {
+ this->Rev.Rev = this->Line.c_str() + 7;
+ } else if (cmHasLiteralPrefix(this->Line.c_str(), "author ")) {
Person author;
- this->ParsePerson(this->Line.c_str()+7, author);
+ this->ParsePerson(this->Line.c_str() + 7, author);
this->Rev.Author = author.Name;
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);
+ this->ParsePerson(this->Line.c_str() + 10, committer);
this->Rev.Committer = committer.Name;
this->Rev.CommitterEMail = committer.EMail;
this->Rev.CommitDate = this->FormatDateTime(committer);
- }
}
+ }
void DoBodyLine()
- {
+ {
// Commit log lines are indented by 4 spaces.
- if(this->Line.size() >= 4)
- {
+ if (this->Line.size() >= 4) {
this->Rev.Log += this->Line.substr(4);
- }
- this->Rev.Log += "\n";
}
+ this->Rev.Log += "\n";
+ }
std::string FormatDateTime(Person const& person)
- {
+ {
// Convert the time to a human-readable format that is also easy
// to machine-parse: "CCYY-MM-DD hh:mm:ss".
time_t seconds = static_cast<time_t>(person.Time);
struct tm* t = gmtime(&seconds);
char dt[1024];
- sprintf(dt, "%04d-%02d-%02d %02d:%02d:%02d",
- t->tm_year+1900, t->tm_mon+1, t->tm_mday,
- t->tm_hour, t->tm_min, t->tm_sec);
+ sprintf(dt, "%04d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900,
+ t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
std::string out = dt;
// Add the time-zone field "+zone" or "-zone".
char tz[32];
- if(person.TimeZone >= 0)
- {
+ if (person.TimeZone >= 0) {
sprintf(tz, " +%04ld", person.TimeZone);
- }
- else
- {
+ } else {
sprintf(tz, " -%04ld", -person.TimeZone);
- }
+ }
out += tz;
return out;
- }
+ }
};
-char const cmCTestGIT::CommitParser::SectionSep[SectionCount] =
-{'\n', '\n', '\0'};
+char const cmCTestGIT::CommitParser::SectionSep[SectionCount] = { '\n', '\n',
+ '\0' };
-//----------------------------------------------------------------------------
-void cmCTestGIT::LoadRevisions()
+bool cmCTestGIT::LoadRevisions()
{
// Use 'git rev-list ... | git diff-tree ...' to get revisions.
std::string range = this->OldRevision + ".." + this->NewRevision;
const char* git = this->CommandLineTool.c_str();
- const char* git_rev_list[] =
- {git, "rev-list", "--reverse", range.c_str(), "--", 0};
- const char* git_diff_tree[] =
- {git, "diff-tree", "--stdin", "--always", "-z", "-r", "--pretty=raw",
- "--encoding=utf-8", 0};
+ const char* git_rev_list[] = { git, "rev-list", "--reverse",
+ range.c_str(), "--", CM_NULLPTR };
+ const char* git_diff_tree[] = {
+ git, "diff-tree", "--stdin", "--always", "-z",
+ "-r", "--pretty=raw", "--encoding=utf-8", CM_NULLPTR
+ };
this->Log << this->ComputeCommandLine(git_rev_list) << " | "
<< this->ComputeCommandLine(git_diff_tree) << "\n";
@@ -619,34 +630,38 @@ void cmCTestGIT::LoadRevisions()
CommitParser out(this, "dt-out> ");
OutputLogger err(this->Log, "dt-err> ");
- this->RunProcess(cp, &out, &err);
+ this->RunProcess(cp, &out, &err, cmProcessOutput::UTF8);
// Send one extra zero-byte to terminate the last record.
out.Process("", 1);
cmsysProcess_Delete(cp);
+ return true;
}
-//----------------------------------------------------------------------------
-void cmCTestGIT::LoadModifications()
+bool cmCTestGIT::LoadModifications()
{
const char* git = this->CommandLineTool.c_str();
// Use 'git update-index' to refresh the index w.r.t. the work tree.
- const char* git_update_index[] = {git, "update-index", "--refresh", 0};
+ const char* git_update_index[] = { git, "update-index", "--refresh",
+ CM_NULLPTR };
OutputLogger ui_out(this->Log, "ui-out> ");
OutputLogger ui_err(this->Log, "ui-err> ");
- this->RunChild(git_update_index, &ui_out, &ui_err);
+ this->RunChild(git_update_index, &ui_out, &ui_err, CM_NULLPTR,
+ cmProcessOutput::UTF8);
// Use 'git diff-index' to get modified files.
- const char* git_diff_index[] = {git, "diff-index", "-z", "HEAD", "--", 0};
+ const char* git_diff_index[] = { git, "diff-index", "-z",
+ "HEAD", "--", CM_NULLPTR };
DiffParser out(this, "di-out> ");
OutputLogger err(this->Log, "di-err> ");
- this->RunChild(git_diff_index, &out, &err);
+ this->RunChild(git_diff_index, &out, &err, CM_NULLPTR,
+ cmProcessOutput::UTF8);
- for(std::vector<Change>::const_iterator ci = out.Changes.begin();
- ci != out.Changes.end(); ++ci)
- {
+ for (std::vector<Change>::const_iterator ci = out.Changes.begin();
+ ci != out.Changes.end(); ++ci) {
this->DoModification(PathModified, ci->Path);
- }
+ }
+ return true;
}
diff --git a/Source/CTest/cmCTestGIT.h b/Source/CTest/cmCTestGIT.h
index f4fae8f9d..4bf8294e6 100644
--- a/Source/CTest/cmCTestGIT.h
+++ b/Source/CTest/cmCTestGIT.h
@@ -1,38 +1,36 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestGIT_h
#define cmCTestGIT_h
+#include "cmConfigure.h"
+
#include "cmCTestGlobalVC.h"
+#include <iosfwd>
+#include <string>
+
+class cmCTest;
+
/** \class cmCTestGIT
* \brief Interaction with git command-line tool
*
*/
-class cmCTestGIT: public cmCTestGlobalVC
+class cmCTestGIT : public cmCTestGlobalVC
{
public:
/** Construct with a CTest instance and update log stream. */
cmCTestGIT(cmCTest* ctest, std::ostream& log);
- virtual ~cmCTestGIT();
+ ~cmCTestGIT() CM_OVERRIDE;
private:
unsigned int CurrentGitVersion;
unsigned int GetGitVersion();
std::string GetWorkingRevision();
- virtual void NoteOldRevision();
- virtual void NoteNewRevision();
- virtual bool UpdateImpl();
+ bool NoteOldRevision() CM_OVERRIDE;
+ bool NoteNewRevision() CM_OVERRIDE;
+ bool UpdateImpl() CM_OVERRIDE;
std::string FindGitDir();
std::string FindTopDir();
@@ -41,17 +39,19 @@ private:
bool UpdateByCustom(std::string const& custom);
bool UpdateInternal();
- void LoadRevisions();
- void LoadModifications();
+ bool LoadRevisions() CM_OVERRIDE;
+ bool LoadModifications() CM_OVERRIDE;
-public: // needed by older Sun compilers
+ // "public" needed by older Sun compilers
+public:
// Parsing helper classes.
- class OneLineParser;
- class DiffParser;
class CommitParser;
- friend class OneLineParser;
- friend class DiffParser;
+ class DiffParser;
+ class OneLineParser;
+
friend class CommitParser;
+ friend class DiffParser;
+ friend class OneLineParser;
};
#endif
diff --git a/Source/CTest/cmCTestGenericHandler.cxx b/Source/CTest/cmCTestGenericHandler.cxx
index 5338f307b..19034c01b 100644
--- a/Source/CTest/cmCTestGenericHandler.cxx
+++ b/Source/CTest/cmCTestGenericHandler.cxx
@@ -1,171 +1,138 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestGenericHandler.h"
-#include "cmSystemTools.h"
+
+#include "cmConfigure.h"
+#include <sstream>
+#include <utility>
#include "cmCTest.h"
+#include "cmSystemTools.h"
-//----------------------------------------------------------------------
cmCTestGenericHandler::cmCTestGenericHandler()
{
this->HandlerVerbose = cmSystemTools::OUTPUT_NONE;
- this->CTest = 0;
+ this->CTest = CM_NULLPTR;
this->SubmitIndex = 0;
this->AppendXML = false;
+ this->Quiet = false;
+ this->TestLoad = 0;
}
-//----------------------------------------------------------------------
cmCTestGenericHandler::~cmCTestGenericHandler()
{
}
-//----------------------------------------------------------------------
-void cmCTestGenericHandler::SetOption(const char* op, const char* value)
+void cmCTestGenericHandler::SetOption(const std::string& op, const char* value)
{
- if ( !op )
- {
- return;
- }
- if ( !value )
- {
- cmCTestGenericHandler::t_StringToString::iterator remit
- = this->Options.find(op);
- if ( remit != this->Options.end() )
- {
+ if (!value) {
+ cmCTestGenericHandler::t_StringToString::iterator remit =
+ this->Options.find(op);
+ if (remit != this->Options.end()) {
this->Options.erase(remit);
- }
- return;
}
+ return;
+ }
this->Options[op] = value;
}
-//----------------------------------------------------------------------
-void cmCTestGenericHandler::SetPersistentOption(const char* op,
+void cmCTestGenericHandler::SetPersistentOption(const std::string& op,
const char* value)
{
this->SetOption(op, value);
- if ( !op )
- {
- return;
- }
- if ( !value )
- {
- cmCTestGenericHandler::t_StringToString::iterator remit
- = this->PersistentOptions.find(op);
- if ( remit != this->PersistentOptions.end() )
- {
+ if (!value) {
+ cmCTestGenericHandler::t_StringToString::iterator remit =
+ this->PersistentOptions.find(op);
+ if (remit != this->PersistentOptions.end()) {
this->PersistentOptions.erase(remit);
- }
- return;
}
+ return;
+ }
this->PersistentOptions[op] = value;
}
-//----------------------------------------------------------------------
void cmCTestGenericHandler::Initialize()
{
this->AppendXML = false;
+ this->TestLoad = 0;
this->Options.clear();
t_StringToString::iterator it;
- for ( it = this->PersistentOptions.begin();
- it != this->PersistentOptions.end();
- ++ it )
- {
- this->Options[it->first.c_str()] = it->second.c_str();
- }
+ for (it = this->PersistentOptions.begin();
+ it != this->PersistentOptions.end(); ++it) {
+ this->Options[it->first] = it->second;
+ }
}
-//----------------------------------------------------------------------
-const char* cmCTestGenericHandler::GetOption(const char* op)
+const char* cmCTestGenericHandler::GetOption(const std::string& op)
{
- cmCTestGenericHandler::t_StringToString::iterator remit
- = this->Options.find(op);
- if ( remit == this->Options.end() )
- {
- return 0;
- }
+ cmCTestGenericHandler::t_StringToString::iterator remit =
+ this->Options.find(op);
+ if (remit == this->Options.end()) {
+ return CM_NULLPTR;
+ }
return remit->second.c_str();
}
-//----------------------------------------------------------------------
bool cmCTestGenericHandler::StartResultingXML(cmCTest::Part part,
const char* name,
cmGeneratedFileStream& xofs)
{
- if ( !name )
- {
+ if (!name) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot create resulting XML file without providing the name"
- << std::endl;);
+ "Cannot create resulting XML file without providing the name"
+ << std::endl;);
return false;
- }
- cmOStringStream ostr;
+ }
+ std::ostringstream ostr;
ostr << name;
- if ( this->SubmitIndex > 0 )
- {
+ if (this->SubmitIndex > 0) {
ostr << "_" << this->SubmitIndex;
- }
+ }
ostr << ".xml";
- if(this->CTest->GetCurrentTag().empty())
- {
+ if (this->CTest->GetCurrentTag().empty()) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Current Tag empty, this may mean NightlyStartTime / "
"CTEST_NIGHTLY_START_TIME was not set correctly. Or "
"maybe you forgot to call ctest_start() before calling "
- "ctest_configure()." << std::endl);
+ "ctest_configure()."
+ << std::endl);
cmSystemTools::SetFatalErrorOccured();
return false;
- }
- if( !this->CTest->OpenOutputFile(this->CTest->GetCurrentTag(),
- ostr.str().c_str(), xofs, true) )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot create resulting XML file: " << ostr.str().c_str()
- << std::endl);
+ }
+ if (!this->CTest->OpenOutputFile(this->CTest->GetCurrentTag(), ostr.str(),
+ xofs, true)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create resulting XML file: "
+ << ostr.str() << std::endl);
return false;
- }
+ }
this->CTest->AddSubmitFile(part, ostr.str().c_str());
return true;
}
-//----------------------------------------------------------------------
bool cmCTestGenericHandler::StartLogFile(const char* name,
- cmGeneratedFileStream& xofs)
+ cmGeneratedFileStream& xofs)
{
- if ( !name )
- {
+ if (!name) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot create log file without providing the name" << std::endl;);
+ "Cannot create log file without providing the name"
+ << std::endl;);
return false;
- }
- cmOStringStream ostr;
+ }
+ std::ostringstream ostr;
ostr << "Last" << name;
- if ( this->SubmitIndex > 0 )
- {
+ if (this->SubmitIndex > 0) {
ostr << "_" << this->SubmitIndex;
- }
- if ( !this->CTest->GetCurrentTag().empty() )
- {
+ }
+ if (!this->CTest->GetCurrentTag().empty()) {
ostr << "_" << this->CTest->GetCurrentTag();
- }
+ }
ostr << ".log";
- if( !this->CTest->OpenOutputFile("Temporary", ostr.str().c_str(), xofs) )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create log file: "
- << ostr.str().c_str() << std::endl);
+ if (!this->CTest->OpenOutputFile("Temporary", ostr.str(), xofs)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot create log file: " << ostr.str() << std::endl);
return false;
- }
+ }
return true;
}
diff --git a/Source/CTest/cmCTestGenericHandler.h b/Source/CTest/cmCTestGenericHandler.h
index ba8febb61..e881252c9 100644
--- a/Source/CTest/cmCTestGenericHandler.h
+++ b/Source/CTest/cmCTestGenericHandler.h
@@ -1,45 +1,42 @@
-/*============================================================================
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestGenericHandler_h
#define cmCTestGenericHandler_h
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <map>
+#include <stddef.h>
+#include <string>
+#include <vector>
-#include "cmObject.h"
#include "cmCTest.h"
-#include "cmSystemTools.h" //OutputOption
+#include "cmSystemTools.h"
-class cmMakefile;
class cmCTestCommand;
class cmGeneratedFileStream;
+class cmMakefile;
/** \class cmCTestGenericHandler
* \brief A superclass of all CTest Handlers
*
*/
-class cmCTestGenericHandler : public cmObject
+class cmCTestGenericHandler
{
public:
/**
* If verbose then more informaiton is printed out
*/
void SetVerbose(bool val)
- { this->HandlerVerbose = val ?
- cmSystemTools::OUTPUT_MERGE : cmSystemTools::OUTPUT_NONE; }
+ {
+ this->HandlerVerbose =
+ val ? cmSystemTools::OUTPUT_MERGE : cmSystemTools::OUTPUT_NONE;
+ }
/**
* Populate internals from CTest custom scripts
*/
- virtual void PopulateCustomVectors(cmMakefile *) {}
+ virtual void PopulateCustomVectors(cmMakefile*) {}
/**
* Do the actual processing. Subclass has to override it.
@@ -52,7 +49,10 @@ public:
*/
virtual int ProcessCommandLineArguments(
const std::string& /*currentArg*/, size_t& /*idx*/,
- const std::vector<std::string>& /*allArgs*/) { return 1; }
+ const std::vector<std::string>& /*allArgs*/)
+ {
+ return 1;
+ }
/**
* Initialize handler
@@ -71,31 +71,33 @@ public:
cmCTestGenericHandler();
virtual ~cmCTestGenericHandler();
- typedef std::map<cmStdString,cmStdString> t_StringToString;
+ typedef std::map<std::string, std::string> t_StringToString;
+ void SetPersistentOption(const std::string& op, const char* value);
+ void SetOption(const std::string& op, const char* value);
+ const char* GetOption(const std::string& op);
- void SetPersistentOption(const char* op, const char* value);
- void SetOption(const char* op, const char* value);
- const char* GetOption(const char* op);
-
- void SetCommand(cmCTestCommand* command)
- {
- this->Command = command;
- }
+ void SetCommand(cmCTestCommand* command) { this->Command = command; }
void SetSubmitIndex(int idx) { this->SubmitIndex = idx; }
int GetSubmitIndex() { return this->SubmitIndex; }
void SetAppendXML(bool b) { this->AppendXML = b; }
+ void SetQuiet(bool b) { this->Quiet = b; }
+ bool GetQuiet() { return this->Quiet; }
+ void SetTestLoad(unsigned long load) { this->TestLoad = load; }
+ unsigned long GetTestLoad() const { return this->TestLoad; }
protected:
- bool StartResultingXML(cmCTest::Part part,
- const char* name, cmGeneratedFileStream& xofs);
+ bool StartResultingXML(cmCTest::Part part, const char* name,
+ cmGeneratedFileStream& xofs);
bool StartLogFile(const char* name, cmGeneratedFileStream& xofs);
bool AppendXML;
+ bool Quiet;
+ unsigned long TestLoad;
cmSystemTools::OutputOption HandlerVerbose;
- cmCTest *CTest;
+ cmCTest* CTest;
t_StringToString Options;
t_StringToString PersistentOptions;
@@ -104,4 +106,3 @@ protected:
};
#endif
-
diff --git a/Source/CTest/cmCTestGlobalVC.cxx b/Source/CTest/cmCTestGlobalVC.cxx
index 8c51102e5..25294b5ae 100644
--- a/Source/CTest/cmCTestGlobalVC.cxx
+++ b/Source/CTest/cmCTestGlobalVC.cxx
@@ -1,50 +1,37 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestGlobalVC.h"
#include "cmCTest.h"
#include "cmSystemTools.h"
-#include "cmXMLSafe.h"
+#include "cmXMLWriter.h"
-#include <cmsys/RegularExpression.hxx>
+#include <ostream>
+#include <utility>
-//----------------------------------------------------------------------------
-cmCTestGlobalVC::cmCTestGlobalVC(cmCTest* ct, std::ostream& log):
- cmCTestVC(ct, log)
+cmCTestGlobalVC::cmCTestGlobalVC(cmCTest* ct, std::ostream& log)
+ : cmCTestVC(ct, log)
{
this->PriorRev = this->Unknown;
}
-//----------------------------------------------------------------------------
cmCTestGlobalVC::~cmCTestGlobalVC()
{
}
-//----------------------------------------------------------------------------
const char* cmCTestGlobalVC::LocalPath(std::string const& path)
{
return path.c_str();
}
-//----------------------------------------------------------------------------
void cmCTestGlobalVC::DoRevision(Revision const& revision,
std::vector<Change> const& changes)
{
// Ignore changes in the old revision.
- if(revision.Rev == this->OldRevision)
- {
+ if (revision.Rev == this->OldRevision) {
this->PriorRev = revision;
return;
- }
+ }
// Indicate we found a revision.
cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
@@ -54,27 +41,27 @@ void cmCTestGlobalVC::DoRevision(Revision const& revision,
// Report this revision.
Revision const& rev = this->Revisions.back();
+ /* clang-format off */
this->Log << "Found revision " << rev.Rev << "\n"
<< " author = " << rev.Author << "\n"
<< " date = " << rev.Date << "\n";
+ /* clang-format on */
// Update information about revisions of the changed files.
- for(std::vector<Change>::const_iterator ci = changes.begin();
- ci != changes.end(); ++ci)
- {
- if(const char* local = this->LocalPath(ci->Path))
- {
+ for (std::vector<Change>::const_iterator ci = changes.begin();
+ ci != changes.end(); ++ci) {
+ if (const char* local = this->LocalPath(ci->Path)) {
std::string dir = cmSystemTools::GetFilenamePath(local);
std::string name = cmSystemTools::GetFilenameName(local);
File& file = this->Dirs[dir][name];
- file.PriorRev = file.Rev? file.Rev : &this->PriorRev;
+ file.PriorRev = file.Rev ? file.Rev : &this->PriorRev;
file.Rev = &rev;
- this->Log << " " << ci->Action << " " << local << " " << "\n";
- }
+ this->Log << " " << ci->Action << " " << local << " "
+ << "\n";
}
+ }
}
-//----------------------------------------------------------------------------
void cmCTestGlobalVC::DoModification(PathStatus status,
std::string const& path)
{
@@ -84,59 +71,54 @@ void cmCTestGlobalVC::DoModification(PathStatus status,
file.Status = status;
// For local modifications the current rev is unknown and the
// prior rev is the latest from svn.
- if(!file.Rev && !file.PriorRev)
- {
+ if (!file.Rev && !file.PriorRev) {
file.PriorRev = &this->PriorRev;
- }
+ }
}
-//----------------------------------------------------------------------------
-void cmCTestGlobalVC::WriteXMLDirectory(std::ostream& xml,
+void cmCTestGlobalVC::WriteXMLDirectory(cmXMLWriter& xml,
std::string const& path,
Directory const& dir)
{
- const char* slash = path.empty()? "":"/";
- xml << "\t<Directory>\n"
- << "\t\t<Name>" << cmXMLSafe(path) << "</Name>\n";
- for(Directory::const_iterator fi = dir.begin(); fi != dir.end(); ++fi)
- {
+ const char* slash = path.empty() ? "" : "/";
+ xml.StartElement("Directory");
+ xml.Element("Name", path);
+ for (Directory::const_iterator fi = dir.begin(); fi != dir.end(); ++fi) {
std::string full = path + slash + fi->first;
this->WriteXMLEntry(xml, path, fi->first, full, fi->second);
- }
- xml << "\t</Directory>\n";
+ }
+ xml.EndElement(); // Directory
}
-//----------------------------------------------------------------------------
-void cmCTestGlobalVC::WriteXMLGlobal(std::ostream& xml)
+void cmCTestGlobalVC::WriteXMLGlobal(cmXMLWriter& xml)
{
- if(!this->NewRevision.empty())
- {
- xml << "\t<Revision>" << this->NewRevision << "</Revision>\n";
- }
- if(!this->OldRevision.empty() && this->OldRevision != this->NewRevision)
- {
- xml << "\t<PriorRevision>" << this->OldRevision << "</PriorRevision>\n";
- }
+ if (!this->NewRevision.empty()) {
+ xml.Element("Revision", this->NewRevision);
+ }
+ if (!this->OldRevision.empty() && this->OldRevision != this->NewRevision) {
+ xml.Element("PriorRevision", this->OldRevision);
+ }
}
-//----------------------------------------------------------------------------
-bool cmCTestGlobalVC::WriteXMLUpdates(std::ostream& xml)
+bool cmCTestGlobalVC::WriteXMLUpdates(cmXMLWriter& xml)
{
+ bool result = true;
cmCTestLog(this->CTest, HANDLER_OUTPUT,
" Gathering version information (one . per revision):\n"
- " " << std::flush);
- this->LoadRevisions();
+ " "
+ << std::flush);
+ result = this->LoadRevisions() && result;
cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
- this->LoadModifications();
+ result = this->LoadModifications() && result;
this->WriteXMLGlobal(xml);
- for(std::map<cmStdString, Directory>::const_iterator
- di = this->Dirs.begin(); di != this->Dirs.end(); ++di)
- {
+ for (std::map<std::string, Directory>::const_iterator di =
+ this->Dirs.begin();
+ di != this->Dirs.end(); ++di) {
this->WriteXMLDirectory(xml, di->first, di->second);
- }
+ }
- return true;
+ return result;
}
diff --git a/Source/CTest/cmCTestGlobalVC.h b/Source/CTest/cmCTestGlobalVC.h
index a648a5982..a5273d3dd 100644
--- a/Source/CTest/cmCTestGlobalVC.h
+++ b/Source/CTest/cmCTestGlobalVC.h
@@ -1,46 +1,53 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestGlobalVC_h
#define cmCTestGlobalVC_h
+#include "cmConfigure.h"
+
#include "cmCTestVC.h"
+#include <iosfwd>
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+class cmCTest;
+class cmXMLWriter;
+
/** \class cmCTestGlobalVC
* \brief Base class for handling globally-versioned trees
*
*/
-class cmCTestGlobalVC: public cmCTestVC
+class cmCTestGlobalVC : public cmCTestVC
{
public:
/** Construct with a CTest instance and update log stream. */
cmCTestGlobalVC(cmCTest* ctest, std::ostream& log);
- virtual ~cmCTestGlobalVC();
+ ~cmCTestGlobalVC() CM_OVERRIDE;
protected:
// Implement cmCTestVC internal API.
- virtual bool WriteXMLUpdates(std::ostream& xml);
+ bool WriteXMLUpdates(cmXMLWriter& xml) CM_OVERRIDE;
/** Represent a vcs-reported action for one path in a revision. */
struct Change
{
char Action;
std::string Path;
- Change(char a = '?'): Action(a) {}
+ Change(char a = '?')
+ : Action(a)
+ {
+ }
};
// Update status for files in each directory.
- class Directory: public std::map<cmStdString, File> {};
- std::map<cmStdString, Directory> Dirs;
+ class Directory : public std::map<std::string, File>
+ {
+ };
+ std::map<std::string, Directory> Dirs;
// Old and new repository revisions.
std::string OldRevision;
@@ -57,11 +64,11 @@ protected:
virtual void DoRevision(Revision const& revision,
std::vector<Change> const& changes);
virtual void DoModification(PathStatus status, std::string const& path);
- virtual void LoadModifications() = 0;
- virtual void LoadRevisions() = 0;
+ virtual bool LoadModifications() = 0;
+ virtual bool LoadRevisions() = 0;
- virtual void WriteXMLGlobal(std::ostream& xml);
- void WriteXMLDirectory(std::ostream& xml, std::string const& path,
+ virtual void WriteXMLGlobal(cmXMLWriter& xml);
+ void WriteXMLDirectory(cmXMLWriter& xml, std::string const& path,
Directory const& dir);
};
diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx
index 86a7617f1..49f9a6500 100644
--- a/Source/CTest/cmCTestHG.cxx
+++ b/Source/CTest/cmCTestHG.cxx
@@ -1,105 +1,102 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestHG.h"
#include "cmCTest.h"
+#include "cmCTestVC.h"
+#include "cmProcessTools.h"
#include "cmSystemTools.h"
#include "cmXMLParser.h"
-#include <cmsys/RegularExpression.hxx>
+#include "cmsys/RegularExpression.hxx"
+#include <ostream>
+#include <vector>
-//----------------------------------------------------------------------------
-cmCTestHG::cmCTestHG(cmCTest* ct, std::ostream& log):
- cmCTestGlobalVC(ct, log)
+cmCTestHG::cmCTestHG(cmCTest* ct, std::ostream& log)
+ : cmCTestGlobalVC(ct, log)
{
this->PriorRev = this->Unknown;
}
-//----------------------------------------------------------------------------
cmCTestHG::~cmCTestHG()
{
}
-//----------------------------------------------------------------------------
-class cmCTestHG::IdentifyParser: public cmCTestVC::LineParser
+class cmCTestHG::IdentifyParser : public cmCTestVC::LineParser
{
public:
- IdentifyParser(cmCTestHG* hg, const char* prefix,
- std::string& rev): Rev(rev)
- {
+ IdentifyParser(cmCTestHG* hg, const char* prefix, std::string& rev)
+ : Rev(rev)
+ {
this->SetLog(&hg->Log, prefix);
this->RegexIdentify.compile("^([0-9a-f]+)");
- }
+ }
+
private:
std::string& Rev;
cmsys::RegularExpression RegexIdentify;
- bool ProcessLine()
- {
- if(this->RegexIdentify.find(this->Line))
- {
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexIdentify.find(this->Line)) {
this->Rev = this->RegexIdentify.match(1);
return false;
- }
- return true;
}
+ return true;
+ }
};
-//----------------------------------------------------------------------------
-class cmCTestHG::StatusParser: public cmCTestVC::LineParser
+class cmCTestHG::StatusParser : public cmCTestVC::LineParser
{
public:
- StatusParser(cmCTestHG* hg, const char* prefix): HG(hg)
- {
+ StatusParser(cmCTestHG* hg, const char* prefix)
+ : HG(hg)
+ {
this->SetLog(&hg->Log, prefix);
this->RegexStatus.compile("([MARC!?I]) (.*)");
- }
+ }
private:
cmCTestHG* HG;
cmsys::RegularExpression RegexStatus;
- bool ProcessLine()
- {
- if(this->RegexStatus.find(this->Line))
- {
- this->DoPath(this->RegexStatus.match(1)[0],
- this->RegexStatus.match(2));
- }
- return true;
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexStatus.find(this->Line)) {
+ this->DoPath(this->RegexStatus.match(1)[0], this->RegexStatus.match(2));
}
+ return true;
+ }
void DoPath(char status, std::string const& path)
- {
- if(path.empty()) return;
+ {
+ if (path.empty()) {
+ return;
+ }
// See "hg help status". Note that there is no 'conflict' status.
- switch(status)
- {
- case 'M': case 'A': case '!': case 'R':
+ switch (status) {
+ case 'M':
+ case 'A':
+ case '!':
+ case 'R':
this->HG->DoModification(PathModified, path);
break;
- case 'I': case '?': case 'C': case ' ': default:
+ case 'I':
+ case '?':
+ case 'C':
+ case ' ':
+ default:
break;
- }
}
+ }
};
-//----------------------------------------------------------------------------
std::string cmCTestHG::GetWorkingRevision()
{
// Run plumbing "hg identify" to get work tree revision.
const char* hg = this->CommandLineTool.c_str();
- const char* hg_identify[] = {hg, "identify","-i", 0};
+ const char* hg_identify[] = { hg, "identify", "-i", CM_NULLPTR };
std::string rev;
IdentifyParser out(this, "rev-out> ", rev);
OutputLogger err(this->Log, "rev-err> ");
@@ -107,33 +104,32 @@ std::string cmCTestHG::GetWorkingRevision()
return rev;
}
-//----------------------------------------------------------------------------
-void cmCTestHG::NoteOldRevision()
+bool cmCTestHG::NoteOldRevision()
{
this->OldRevision = this->GetWorkingRevision();
cmCTestLog(this->CTest, HANDLER_OUTPUT, " Old revision of repository is: "
- << this->OldRevision << "\n");
+ << this->OldRevision << "\n");
this->PriorRev.Rev = this->OldRevision;
+ return true;
}
-//----------------------------------------------------------------------------
-void cmCTestHG::NoteNewRevision()
+bool cmCTestHG::NoteNewRevision()
{
this->NewRevision = this->GetWorkingRevision();
cmCTestLog(this->CTest, HANDLER_OUTPUT, " New revision of repository is: "
- << this->NewRevision << "\n");
+ << this->NewRevision << "\n");
+ return true;
}
-//----------------------------------------------------------------------------
bool cmCTestHG::UpdateImpl()
{
// Use "hg pull" followed by "hg update" to update the working tree.
{
- const char* hg = this->CommandLineTool.c_str();
- const char* hg_pull[] = {hg, "pull","-v", 0};
- OutputLogger out(this->Log, "pull-out> ");
- OutputLogger err(this->Log, "pull-err> ");
- this->RunChild(&hg_pull[0], &out, &err);
+ const char* hg = this->CommandLineTool.c_str();
+ const char* hg_pull[] = { hg, "pull", "-v", CM_NULLPTR };
+ OutputLogger out(this->Log, "pull-out> ");
+ OutputLogger err(this->Log, "pull-err> ");
+ this->RunChild(&hg_pull[0], &out, &err);
}
// TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
@@ -145,33 +141,34 @@ bool cmCTestHG::UpdateImpl()
// Add user-specified update options.
std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
- if(opts.empty())
- {
+ if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("HGUpdateOptions");
- }
- std::vector<cmStdString> args = cmSystemTools::ParseArguments(opts.c_str());
- for(std::vector<cmStdString>::const_iterator ai = args.begin();
- ai != args.end(); ++ai)
- {
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ for (std::vector<std::string>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai) {
hg_update.push_back(ai->c_str());
- }
+ }
// Sentinel argument.
- hg_update.push_back(0);
+ hg_update.push_back(CM_NULLPTR);
OutputLogger out(this->Log, "update-out> ");
OutputLogger err(this->Log, "update-err> ");
return this->RunUpdateCommand(&hg_update[0], &out, &err);
}
-//----------------------------------------------------------------------------
-class cmCTestHG::LogParser: public cmCTestVC::OutputLogger,
- private cmXMLParser
+class cmCTestHG::LogParser : public cmCTestVC::OutputLogger,
+ private cmXMLParser
{
public:
- LogParser(cmCTestHG* hg, const char* prefix):
- OutputLogger(hg->Log, prefix), HG(hg) { this->InitializeParser(); }
- ~LogParser() { this->CleanupParser(); }
+ LogParser(cmCTestHG* hg, const char* prefix)
+ : OutputLogger(hg->Log, prefix)
+ , HG(hg)
+ {
+ this->InitializeParser();
+ }
+ ~LogParser() CM_OVERRIDE { this->CleanupParser(); }
private:
cmCTestHG* HG;
@@ -182,119 +179,92 @@ private:
Change CurChange;
std::vector<char> CData;
- virtual bool ProcessChunk(const char* data, int length)
- {
+ bool ProcessChunk(const char* data, int length) CM_OVERRIDE
+ {
this->OutputLogger::ProcessChunk(data, length);
this->ParseChunk(data, length);
return true;
- }
+ }
- virtual void StartElement(const char* name, const char** atts)
- {
+ void StartElement(const std::string& name, const char** atts) CM_OVERRIDE
+ {
this->CData.clear();
- if(strcmp(name, "logentry") == 0)
- {
+ if (name == "logentry") {
this->Rev = Revision();
- if(const char* rev = this->FindAttribute(atts, "revision"))
- {
+ if (const char* rev = this->FindAttribute(atts, "revision")) {
this->Rev.Rev = rev;
- }
- this->Changes.clear();
}
+ this->Changes.clear();
}
+ }
- virtual void CharacterDataHandler(const char* data, int length)
- {
- this->CData.insert(this->CData.end(), data, data+length);
- }
+ void CharacterDataHandler(const char* data, int length) CM_OVERRIDE
+ {
+ this->CData.insert(this->CData.end(), data, data + length);
+ }
- virtual void EndElement(const char* name)
- {
- if(strcmp(name, "logentry") == 0)
- {
+ void EndElement(const std::string& name) CM_OVERRIDE
+ {
+ if (name == "logentry") {
this->HG->DoRevision(this->Rev, this->Changes);
- }
- else if(strcmp(name, "author") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "author") {
this->Rev.Author.assign(&this->CData[0], this->CData.size());
- }
- else if ( strcmp(name, "email") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "email") {
this->Rev.EMail.assign(&this->CData[0], this->CData.size());
- }
- else if(strcmp(name, "date") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "date") {
this->Rev.Date.assign(&this->CData[0], this->CData.size());
- }
- else if(strcmp(name, "msg") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "msg") {
this->Rev.Log.assign(&this->CData[0], this->CData.size());
- }
- else if(strcmp(name, "files") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "files") {
std::vector<std::string> paths = this->SplitCData();
- for(unsigned int i = 0; i < paths.size(); ++i)
- {
+ for (unsigned int i = 0; i < paths.size(); ++i) {
// Updated by default, will be modified using file_adds and
// file_dels.
this->CurChange = Change('U');
this->CurChange.Path = paths[i];
this->Changes.push_back(this->CurChange);
- }
}
- else if(strcmp(name, "file_adds") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "file_adds") {
std::string added_paths(this->CData.begin(), this->CData.end());
- for(unsigned int i = 0; i < this->Changes.size(); ++i)
- {
- if(added_paths.find(this->Changes[i].Path) != std::string::npos)
- {
+ for (unsigned int i = 0; i < this->Changes.size(); ++i) {
+ if (added_paths.find(this->Changes[i].Path) != std::string::npos) {
this->Changes[i].Action = 'A';
- }
}
}
- else if(strcmp(name, "file_dels") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "file_dels") {
std::string added_paths(this->CData.begin(), this->CData.end());
- for(unsigned int i = 0; i < this->Changes.size(); ++i)
- {
- if(added_paths.find(this->Changes[i].Path) != std::string::npos)
- {
+ for (unsigned int i = 0; i < this->Changes.size(); ++i) {
+ if (added_paths.find(this->Changes[i].Path) != std::string::npos) {
this->Changes[i].Action = 'D';
- }
}
}
- this->CData.clear();
}
+ this->CData.clear();
+ }
std::vector<std::string> SplitCData()
- {
+ {
std::vector<std::string> output;
std::string currPath;
- for(unsigned int i=0; i < this->CData.size(); ++i)
- {
- if(this->CData[i] != ' ')
- {
+ for (unsigned int i = 0; i < this->CData.size(); ++i) {
+ if (this->CData[i] != ' ') {
currPath += this->CData[i];
- }
- else
- {
+ } else {
output.push_back(currPath);
currPath = "";
- }
}
+ }
output.push_back(currPath);
return output;
- }
+ }
- virtual void ReportError(int, int, const char* msg)
- {
+ void ReportError(int /*line*/, int /*column*/, const char* msg) CM_OVERRIDE
+ {
this->HG->Log << "Error parsing hg log xml: " << msg << "\n";
- }
+ }
};
-//----------------------------------------------------------------------------
-void cmCTestHG::LoadRevisions()
+bool cmCTestHG::LoadRevisions()
{
// Use 'hg log' to get revisions in a xml format.
//
@@ -304,19 +274,20 @@ void cmCTestHG::LoadRevisions()
// proper XML escapes.
std::string range = this->OldRevision + ":" + this->NewRevision;
const char* hg = this->CommandLineTool.c_str();
- const char* hgXMLTemplate =
- "<logentry\n"
- " revision=\"{node|short}\">\n"
- " <author>{author|person}</author>\n"
- " <email>{author|email}</email>\n"
- " <date>{date|isodate}</date>\n"
- " <msg>{desc}</msg>\n"
- " <files>{files}</files>\n"
- " <file_adds>{file_adds}</file_adds>\n"
- " <file_dels>{file_dels}</file_dels>\n"
- "</logentry>\n";
- const char* hg_log[] = {hg, "log","--removed", "-r", range.c_str(),
- "--template", hgXMLTemplate, 0};
+ const char* hgXMLTemplate = "<logentry\n"
+ " revision=\"{node|short}\">\n"
+ " <author>{author|person}</author>\n"
+ " <email>{author|email}</email>\n"
+ " <date>{date|isodate}</date>\n"
+ " <msg>{desc}</msg>\n"
+ " <files>{files}</files>\n"
+ " <file_adds>{file_adds}</file_adds>\n"
+ " <file_dels>{file_dels}</file_dels>\n"
+ "</logentry>\n";
+ const char* hg_log[] = {
+ hg, "log", "--removed", "-r", range.c_str(),
+ "--template", hgXMLTemplate, CM_NULLPTR
+ };
LogParser out(this, "log-out> ");
out.Process("<?xml version=\"1.0\"?>\n"
@@ -324,15 +295,16 @@ void cmCTestHG::LoadRevisions()
OutputLogger err(this->Log, "log-err> ");
this->RunChild(hg_log, &out, &err);
out.Process("</log>\n");
+ return true;
}
-//----------------------------------------------------------------------------
-void cmCTestHG::LoadModifications()
+bool cmCTestHG::LoadModifications()
{
// Use 'hg status' to get modified files.
const char* hg = this->CommandLineTool.c_str();
- const char* hg_status[] = {hg, "status", 0};
+ const char* hg_status[] = { hg, "status", CM_NULLPTR };
StatusParser out(this, "status-out> ");
OutputLogger err(this->Log, "status-err> ");
this->RunChild(hg_status, &out, &err);
+ return true;
}
diff --git a/Source/CTest/cmCTestHG.h b/Source/CTest/cmCTestHG.h
index 1eaf9337e..ec9eaffe8 100644
--- a/Source/CTest/cmCTestHG.h
+++ b/Source/CTest/cmCTestHG.h
@@ -1,47 +1,46 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestHG_h
#define cmCTestHG_h
+#include "cmConfigure.h"
+
#include "cmCTestGlobalVC.h"
+#include <iosfwd>
+#include <string>
+
+class cmCTest;
+
/** \class cmCTestHG
* \brief Interaction with Mercurial command-line tool
*
*/
-class cmCTestHG: public cmCTestGlobalVC
+class cmCTestHG : public cmCTestGlobalVC
{
public:
/** Construct with a CTest instance and update log stream. */
cmCTestHG(cmCTest* ctest, std::ostream& log);
- virtual ~cmCTestHG();
+ ~cmCTestHG() CM_OVERRIDE;
private:
std::string GetWorkingRevision();
- virtual void NoteOldRevision();
- virtual void NoteNewRevision();
- virtual bool UpdateImpl();
+ bool NoteOldRevision() CM_OVERRIDE;
+ bool NoteNewRevision() CM_OVERRIDE;
+ bool UpdateImpl() CM_OVERRIDE;
- void LoadRevisions();
- void LoadModifications();
+ bool LoadRevisions() CM_OVERRIDE;
+ bool LoadModifications() CM_OVERRIDE;
// Parsing helper classes.
class IdentifyParser;
- class StatusParser;
class LogParser;
+ class StatusParser;
+
friend class IdentifyParser;
- friend class StatusParser;
friend class LogParser;
+ friend class StatusParser;
};
#endif
diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx
index 2e2feb047..c99e450d0 100644
--- a/Source/CTest/cmCTestHandlerCommand.cxx
+++ b/Source/CTest/cmCTestHandlerCommand.cxx
@@ -1,63 +1,139 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestHandlerCommand.h"
#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmWorkingDirectory.h"
+#include "cmake.h"
+
+#include <sstream>
+#include <stdlib.h>
+
+class cmExecutionStatus;
cmCTestHandlerCommand::cmCTestHandlerCommand()
{
const size_t INIT_SIZE = 100;
size_t cc;
this->Arguments.reserve(INIT_SIZE);
- for ( cc = 0; cc < INIT_SIZE; ++ cc )
- {
- this->Arguments.push_back(0);
- }
+ for (cc = 0; cc < INIT_SIZE; ++cc) {
+ this->Arguments.push_back(CM_NULLPTR);
+ }
this->Arguments[ct_RETURN_VALUE] = "RETURN_VALUE";
+ this->Arguments[ct_CAPTURE_CMAKE_ERROR] = "CAPTURE_CMAKE_ERROR";
this->Arguments[ct_SOURCE] = "SOURCE";
this->Arguments[ct_BUILD] = "BUILD";
this->Arguments[ct_SUBMIT_INDEX] = "SUBMIT_INDEX";
this->Last = ct_LAST;
this->AppendXML = false;
+ this->Quiet = false;
}
-bool cmCTestHandlerCommand
-::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
+namespace {
+// class to save and restore the error state for ctest_* commands
+// if a ctest_* command has a CAPTURE_CMAKE_ERROR then put the error
+// state into there and restore the system wide error to what
+// it was before the command ran
+class SaveRestoreErrorState
{
+public:
+ SaveRestoreErrorState()
+ {
+ this->InitialErrorState = cmSystemTools::GetErrorOccuredFlag();
+ cmSystemTools::ResetErrorOccuredFlag(); // rest the error state
+ this->CaptureCMakeErrorValue = false;
+ }
+ // if the function has a CAPTURE_CMAKE_ERROR then we should restore
+ // the error state to what it was before the function was run
+ // if not then let the error state be what it is
+ void CaptureCMakeError() { this->CaptureCMakeErrorValue = true; }
+ ~SaveRestoreErrorState()
+ {
+ // if we are not saving the return value then make sure
+ // if it was in error it goes back to being in error
+ // otherwise leave it be what it is
+ if (!this->CaptureCMakeErrorValue) {
+ if (this->InitialErrorState) {
+ cmSystemTools::SetErrorOccured();
+ }
+ return;
+ }
+ // if we have saved the error in a return variable
+ // then put things back exactly like they were
+ bool currentState = cmSystemTools::GetErrorOccuredFlag();
+ // if the state changed during this command we need
+ // to handle it, if not then nothing needs to be done
+ if (currentState != this->InitialErrorState) {
+ // restore the initial error state
+ if (this->InitialErrorState) {
+ cmSystemTools::SetErrorOccured();
+ } else {
+ cmSystemTools::ResetErrorOccuredFlag();
+ }
+ }
+ }
+
+private:
+ bool InitialErrorState;
+ bool CaptureCMakeErrorValue;
+};
+}
+
+bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& /*unused*/)
+{
+ // save error state and restore it if needed
+ SaveRestoreErrorState errorState;
// Allocate space for argument values.
this->Values.clear();
- this->Values.resize(this->Last, 0);
+ this->Values.resize(this->Last, CM_NULLPTR);
// Process input arguments.
this->ArgumentDoing = ArgumentDoingNone;
- for(unsigned int i=0; i < args.size(); ++i)
- {
+ // look at all arguments and do not short circuit on the first
+ // bad one so that CAPTURE_CMAKE_ERROR can override setting the
+ // global error state
+ bool foundBadArgument = false;
+ for (unsigned int i = 0; i < args.size(); ++i) {
// Check this argument.
- if(!this->CheckArgumentKeyword(args[i]) &&
- !this->CheckArgumentValue(args[i]))
- {
- cmOStringStream e;
+ if (!this->CheckArgumentKeyword(args[i]) &&
+ !this->CheckArgumentValue(args[i])) {
+ std::ostringstream e;
e << "called with unknown argument \"" << args[i] << "\".";
- this->SetError(e.str().c_str());
- return false;
- }
-
- // Quit if an argument is invalid.
- if(this->ArgumentDoing == ArgumentDoingError)
- {
- return false;
+ this->SetError(e.str());
+ foundBadArgument = true;
+ }
+ // note bad argument
+ if (this->ArgumentDoing == ArgumentDoingError) {
+ foundBadArgument = true;
+ }
+ }
+ bool capureCMakeError = (this->Values[ct_CAPTURE_CMAKE_ERROR] &&
+ *this->Values[ct_CAPTURE_CMAKE_ERROR]);
+ // now that arguments are parsed check to see if there is a
+ // CAPTURE_CMAKE_ERROR specified let the errorState object know.
+ if (capureCMakeError) {
+ errorState.CaptureCMakeError();
+ }
+ // if we found a bad argument then exit before running command
+ if (foundBadArgument) {
+ // store the cmake error
+ if (capureCMakeError) {
+ this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR],
+ "-1");
+ std::string const err = this->GetName() + " " + this->GetError();
+ if (!cmSystemTools::FindLastString(err.c_str(), "unknown error.")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, err << " error from command\n");
}
+ // return success because failure is recorded in CAPTURE_CMAKE_ERROR
+ return true;
}
+ // return failure because of bad argument
+ return false;
+ }
// Set the config type of this ctest to the current value of the
// CTEST_CONFIGURATION_TYPE script variable if it is defined.
@@ -65,134 +141,156 @@ bool cmCTestHandlerCommand
// line.
const char* ctestConfigType =
this->Makefile->GetDefinition("CTEST_CONFIGURATION_TYPE");
- if (ctestConfigType)
- {
+ if (ctestConfigType) {
this->CTest->SetConfigType(ctestConfigType);
- }
+ }
- if ( this->Values[ct_BUILD] )
- {
- this->CTest->SetCTestConfiguration("BuildDirectory",
- cmSystemTools::CollapseFullPath(
- this->Values[ct_BUILD]).c_str());
- }
- else
- {
+ if (this->Values[ct_BUILD]) {
+ this->CTest->SetCTestConfiguration(
+ "BuildDirectory",
+ cmSystemTools::CollapseFullPath(this->Values[ct_BUILD]).c_str(),
+ this->Quiet);
+ } else {
const char* bdir =
this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY");
- if(bdir)
- {
- this->
- CTest->SetCTestConfiguration("BuildDirectory",
- cmSystemTools::CollapseFullPath(bdir).c_str());
- }
- else
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "CTEST_BINARY_DIRECTORY not set" << std::endl;);
- }
- }
- if ( this->Values[ct_SOURCE] )
- {
- cmCTestLog(this->CTest, DEBUG,
- "Set source directory to: " << this->Values[ct_SOURCE] << std::endl);
- this->CTest->SetCTestConfiguration("SourceDirectory",
- cmSystemTools::CollapseFullPath(
- this->Values[ct_SOURCE]).c_str());
+ if (bdir) {
+ this->CTest->SetCTestConfiguration(
+ "BuildDirectory", cmSystemTools::CollapseFullPath(bdir).c_str(),
+ this->Quiet);
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "CTEST_BINARY_DIRECTORY not set"
+ << std::endl;);
}
- else
- {
- this->CTest->SetCTestConfiguration("SourceDirectory",
+ }
+ if (this->Values[ct_SOURCE]) {
+ cmCTestLog(this->CTest, DEBUG, "Set source directory to: "
+ << this->Values[ct_SOURCE] << std::endl);
+ this->CTest->SetCTestConfiguration(
+ "SourceDirectory",
+ cmSystemTools::CollapseFullPath(this->Values[ct_SOURCE]).c_str(),
+ this->Quiet);
+ } else {
+ this->CTest->SetCTestConfiguration(
+ "SourceDirectory",
cmSystemTools::CollapseFullPath(
- this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY")).c_str());
- }
+ this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY"))
+ .c_str(),
+ this->Quiet);
+ }
+
+ if (const char* changeId =
+ this->Makefile->GetDefinition("CTEST_CHANGE_ID")) {
+ this->CTest->SetCTestConfiguration("ChangeId", changeId, this->Quiet);
+ }
cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl;);
cmCTestGenericHandler* handler = this->InitializeHandler();
- if ( !handler )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot instantiate test handler " << this->GetName()
- << std::endl);
- return false;
+ if (!handler) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot instantiate test handler "
+ << this->GetName() << std::endl);
+ if (capureCMakeError) {
+ this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR],
+ "-1");
+ const char* err = this->GetError();
+ if (err && !cmSystemTools::FindLastString(err, "unknown error.")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, err << " error from command\n");
+ }
+ return true;
}
+ return false;
+ }
handler->SetAppendXML(this->AppendXML);
handler->PopulateCustomVectors(this->Makefile);
- if ( this->Values[ct_SUBMIT_INDEX] )
- {
- if(!this->CTest->GetDropSiteCDash() && this->CTest->GetDartVersion() <= 1)
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
+ if (this->Values[ct_SUBMIT_INDEX]) {
+ if (!this->CTest->GetDropSiteCDash() &&
+ this->CTest->GetDartVersion() <= 1) {
+ cmCTestLog(
+ this->CTest, ERROR_MESSAGE,
"Dart before version 2.0 does not support collecting submissions."
- << std::endl
- << "Please upgrade the server to Dart 2 or higher, or do not use "
- "SUBMIT_INDEX." << std::endl);
- }
- else
- {
+ << std::endl
+ << "Please upgrade the server to Dart 2 or higher, or do not use "
+ "SUBMIT_INDEX."
+ << std::endl);
+ } else {
handler->SetSubmitIndex(atoi(this->Values[ct_SUBMIT_INDEX]));
- }
}
- std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
- cmSystemTools::ChangeDirectory(
- this->CTest->GetCTestConfiguration("BuildDirectory").c_str());
+ }
+ cmWorkingDirectory workdir(
+ this->CTest->GetCTestConfiguration("BuildDirectory"));
int res = handler->ProcessHandler();
- if ( this->Values[ct_RETURN_VALUE] && *this->Values[ct_RETURN_VALUE])
- {
- cmOStringStream str;
+ if (this->Values[ct_RETURN_VALUE] && *this->Values[ct_RETURN_VALUE]) {
+ std::ostringstream str;
str << res;
- this->Makefile->AddDefinition(
- this->Values[ct_RETURN_VALUE], str.str().c_str());
+ this->Makefile->AddDefinition(this->Values[ct_RETURN_VALUE],
+ str.str().c_str());
+ }
+ this->ProcessAdditionalValues(handler);
+ // log the error message if there was an error
+ if (capureCMakeError) {
+ const char* returnString = "0";
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ returnString = "-1";
+ const char* err = this->GetError();
+ // print out the error if it is not "unknown error" which means
+ // there was no message
+ if (err && !cmSystemTools::FindLastString(err, "unknown error.")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, err);
+ }
}
- cmSystemTools::ChangeDirectory(current_dir.c_str());
+ // store the captured cmake error state 0 or -1
+ this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR],
+ returnString);
+ }
return true;
}
-//----------------------------------------------------------------------------
+void cmCTestHandlerCommand::ProcessAdditionalValues(cmCTestGenericHandler*)
+{
+}
+
bool cmCTestHandlerCommand::CheckArgumentKeyword(std::string const& arg)
{
// Look for non-value arguments common to all commands.
- if(arg == "APPEND")
- {
+ if (arg == "APPEND") {
this->ArgumentDoing = ArgumentDoingNone;
this->AppendXML = true;
return true;
- }
+ }
+ if (arg == "QUIET") {
+ this->ArgumentDoing = ArgumentDoingNone;
+ this->Quiet = true;
+ return true;
+ }
// Check for a keyword in our argument/value table.
- for(unsigned int k=0; k < this->Arguments.size(); ++k)
- {
- if(this->Arguments[k] && arg == this->Arguments[k])
- {
+ for (unsigned int k = 0; k < this->Arguments.size(); ++k) {
+ if (this->Arguments[k] && arg == this->Arguments[k]) {
this->ArgumentDoing = ArgumentDoingKeyword;
this->ArgumentIndex = k;
return true;
- }
}
+ }
return false;
}
-//----------------------------------------------------------------------------
bool cmCTestHandlerCommand::CheckArgumentValue(std::string const& arg)
{
- if(this->ArgumentDoing == ArgumentDoingKeyword)
- {
+ if (this->ArgumentDoing == ArgumentDoingKeyword) {
this->ArgumentDoing = ArgumentDoingNone;
unsigned int k = this->ArgumentIndex;
- if(this->Values[k])
- {
- cmOStringStream e;
+ if (this->Values[k]) {
+ std::ostringstream e;
e << "Called with more than one value for " << this->Arguments[k];
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
this->ArgumentDoing = ArgumentDoingError;
return true;
- }
+ }
this->Values[k] = arg.c_str();
- cmCTestLog(this->CTest, DEBUG, "Set " << this->Arguments[k]
- << " to " << arg << "\n");
+ cmCTestLog(this->CTest, DEBUG, "Set " << this->Arguments[k] << " to "
+ << arg << "\n");
return true;
- }
+ }
return false;
}
diff --git a/Source/CTest/cmCTestHandlerCommand.h b/Source/CTest/cmCTestHandlerCommand.h
index 8ef2b8028..0ea061225 100644
--- a/Source/CTest/cmCTestHandlerCommand.h
+++ b/Source/CTest/cmCTestHandlerCommand.h
@@ -1,20 +1,18 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestHandlerCommand_h
#define cmCTestHandlerCommand_h
+#include "cmConfigure.h"
+
#include "cmCTestCommand.h"
+#include <stddef.h>
+#include <string>
+#include <vector>
+
class cmCTestGenericHandler;
+class cmExecutionStatus;
/** \class cmCTestHandler
* \brief Run a ctest script
@@ -27,27 +25,33 @@ public:
cmCTestHandlerCommand();
/**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ virtual std::string GetName() const = 0;
+
+ /**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
- virtual bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus &status);
-
- cmTypeMacro(cmCTestHandlerCommand, cmCTestCommand);
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
enum
- {
+ {
ct_NONE,
ct_RETURN_VALUE,
+ ct_CAPTURE_CMAKE_ERROR,
ct_BUILD,
ct_SOURCE,
ct_SUBMIT_INDEX,
ct_LAST
- };
+ };
protected:
virtual cmCTestGenericHandler* InitializeHandler() = 0;
+ virtual void ProcessAdditionalValues(cmCTestGenericHandler* handler);
+
// Command argument handling.
virtual bool CheckArgumentKeyword(std::string const& arg);
virtual bool CheckArgumentValue(std::string const& arg);
@@ -62,6 +66,7 @@ protected:
unsigned int ArgumentIndex;
bool AppendXML;
+ bool Quiet;
std::string ReturnVariable;
std::vector<const char*> Arguments;
@@ -69,9 +74,9 @@ protected:
size_t Last;
};
-#define CTEST_COMMAND_APPEND_OPTION_DOCS \
- "The APPEND option marks results for append to those previously " \
- "submitted to a dashboard server since the last ctest_start. " \
+#define CTEST_COMMAND_APPEND_OPTION_DOCS \
+ "The APPEND option marks results for append to those previously " \
+ "submitted to a dashboard server since the last ctest_start. " \
"Append semantics are defined by the dashboard server in use."
#endif
diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
index 9831d0200..5b213518a 100644
--- a/Source/CTest/cmCTestLaunch.cxx
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -1,37 +1,43 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestLaunch.h"
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
+#include "cmConfigure.h"
- 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 "cmCTestLaunch.h"
+#include "cmsys/FStream.hxx"
+#include "cmsys/Process.h"
+#include "cmsys/RegularExpression.hxx"
+#include <iostream>
+#include <stdlib.h>
+#include <string.h>
+#include "cmCryptoHash.h"
#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProcessOutput.h"
+#include "cmStateSnapshot.h"
#include "cmSystemTools.h"
-#include "cmXMLSafe.h"
+#include "cmXMLWriter.h"
+#include "cm_auto_ptr.hxx"
#include "cmake.h"
-#include <cmsys/MD5.h>
-#include <cmsys/Process.h>
-#include <cmsys/RegularExpression.hxx>
+#ifdef _WIN32
+#include <fcntl.h> // for _O_BINARY
+#include <io.h> // for _setmode
+#include <stdio.h> // for std{out,err} and fileno
+#endif
-//----------------------------------------------------------------------------
cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
{
this->Passthru = true;
- this->Process = 0;
+ this->Process = CM_NULLPTR;
this->ExitCode = 1;
this->CWD = cmSystemTools::GetCurrentWorkingDirectory();
- if(!this->ParseArguments(argc, argv))
- {
+ if (!this->ParseArguments(argc, argv)) {
return;
- }
+ }
this->ComputeFileNames();
@@ -41,148 +47,117 @@ cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
this->Process = cmsysProcess_New();
}
-//----------------------------------------------------------------------------
cmCTestLaunch::~cmCTestLaunch()
{
cmsysProcess_Delete(this->Process);
- if(!this->Passthru)
- {
- cmSystemTools::RemoveFile(this->LogOut.c_str());
- cmSystemTools::RemoveFile(this->LogErr.c_str());
- }
+ if (!this->Passthru) {
+ cmSystemTools::RemoveFile(this->LogOut);
+ cmSystemTools::RemoveFile(this->LogErr);
+ }
}
-//----------------------------------------------------------------------------
bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
{
// Launcher options occur first and are separated from the real
// command line by a '--' option.
- enum Doing { DoingNone,
- DoingOutput,
- DoingSource,
- DoingLanguage,
- DoingTargetName,
- DoingTargetType,
- DoingBuildDir,
- DoingCount };
+ enum Doing
+ {
+ DoingNone,
+ DoingOutput,
+ DoingSource,
+ DoingLanguage,
+ DoingTargetName,
+ DoingTargetType,
+ DoingBuildDir,
+ DoingCount,
+ DoingFilterPrefix
+ };
Doing doing = DoingNone;
int arg0 = 0;
- for(int i=1; !arg0 && i < argc; ++i)
- {
+ for (int i = 1; !arg0 && i < argc; ++i) {
const char* arg = argv[i];
- if(strcmp(arg, "--") == 0)
- {
- arg0 = i+1;
- }
- else if(strcmp(arg, "--output") == 0)
- {
+ if (strcmp(arg, "--") == 0) {
+ arg0 = i + 1;
+ } else if (strcmp(arg, "--output") == 0) {
doing = DoingOutput;
- }
- else if(strcmp(arg, "--source") == 0)
- {
+ } else if (strcmp(arg, "--source") == 0) {
doing = DoingSource;
- }
- else if(strcmp(arg, "--language") == 0)
- {
+ } else if (strcmp(arg, "--language") == 0) {
doing = DoingLanguage;
- }
- else if(strcmp(arg, "--target-name") == 0)
- {
+ } else if (strcmp(arg, "--target-name") == 0) {
doing = DoingTargetName;
- }
- else if(strcmp(arg, "--target-type") == 0)
- {
+ } else if (strcmp(arg, "--target-type") == 0) {
doing = DoingTargetType;
- }
- else if(strcmp(arg, "--build-dir") == 0)
- {
+ } else if (strcmp(arg, "--build-dir") == 0) {
doing = DoingBuildDir;
- }
- else if(doing == DoingOutput)
- {
+ } else if (strcmp(arg, "--filter-prefix") == 0) {
+ doing = DoingFilterPrefix;
+ } else if (doing == DoingOutput) {
this->OptionOutput = arg;
doing = DoingNone;
- }
- else if(doing == DoingSource)
- {
+ } else if (doing == DoingSource) {
this->OptionSource = arg;
doing = DoingNone;
- }
- else if(doing == DoingLanguage)
- {
+ } else if (doing == DoingLanguage) {
this->OptionLanguage = arg;
- if(this->OptionLanguage == "CXX")
- {
+ if (this->OptionLanguage == "CXX") {
this->OptionLanguage = "C++";
- }
- doing = DoingNone;
}
- else if(doing == DoingTargetName)
- {
+ doing = DoingNone;
+ } else if (doing == DoingTargetName) {
this->OptionTargetName = arg;
doing = DoingNone;
- }
- else if(doing == DoingTargetType)
- {
+ } else if (doing == DoingTargetType) {
this->OptionTargetType = arg;
doing = DoingNone;
- }
- else if(doing == DoingBuildDir)
- {
+ } else if (doing == DoingBuildDir) {
this->OptionBuildDir = arg;
doing = DoingNone;
- }
+ } else if (doing == DoingFilterPrefix) {
+ this->OptionFilterPrefix = arg;
+ doing = DoingNone;
}
+ }
// Extract the real command line.
- if(arg0)
- {
+ if (arg0) {
this->RealArgC = argc - arg0;
this->RealArgV = argv + arg0;
- for(int i=0; i < this->RealArgC; ++i)
- {
+ for (int i = 0; i < this->RealArgC; ++i) {
this->HandleRealArg(this->RealArgV[i]);
- }
- return true;
- }
- else
- {
- this->RealArgC = 0;
- this->RealArgV = 0;
- std::cerr << "No launch/command separator ('--') found!\n";
- return false;
}
+ return true;
+ }
+ this->RealArgC = 0;
+ this->RealArgV = CM_NULLPTR;
+ std::cerr << "No launch/command separator ('--') found!\n";
+ return false;
}
-//----------------------------------------------------------------------------
void cmCTestLaunch::HandleRealArg(const char* arg)
{
#ifdef _WIN32
// Expand response file arguments.
- if(arg[0] == '@' && cmSystemTools::FileExists(arg+1))
- {
- std::ifstream fin(arg+1);
+ if (arg[0] == '@' && cmSystemTools::FileExists(arg + 1)) {
+ cmsys::ifstream fin(arg + 1);
std::string line;
- while(cmSystemTools::GetLineFromStream(fin, line))
- {
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
cmSystemTools::ParseWindowsCommandLine(line.c_str(), this->RealArgs);
- }
- return;
}
+ return;
+ }
#endif
this->RealArgs.push_back(arg);
}
-//----------------------------------------------------------------------------
void cmCTestLaunch::ComputeFileNames()
{
// We just passthru the behavior of the real command unless the
// CTEST_LAUNCH_LOGS environment variable is set.
const char* d = getenv("CTEST_LAUNCH_LOGS");
- if(!(d && *d))
- {
+ if (!(d && *d)) {
return;
- }
+ }
this->Passthru = false;
// The environment variable specifies the directory into which we
@@ -193,18 +168,14 @@ void cmCTestLaunch::ComputeFileNames()
// We hash the input command working dir and command line to obtain
// a repeatable and (probably) unique name for log files.
- char hash[32];
- cmsysMD5* md5 = cmsysMD5_New();
- cmsysMD5_Initialize(md5);
- cmsysMD5_Append(md5, (unsigned char const*)(this->CWD.c_str()), -1);
- for(std::vector<std::string>::const_iterator ai = this->RealArgs.begin();
- ai != this->RealArgs.end(); ++ai)
- {
- cmsysMD5_Append(md5, (unsigned char const*)ai->c_str(), -1);
- }
- cmsysMD5_FinalizeHex(md5, hash);
- cmsysMD5_Delete(md5);
- this->LogHash.assign(hash, 32);
+ cmCryptoHash md5(cmCryptoHash::AlgoMD5);
+ md5.Initialize();
+ md5.Append(this->CWD);
+ for (std::vector<std::string>::const_iterator ai = this->RealArgs.begin();
+ ai != this->RealArgs.end(); ++ai) {
+ md5.Append(*ai);
+ }
+ this->LogHash = md5.FinalizeHex();
// We store stdout and stderr in temporary log files.
this->LogOut = this->LogDir;
@@ -217,82 +188,88 @@ void cmCTestLaunch::ComputeFileNames()
this->LogErr += "-err.txt";
}
-//----------------------------------------------------------------------------
void cmCTestLaunch::RunChild()
{
// Ignore noopt make rules
- if(this->RealArgs.empty() || this->RealArgs[0] == ":")
- {
+ if (this->RealArgs.empty() || this->RealArgs[0] == ":") {
this->ExitCode = 0;
return;
- }
+ }
// Prepare to run the real command.
cmsysProcess* cp = this->Process;
cmsysProcess_SetCommand(cp, this->RealArgV);
- std::ofstream fout;
- std::ofstream ferr;
- if(this->Passthru)
- {
+ cmsys::ofstream fout;
+ cmsys::ofstream ferr;
+ if (this->Passthru) {
// In passthru mode we just share the output pipes.
cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
- }
- else
- {
+ } else {
// In full mode we record the child output pipes to log files.
- fout.open(this->LogOut.c_str(),
- std::ios::out | std::ios::binary);
- ferr.open(this->LogErr.c_str(),
- std::ios::out | std::ios::binary);
- }
+ fout.open(this->LogOut.c_str(), std::ios::out | std::ios::binary);
+ ferr.open(this->LogErr.c_str(), std::ios::out | std::ios::binary);
+ }
+
+#ifdef _WIN32
+ // Do this so that newline transformation is not done when writing to cout
+ // and cerr below.
+ _setmode(fileno(stdout), _O_BINARY);
+ _setmode(fileno(stderr), _O_BINARY);
+#endif
// Run the real command.
cmsysProcess_Execute(cp);
// Record child stdout and stderr if necessary.
- if(!this->Passthru)
- {
- char* data = 0;
+ if (!this->Passthru) {
+ char* data = CM_NULLPTR;
int length = 0;
- while(int p = cmsysProcess_WaitForData(cp, &data, &length, 0))
- {
- if(p == cmsysProcess_Pipe_STDOUT)
- {
- fout.write(data, length);
- std::cout.write(data, length);
+ cmProcessOutput processOutput;
+ std::string strdata;
+ while (int p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR)) {
+ if (p == cmsysProcess_Pipe_STDOUT) {
+ processOutput.DecodeText(data, length, strdata, 1);
+ fout.write(strdata.c_str(), strdata.size());
+ std::cout.write(strdata.c_str(), strdata.size());
this->HaveOut = true;
- }
- else if(p == cmsysProcess_Pipe_STDERR)
- {
- ferr.write(data, length);
- std::cerr.write(data, length);
+ } else if (p == cmsysProcess_Pipe_STDERR) {
+ processOutput.DecodeText(data, length, strdata, 2);
+ ferr.write(strdata.c_str(), strdata.size());
+ std::cerr.write(strdata.c_str(), strdata.size());
this->HaveErr = true;
- }
}
}
+ processOutput.DecodeText(std::string(), strdata, 1);
+ if (!strdata.empty()) {
+ fout.write(strdata.c_str(), strdata.size());
+ std::cout.write(strdata.c_str(), strdata.size());
+ }
+ processOutput.DecodeText(std::string(), strdata, 2);
+ if (!strdata.empty()) {
+ ferr.write(strdata.c_str(), strdata.size());
+ std::cerr.write(strdata.c_str(), strdata.size());
+ }
+ }
// Wait for the real command to finish.
- cmsysProcess_WaitForExit(cp, 0);
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
this->ExitCode = cmsysProcess_GetExitValue(cp);
}
-//----------------------------------------------------------------------------
int cmCTestLaunch::Run()
{
- if(!this->Process)
- {
+ if (!this->Process) {
std::cerr << "Could not allocate cmsysProcess instance!\n";
return -1;
- }
+ }
this->RunChild();
- if(this->CheckResults())
- {
+ if (this->CheckResults()) {
return this->ExitCode;
- }
+ }
this->LoadConfig();
this->WriteXML();
@@ -300,13 +277,11 @@ int cmCTestLaunch::Run()
return this->ExitCode;
}
-//----------------------------------------------------------------------------
void cmCTestLaunch::LoadLabels()
{
- if(this->OptionBuildDir.empty() || this->OptionTargetName.empty())
- {
+ if (this->OptionBuildDir.empty() || this->OptionTargetName.empty()) {
return;
- }
+ }
// Labels are listed in per-target files.
std::string fname = this->OptionBuildDir;
@@ -320,42 +295,35 @@ void cmCTestLaunch::LoadLabels()
cmSystemTools::ConvertToUnixSlashes(source);
// Load the labels file.
- std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
- if(!fin) { return; }
+ cmsys::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary);
+ if (!fin) {
+ return;
+ }
bool inTarget = true;
bool inSource = false;
std::string line;
- while(cmSystemTools::GetLineFromStream(fin, line))
- {
- if(line.empty() || line[0] == '#')
- {
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (line.empty() || line[0] == '#') {
// Ignore blank and comment lines.
continue;
- }
- else if(line[0] == ' ')
- {
+ }
+ if (line[0] == ' ') {
// Label lines appear indented by one space.
- if(inTarget || inSource)
- {
- this->Labels.insert(line.c_str()+1);
- }
+ if (inTarget || inSource) {
+ this->Labels.insert(line.c_str() + 1);
}
- else if(!this->OptionSource.empty() && !inSource)
- {
+ } else if (!this->OptionSource.empty() && !inSource) {
// Non-indented lines specify a source file name. The first one
// is the end of the target-wide labels. Use labels following a
// matching source.
inTarget = false;
inSource = this->SourceMatches(line, source);
- }
- else
- {
+ } else {
return;
- }
}
+ }
}
-//----------------------------------------------------------------------------
bool cmCTestLaunch::SourceMatches(std::string const& lhs,
std::string const& rhs)
{
@@ -366,251 +334,212 @@ bool cmCTestLaunch::SourceMatches(std::string const& lhs,
return lhs == rhs;
}
-//----------------------------------------------------------------------------
bool cmCTestLaunch::IsError() const
{
return this->ExitCode != 0;
}
-//----------------------------------------------------------------------------
void cmCTestLaunch::WriteXML()
{
// Name the xml file.
std::string logXML = this->LogDir;
- logXML += this->IsError()? "error-" : "warning-";
+ logXML += this->IsError() ? "error-" : "warning-";
logXML += this->LogHash;
logXML += ".xml";
// Use cmGeneratedFileStream to atomically create the report file.
cmGeneratedFileStream fxml(logXML.c_str());
- fxml << "\t<Failure type=\""
- << (this->IsError()? "Error" : "Warning") << "\">\n";
- this->WriteXMLAction(fxml);
- this->WriteXMLCommand(fxml);
- this->WriteXMLResult(fxml);
- this->WriteXMLLabels(fxml);
- fxml << "\t</Failure>\n";
+ cmXMLWriter xml(fxml, 2);
+ xml.StartElement("Failure");
+ xml.Attribute("type", this->IsError() ? "Error" : "Warning");
+ this->WriteXMLAction(xml);
+ this->WriteXMLCommand(xml);
+ this->WriteXMLResult(xml);
+ this->WriteXMLLabels(xml);
+ xml.EndElement(); // Failure
}
-//----------------------------------------------------------------------------
-void cmCTestLaunch::WriteXMLAction(std::ostream& fxml)
+void cmCTestLaunch::WriteXMLAction(cmXMLWriter& xml)
{
- fxml << "\t\t<!-- Meta-information about the build action -->\n";
- fxml << "\t\t<Action>\n";
+ xml.Comment("Meta-information about the build action");
+ xml.StartElement("Action");
// TargetName
- if(!this->OptionTargetName.empty())
- {
- fxml << "\t\t\t<TargetName>"
- << cmXMLSafe(this->OptionTargetName)
- << "</TargetName>\n";
- }
+ if (!this->OptionTargetName.empty()) {
+ xml.Element("TargetName", this->OptionTargetName);
+ }
// Language
- if(!this->OptionLanguage.empty())
- {
- fxml << "\t\t\t<Language>"
- << cmXMLSafe(this->OptionLanguage)
- << "</Language>\n";
- }
+ if (!this->OptionLanguage.empty()) {
+ xml.Element("Language", this->OptionLanguage);
+ }
// SourceFile
- if(!this->OptionSource.empty())
- {
+ if (!this->OptionSource.empty()) {
std::string source = this->OptionSource;
cmSystemTools::ConvertToUnixSlashes(source);
// If file is in source tree use its relative location.
- if(cmSystemTools::FileIsFullPath(this->SourceDir.c_str()) &&
- cmSystemTools::FileIsFullPath(source.c_str()) &&
- cmSystemTools::IsSubDirectory(source.c_str(),
- this->SourceDir.c_str()))
- {
- source = cmSystemTools::RelativePath(this->SourceDir.c_str(),
- source.c_str());
- }
-
- fxml << "\t\t\t<SourceFile>"
- << cmXMLSafe(source)
- << "</SourceFile>\n";
+ if (cmSystemTools::FileIsFullPath(this->SourceDir.c_str()) &&
+ cmSystemTools::FileIsFullPath(source.c_str()) &&
+ cmSystemTools::IsSubDirectory(source, this->SourceDir)) {
+ source =
+ cmSystemTools::RelativePath(this->SourceDir.c_str(), source.c_str());
}
+ xml.Element("SourceFile", source);
+ }
+
// OutputFile
- if(!this->OptionOutput.empty())
- {
- fxml << "\t\t\t<OutputFile>"
- << cmXMLSafe(this->OptionOutput)
- << "</OutputFile>\n";
- }
+ if (!this->OptionOutput.empty()) {
+ xml.Element("OutputFile", this->OptionOutput);
+ }
// OutputType
- const char* outputType = 0;
- if(!this->OptionTargetType.empty())
- {
- if(this->OptionTargetType == "EXECUTABLE")
- {
+ const char* outputType = CM_NULLPTR;
+ if (!this->OptionTargetType.empty()) {
+ if (this->OptionTargetType == "EXECUTABLE") {
outputType = "executable";
- }
- else if(this->OptionTargetType == "SHARED_LIBRARY")
- {
+ } else if (this->OptionTargetType == "SHARED_LIBRARY") {
outputType = "shared library";
- }
- else if(this->OptionTargetType == "MODULE_LIBRARY")
- {
+ } else if (this->OptionTargetType == "MODULE_LIBRARY") {
outputType = "module library";
- }
- else if(this->OptionTargetType == "STATIC_LIBRARY")
- {
+ } else if (this->OptionTargetType == "STATIC_LIBRARY") {
outputType = "static library";
- }
}
- else if(!this->OptionSource.empty())
- {
+ } else if (!this->OptionSource.empty()) {
outputType = "object file";
- }
- if(outputType)
- {
- fxml << "\t\t\t<OutputType>"
- << cmXMLSafe(outputType)
- << "</OutputType>\n";
- }
+ }
+ if (outputType) {
+ xml.Element("OutputType", outputType);
+ }
- fxml << "\t\t</Action>\n";
+ xml.EndElement(); // Action
}
-//----------------------------------------------------------------------------
-void cmCTestLaunch::WriteXMLCommand(std::ostream& fxml)
+void cmCTestLaunch::WriteXMLCommand(cmXMLWriter& xml)
{
- fxml << "\n";
- fxml << "\t\t<!-- Details of command -->\n";
- fxml << "\t\t<Command>\n";
- if(!this->CWD.empty())
- {
- fxml << "\t\t\t<WorkingDirectory>"
- << cmXMLSafe(this->CWD)
- << "</WorkingDirectory>\n";
- }
- for(std::vector<std::string>::const_iterator ai = this->RealArgs.begin();
- ai != this->RealArgs.end(); ++ai)
- {
- fxml << "\t\t\t<Argument>"
- << cmXMLSafe(ai->c_str())
- << "</Argument>\n";
- }
- fxml << "\t\t</Command>\n";
+ xml.Comment("Details of command");
+ xml.StartElement("Command");
+ if (!this->CWD.empty()) {
+ xml.Element("WorkingDirectory", this->CWD);
+ }
+ for (std::vector<std::string>::const_iterator ai = this->RealArgs.begin();
+ ai != this->RealArgs.end(); ++ai) {
+ xml.Element("Argument", *ai);
+ }
+ xml.EndElement(); // Command
}
-//----------------------------------------------------------------------------
-void cmCTestLaunch::WriteXMLResult(std::ostream& fxml)
+void cmCTestLaunch::WriteXMLResult(cmXMLWriter& xml)
{
- fxml << "\n";
- fxml << "\t\t<!-- Result of command -->\n";
- fxml << "\t\t<Result>\n";
+ xml.Comment("Result of command");
+ xml.StartElement("Result");
// StdOut
- fxml << "\t\t\t<StdOut>";
- this->DumpFileToXML(fxml, this->LogOut);
- fxml << "</StdOut>\n";
+ xml.StartElement("StdOut");
+ this->DumpFileToXML(xml, this->LogOut);
+ xml.EndElement(); // StdOut
// StdErr
- fxml << "\t\t\t<StdErr>";
- this->DumpFileToXML(fxml, this->LogErr);
- fxml << "</StdErr>\n";
+ xml.StartElement("StdErr");
+ this->DumpFileToXML(xml, this->LogErr);
+ xml.EndElement(); // StdErr
// ExitCondition
- fxml << "\t\t\t<ExitCondition>";
+ xml.StartElement("ExitCondition");
cmsysProcess* cp = this->Process;
- switch (cmsysProcess_GetState(cp))
- {
+ switch (cmsysProcess_GetState(cp)) {
case cmsysProcess_State_Starting:
- fxml << "No process has been executed"; break;
+ xml.Content("No process has been executed");
+ break;
case cmsysProcess_State_Executing:
- fxml << "The process is still executing"; break;
+ xml.Content("The process is still executing");
+ break;
case cmsysProcess_State_Disowned:
- fxml << "Disowned"; break;
+ xml.Content("Disowned");
+ break;
case cmsysProcess_State_Killed:
- fxml << "Killed by parent"; break;
+ xml.Content("Killed by parent");
+ break;
case cmsysProcess_State_Expired:
- fxml << "Killed when timeout expired"; break;
+ xml.Content("Killed when timeout expired");
+ break;
case cmsysProcess_State_Exited:
- fxml << this->ExitCode; break;
+ xml.Content(this->ExitCode);
+ break;
case cmsysProcess_State_Exception:
- fxml << "Terminated abnormally: "
- << cmXMLSafe(cmsysProcess_GetExceptionString(cp)); break;
+ xml.Content("Terminated abnormally: ");
+ xml.Content(cmsysProcess_GetExceptionString(cp));
+ break;
case cmsysProcess_State_Error:
- fxml << "Error administrating child process: "
- << cmXMLSafe(cmsysProcess_GetErrorString(cp)); break;
- };
- fxml << "</ExitCondition>\n";
+ xml.Content("Error administrating child process: ");
+ xml.Content(cmsysProcess_GetErrorString(cp));
+ break;
+ };
+ xml.EndElement(); // ExitCondition
- fxml << "\t\t</Result>\n";
+ xml.EndElement(); // Result
}
-//----------------------------------------------------------------------------
-void cmCTestLaunch::WriteXMLLabels(std::ostream& fxml)
+void cmCTestLaunch::WriteXMLLabels(cmXMLWriter& xml)
{
this->LoadLabels();
- if(!this->Labels.empty())
- {
- fxml << "\n";
- fxml << "\t\t<!-- Interested parties -->\n";
- fxml << "\t\t<Labels>\n";
- for(std::set<cmStdString>::const_iterator li = this->Labels.begin();
- li != this->Labels.end(); ++li)
- {
- fxml << "\t\t\t<Label>" << cmXMLSafe(*li) << "</Label>\n";
- }
- fxml << "\t\t</Labels>\n";
- }
+ if (!this->Labels.empty()) {
+ xml.Comment("Interested parties");
+ xml.StartElement("Labels");
+ for (std::set<std::string>::const_iterator li = this->Labels.begin();
+ li != this->Labels.end(); ++li) {
+ xml.Element("Label", *li);
+ }
+ xml.EndElement(); // Labels
+ }
}
-//----------------------------------------------------------------------------
-void cmCTestLaunch::DumpFileToXML(std::ostream& fxml,
- std::string const& fname)
+void cmCTestLaunch::DumpFileToXML(cmXMLWriter& xml, 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))
- {
- fxml << sep << cmXMLSafe(line).Quotes(false);
- sep = "\n";
+
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (MatchesFilterPrefix(line)) {
+ continue;
}
+
+ xml.Content(sep);
+ xml.Content(line);
+ sep = "\n";
+ }
}
-//----------------------------------------------------------------------------
bool cmCTestLaunch::CheckResults()
{
// Skip XML in passthru mode.
- if(this->Passthru)
- {
+ if (this->Passthru) {
return true;
- }
+ }
// We always report failure for error conditions.
- if(this->IsError())
- {
+ if (this->IsError()) {
return false;
- }
+ }
// Scrape the output logs to look for warnings.
- if((this->HaveErr && this->ScrapeLog(this->LogErr)) ||
- (this->HaveOut && this->ScrapeLog(this->LogOut)))
- {
+ if ((this->HaveErr && this->ScrapeLog(this->LogErr)) ||
+ (this->HaveOut && this->ScrapeLog(this->LogOut))) {
return false;
- }
+ }
return true;
}
-//----------------------------------------------------------------------------
void cmCTestLaunch::LoadScrapeRules()
{
- if(this->ScrapeRulesLoaded)
- {
+ if (this->ScrapeRulesLoaded) {
return;
- }
+ }
this->ScrapeRulesLoaded = true;
// Common compiler warning formats. These are much simpler than the
@@ -625,95 +554,86 @@ void cmCTestLaunch::LoadScrapeRules()
this->LoadScrapeRules("WarningSuppress", this->RegexWarningSuppress);
}
-//----------------------------------------------------------------------------
-void
-cmCTestLaunch
-::LoadScrapeRules(const char* purpose,
- std::vector<cmsys::RegularExpression>& regexps)
+void cmCTestLaunch::LoadScrapeRules(
+ const char* purpose, std::vector<cmsys::RegularExpression>& regexps)
{
std::string fname = this->LogDir;
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))
- {
- if(rex.compile(line.c_str()))
- {
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (rex.compile(line.c_str())) {
regexps.push_back(rex);
- }
}
+ }
}
-//----------------------------------------------------------------------------
bool cmCTestLaunch::ScrapeLog(std::string const& fname)
{
this->LoadScrapeRules();
// 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))
- {
- if(this->Match(line.c_str(), this->RegexWarning) &&
- !this->Match(line.c_str(), this->RegexWarningSuppress))
- {
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ if (MatchesFilterPrefix(line)) {
+ continue;
+ }
+
+ if (this->Match(line, this->RegexWarning) &&
+ !this->Match(line, this->RegexWarningSuppress)) {
return true;
- }
}
+ }
return false;
}
-//----------------------------------------------------------------------------
bool cmCTestLaunch::Match(std::string const& line,
std::vector<cmsys::RegularExpression>& regexps)
{
- for(std::vector<cmsys::RegularExpression>::iterator ri = regexps.begin();
- ri != regexps.end(); ++ri)
- {
- if(ri->find(line.c_str()))
- {
+ for (std::vector<cmsys::RegularExpression>::iterator ri = regexps.begin();
+ ri != regexps.end(); ++ri) {
+ if (ri->find(line.c_str())) {
return true;
- }
}
+ }
return false;
}
-//----------------------------------------------------------------------------
+bool cmCTestLaunch::MatchesFilterPrefix(std::string const& line) const
+{
+ return !this->OptionFilterPrefix.empty() &&
+ cmSystemTools::StringStartsWith(line, this->OptionFilterPrefix.c_str());
+}
+
int cmCTestLaunch::Main(int argc, const char* const argv[])
{
- if(argc == 2)
- {
+ if (argc == 2) {
std::cerr << "ctest --launch: this mode is for internal CTest use only"
<< std::endl;
return 1;
- }
+ }
cmCTestLaunch self(argc, argv);
return self.Run();
}
-//----------------------------------------------------------------------------
-#include "cmGlobalGenerator.h"
-#include "cmLocalGenerator.h"
-#include "cmMakefile.h"
-#include "cmake.h"
-#include <cmsys/auto_ptr.hxx>
void cmCTestLaunch::LoadConfig()
{
- cmake cm;
- cmGlobalGenerator gg;
- gg.SetCMakeInstance(&cm);
- cmsys::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator());
- cmMakefile* mf = lg->GetMakefile();
+ cmake cm(cmake::RoleScript);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator gg(&cm);
+ CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(&gg, cm.GetCurrentSnapshot()));
std::string fname = this->LogDir;
fname += "CTestLaunchConfig.cmake";
- if(cmSystemTools::FileExists(fname.c_str()) &&
- mf->ReadListFile(0, fname.c_str()))
- {
+ if (cmSystemTools::FileExists(fname.c_str()) &&
+ mf->ReadListFile(fname.c_str())) {
this->SourceDir = mf->GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
cmSystemTools::ConvertToUnixSlashes(this->SourceDir);
- }
+ }
}
diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h
index 7457e8357..29986ff60 100644
--- a/Source/CTest/cmCTestLaunch.h
+++ b/Source/CTest/cmCTestLaunch.h
@@ -1,19 +1,16 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestLaunch_h
#define cmCTestLaunch_h
-#include "cmStandardIncludes.h"
-#include <cmsys/RegularExpression.hxx>
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmsys/RegularExpression.hxx"
+#include <set>
+#include <string>
+#include <vector>
+
+class cmXMLWriter;
/** \class cmCTestLaunch
* \brief Launcher for make rules to report results for ctest
@@ -25,6 +22,7 @@ class cmCTestLaunch
public:
/** Entry point from ctest executable main(). */
static int Main(int argc, const char* const argv[]);
+
private:
// Initialize the launcher from its command line.
cmCTestLaunch(int argc, const char* const* argv);
@@ -45,6 +43,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.
@@ -72,10 +71,9 @@ private:
bool HaveErr;
// Labels associated with the build rule.
- std::set<cmStdString> Labels;
+ std::set<std::string> Labels;
void LoadLabels();
- bool SourceMatches(std::string const& lhs,
- std::string const& rhs);
+ bool SourceMatches(std::string const& lhs, std::string const& rhs);
// Regular expressions to match warnings and their exceptions.
bool ScrapeRulesLoaded;
@@ -87,14 +85,15 @@ private:
bool ScrapeLog(std::string const& fname);
bool Match(std::string const& line,
std::vector<cmsys::RegularExpression>& regexps);
+ bool MatchesFilterPrefix(std::string const& line) const;
// Methods to generate the xml fragment.
void WriteXML();
- void WriteXMLAction(std::ostream& fxml);
- void WriteXMLCommand(std::ostream& fxml);
- void WriteXMLResult(std::ostream& fxml);
- void WriteXMLLabels(std::ostream& fxml);
- void DumpFileToXML(std::ostream& fxml, std::string const& fname);
+ void WriteXMLAction(cmXMLWriter& xml);
+ void WriteXMLCommand(cmXMLWriter& xml);
+ void WriteXMLResult(cmXMLWriter& xml);
+ void WriteXMLLabels(cmXMLWriter& xml);
+ void DumpFileToXML(cmXMLWriter& xml, std::string const& fname);
// Configuration
void LoadConfig();
diff --git a/Source/CTest/cmCTestMemCheckCommand.cxx b/Source/CTest/cmCTestMemCheckCommand.cxx
index 535c9934f..b9cae3bfe 100644
--- a/Source/CTest/cmCTestMemCheckCommand.cxx
+++ b/Source/CTest/cmCTestMemCheckCommand.cxx
@@ -1,32 +1,54 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestMemCheckCommand.h"
+#include <sstream>
+#include <string>
+#include <vector>
+
#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
+#include "cmCTestMemCheckHandler.h"
+#include "cmMakefile.h"
+cmCTestMemCheckCommand::cmCTestMemCheckCommand()
+{
+ this->Arguments[ctm_DEFECT_COUNT] = "DEFECT_COUNT";
+ this->Arguments[ctm_LAST] = CM_NULLPTR;
+ this->Last = ctm_LAST;
+}
cmCTestGenericHandler* cmCTestMemCheckCommand::InitializeActualHandler()
{
- cmCTestGenericHandler* handler
- = this->CTest->GetInitializedHandler("memcheck");
-
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "MemoryCheckCommand", "CTEST_MEMORYCHECK_COMMAND");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "MemoryCheckCommandOptions", "CTEST_MEMORYCHECK_COMMAND_OPTIONS");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "MemoryCheckSuppressionFile", "CTEST_MEMORYCHECK_SUPPRESSIONS_FILE");
-
+ cmCTestGenericHandler* handler =
+ this->CTest->GetInitializedHandler("memcheck");
+
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckType", "CTEST_MEMORYCHECK_TYPE", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckSanitizerOptions",
+ "CTEST_MEMORYCHECK_SANITIZER_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckCommand", "CTEST_MEMORYCHECK_COMMAND",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckCommandOptions",
+ "CTEST_MEMORYCHECK_COMMAND_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "MemoryCheckSuppressionFile",
+ "CTEST_MEMORYCHECK_SUPPRESSIONS_FILE", this->Quiet);
+
+ handler->SetQuiet(this->Quiet);
return handler;
}
+void cmCTestMemCheckCommand::ProcessAdditionalValues(
+ cmCTestGenericHandler* handler)
+{
+ if (this->Values[ctm_DEFECT_COUNT] && *this->Values[ctm_DEFECT_COUNT]) {
+ std::ostringstream str;
+ str << static_cast<cmCTestMemCheckHandler*>(handler)->GetDefectCount();
+ this->Makefile->AddDefinition(this->Values[ctm_DEFECT_COUNT],
+ str.str().c_str());
+ }
+}
diff --git a/Source/CTest/cmCTestMemCheckCommand.h b/Source/CTest/cmCTestMemCheckCommand.h
index 6db47aec8..fa595594a 100644
--- a/Source/CTest/cmCTestMemCheckCommand.h
+++ b/Source/CTest/cmCTestMemCheckCommand.h
@@ -1,20 +1,14 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestMemCheckCommand_h
#define cmCTestMemCheckCommand_h
+#include "cmConfigure.h"
+
#include "cmCTestTestCommand.h"
class cmCTestGenericHandler;
+class cmCommand;
/** \class cmCTestMemCheck
* \brief Run a ctest script
@@ -24,65 +18,29 @@ class cmCTestGenericHandler;
class cmCTestMemCheckCommand : public cmCTestTestCommand
{
public:
-
- cmCTestMemCheckCommand() {}
+ cmCTestMemCheckCommand();
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestMemCheckCommand* ni = new cmCTestMemCheckCommand;
ni->CTest = this->CTest;
ni->CTestScriptHandler = this->CTestScriptHandler;
return ni;
- }
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- 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;
- }
+protected:
+ cmCTestGenericHandler* InitializeActualHandler() CM_OVERRIDE;
- cmTypeMacro(cmCTestMemCheckCommand, cmCTestTestCommand);
+ void ProcessAdditionalValues(cmCTestGenericHandler* handler) CM_OVERRIDE;
-protected:
- cmCTestGenericHandler* InitializeActualHandler();
+ enum
+ {
+ ctm_DEFECT_COUNT = ctt_LAST,
+ ctm_LAST
+ };
};
-
#endif
-
diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx
index 3ae2ac6a7..c35f0bc70 100644
--- a/Source/CTest/cmCTestMemCheckHandler.cxx
+++ b/Source/CTest/cmCTestMemCheckHandler.cxx
@@ -1,29 +1,18 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestMemCheckHandler.h"
-#include "cmXMLParser.h"
+
#include "cmCTest.h"
-#include "cmake.h"
-#include "cmGeneratedFileStream.h"
-#include <cmsys/Process.h>
-#include <cmsys/RegularExpression.hxx>
-#include <cmsys/Base64.h>
-#include "cmMakefile.h"
-#include "cmXMLSafe.h"
-
-#include <stdlib.h>
-#include <math.h>
-#include <float.h>
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include "cmXMLWriter.h"
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+#include "cmsys/RegularExpression.hxx"
+#include <iostream>
+#include <sstream>
+#include <string.h>
struct CatToErrorType
{
@@ -31,172 +20,106 @@ struct CatToErrorType
int ErrorCode;
};
-
static CatToErrorType cmCTestMemCheckBoundsChecker[] = {
// Error tags
- {"Write Overrun", cmCTestMemCheckHandler::ABW},
- {"Read Overrun", cmCTestMemCheckHandler::ABR},
- {"Memory Overrun", cmCTestMemCheckHandler::ABW},
- {"Allocation Conflict", cmCTestMemCheckHandler::FMM},
- {"Bad Pointer Use", cmCTestMemCheckHandler::FMW},
- {"Dangling Pointer", cmCTestMemCheckHandler::FMR},
- {0,0}
+ { "Write Overrun", cmCTestMemCheckHandler::ABW },
+ { "Read Overrun", cmCTestMemCheckHandler::ABR },
+ { "Memory Overrun", cmCTestMemCheckHandler::ABW },
+ { "Allocation Conflict", cmCTestMemCheckHandler::FMM },
+ { "Bad Pointer Use", cmCTestMemCheckHandler::FMW },
+ { "Dangling Pointer", cmCTestMemCheckHandler::FMR },
+ { CM_NULLPTR, 0 }
};
+static void xmlReportError(int line, const char* msg, void* data)
+{
+ cmCTest* ctest = (cmCTest*)data;
+ cmCTestLog(ctest, ERROR_MESSAGE, "Error parsing XML in stream at line "
+ << line << ": " << msg << std::endl);
+}
+
// parse the xml file containing the results of last BoundsChecker run
class cmBoundsCheckerParser : public cmXMLParser
{
public:
- cmBoundsCheckerParser(cmCTest* c) { this->CTest = c;}
- void StartElement(const char* name, const char** atts)
- {
- if(strcmp(name, "MemoryLeak") == 0)
- {
- this->Errors.push_back(cmCTestMemCheckHandler::MLK);
- }
- if(strcmp(name, "ResourceLeak") == 0)
- {
- this->Errors.push_back(cmCTestMemCheckHandler::MLK);
- }
- if(strcmp(name, "Error") == 0)
- {
- this->ParseError(atts);
- }
- if(strcmp(name, "Dangling Pointer") == 0)
- {
- this->ParseError(atts);
- }
- // Create the log
- cmOStringStream ostr;
- ostr << name << ":\n";
- int i = 0;
- for(; atts[i] != 0; i+=2)
- {
- ostr << " " << cmXMLSafe(atts[i])
- << " - " << cmXMLSafe(atts[i+1]) << "\n";
- }
- ostr << "\n";
- this->Log += ostr.str();
+ cmBoundsCheckerParser(cmCTest* c)
+ {
+ this->CTest = c;
+ this->SetErrorCallback(xmlReportError, (void*)c);
+ }
+ void StartElement(const std::string& name, const char** atts) CM_OVERRIDE
+ {
+ if (name == "MemoryLeak" || name == "ResourceLeak") {
+ this->Errors.push_back(cmCTestMemCheckHandler::MLK);
+ } else if (name == "Error" || name == "Dangling Pointer") {
+ this->ParseError(atts);
}
- void EndElement(const char* )
- {
+ // Create the log
+ std::ostringstream ostr;
+ ostr << name << ":\n";
+ int i = 0;
+ for (; atts[i] != CM_NULLPTR; i += 2) {
+ ostr << " " << atts[i] << " - " << atts[i + 1] << "\n";
}
+ ostr << "\n";
+ this->Log += ostr.str();
+ }
+ void EndElement(const std::string& /*name*/) CM_OVERRIDE {}
const char* GetAttribute(const char* name, const char** atts)
- {
- int i = 0;
- for(; atts[i] != 0; ++i)
- {
- if(strcmp(name, atts[i]) == 0)
- {
- return atts[i+1];
- }
- }
- return 0;
+ {
+ int i = 0;
+ for (; atts[i] != CM_NULLPTR; ++i) {
+ if (strcmp(name, atts[i]) == 0) {
+ return atts[i + 1];
+ }
}
+ return CM_NULLPTR;
+ }
void ParseError(const char** atts)
- {
- CatToErrorType* ptr = cmCTestMemCheckBoundsChecker;
- const char* cat = this->GetAttribute("ErrorCategory", atts);
- if(!cat)
- {
- this->Errors.push_back(cmCTestMemCheckHandler::ABW); // do not know
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "No Category found in Bounds checker XML\n" );
- return;
- }
- while(ptr->ErrorCategory && cat)
- {
- if(strcmp(ptr->ErrorCategory, cat) == 0)
- {
- this->Errors.push_back(ptr->ErrorCode);
- return; // found it we are done
- }
- ptr++;
- }
- if(ptr->ErrorCategory)
- {
- this->Errors.push_back(cmCTestMemCheckHandler::ABW); // do not know
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Found unknown Bounds Checker error "
- << ptr->ErrorCategory << std::endl);
- }
+ {
+ CatToErrorType* ptr = cmCTestMemCheckBoundsChecker;
+ const char* cat = this->GetAttribute("ErrorCategory", atts);
+ if (!cat) {
+ this->Errors.push_back(cmCTestMemCheckHandler::ABW); // do not know
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "No Category found in Bounds checker XML\n");
+ return;
+ }
+ while (ptr->ErrorCategory && cat) {
+ if (strcmp(ptr->ErrorCategory, cat) == 0) {
+ this->Errors.push_back(ptr->ErrorCode);
+ return; // found it we are done
+ }
+ ptr++;
+ }
+ if (ptr->ErrorCategory) {
+ this->Errors.push_back(cmCTestMemCheckHandler::ABW); // do not know
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Found unknown Bounds Checker error " << ptr->ErrorCategory
+ << std::endl);
}
+ }
cmCTest* CTest;
std::vector<int> Errors;
std::string Log;
};
-#define BOUNDS_CHECKER_MARKER \
-"******######*****Begin BOUNDS CHECKER XML******######******"
-//----------------------------------------------------------------------
-static const char* cmCTestMemCheckResultStrings[] = {
- "ABR",
- "ABW",
- "ABWL",
- "COR",
- "EXU",
- "FFM",
- "FIM",
- "FMM",
- "FMR",
- "FMW",
- "FUM",
- "IPR",
- "IPW",
- "MAF",
- "MLK",
- "MPK",
- "NPR",
- "ODS",
- "PAR",
- "PLK",
- "UMC",
- "UMR",
- 0
-};
-
-
-//----------------------------------------------------------------------
-static const char* cmCTestMemCheckResultLongStrings[] = {
- "Threading Problem",
- "ABW",
- "ABWL",
- "COR",
- "EXU",
- "FFM",
- "FIM",
- "Mismatched deallocation",
- "FMR",
- "FMW",
- "FUM",
- "IPR",
- "IPW",
- "MAF",
- "Memory Leak",
- "Potential Memory Leak",
- "NPR",
- "ODS",
- "Invalid syscall param",
- "PLK",
- "Uninitialized Memory Conditional",
- "Uninitialized Memory Read",
- 0
-};
-
+#define BOUNDS_CHECKER_MARKER \
+ "******######*****Begin BOUNDS CHECKER XML******######******"
-//----------------------------------------------------------------------
cmCTestMemCheckHandler::cmCTestMemCheckHandler()
{
this->MemCheck = true;
this->CustomMaximumPassedTestOutputSize = 0;
this->CustomMaximumFailedTestOutputSize = 0;
+ this->LogWithPID = false;
}
-//----------------------------------------------------------------------
void cmCTestMemCheckHandler::Initialize()
{
this->Superclass::Initialize();
+ this->LogWithPID = false;
this->CustomMaximumPassedTestOutputSize = 0;
this->CustomMaximumFailedTestOutputSize = 0;
this->MemoryTester = "";
@@ -204,353 +127,452 @@ void cmCTestMemCheckHandler::Initialize()
this->MemoryTesterOptions.clear();
this->MemoryTesterStyle = UNKNOWN;
this->MemoryTesterOutputFile = "";
- int cc;
- for ( cc = 0; cc < NO_MEMORY_FAULT; cc ++ )
- {
- this->MemoryTesterGlobalResults[cc] = 0;
- }
-
+ this->DefectCount = 0;
}
-//----------------------------------------------------------------------
int cmCTestMemCheckHandler::PreProcessHandler()
{
- if ( !this->InitializeMemoryChecking() )
- {
+ if (!this->InitializeMemoryChecking()) {
return 0;
- }
+ }
- if ( !this->ExecuteCommands(this->CustomPreMemCheck) )
- {
+ if (!this->ExecuteCommands(this->CustomPreMemCheck)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Problem executing pre-memcheck command(s)." << std::endl);
+ "Problem executing pre-memcheck command(s)." << std::endl);
return 0;
- }
+ }
return 1;
}
-//----------------------------------------------------------------------
int cmCTestMemCheckHandler::PostProcessHandler()
{
- if ( !this->ExecuteCommands(this->CustomPostMemCheck) )
- {
+ if (!this->ExecuteCommands(this->CustomPostMemCheck)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Problem executing post-memcheck command(s)." << std::endl);
+ "Problem executing post-memcheck command(s)." << std::endl);
return 0;
- }
+ }
return 1;
}
-//----------------------------------------------------------------------
void cmCTestMemCheckHandler::GenerateTestCommand(
std::vector<std::string>& args, int test)
{
- std::vector<cmStdString>::size_type pp;
- cmStdString index;
- cmOStringStream stream;
- std::string memcheckcommand
- = cmSystemTools::ConvertToOutputPath(this->MemoryTester.c_str());
+ std::vector<std::string>::size_type pp;
+ std::string index;
+ std::ostringstream stream;
+ std::string memcheckcommand =
+ cmSystemTools::ConvertToOutputPath(this->MemoryTester.c_str());
stream << test;
index = stream.str();
- for ( pp = 0; pp < this->MemoryTesterDynamicOptions.size(); pp ++ )
- {
- cmStdString arg = this->MemoryTesterDynamicOptions[pp];
- cmStdString::size_type pos = arg.find("??");
- if (pos != cmStdString::npos)
- {
+ for (pp = 0; pp < this->MemoryTesterDynamicOptions.size(); pp++) {
+ std::string arg = this->MemoryTesterDynamicOptions[pp];
+ std::string::size_type pos = arg.find("??");
+ if (pos != std::string::npos) {
arg.replace(pos, 2, index);
- }
+ }
args.push_back(arg);
memcheckcommand += " \"";
memcheckcommand += arg;
memcheckcommand += "\"";
+ }
+ // Create a copy of the memory tester environment variable.
+ // This is used for memory testing programs that pass options
+ // via environment varaibles.
+ std::string memTesterEnvironmentVariable =
+ this->MemoryTesterEnvironmentVariable;
+ for (pp = 0; pp < this->MemoryTesterOptions.size(); pp++) {
+ if (!memTesterEnvironmentVariable.empty()) {
+ // If we are using env to pass options, append all the options to
+ // this string with space separation.
+ memTesterEnvironmentVariable += " " + this->MemoryTesterOptions[pp];
}
- for ( pp = 0; pp < this->MemoryTesterOptions.size(); pp ++ )
- {
- args.push_back(this->MemoryTesterOptions[pp]);
- memcheckcommand += " \"";
- memcheckcommand += this->MemoryTesterOptions[pp];
- memcheckcommand += "\"";
+ // for regular options just add them to args and memcheckcommand
+ // which is just used for display
+ else {
+ args.push_back(this->MemoryTesterOptions[pp]);
+ memcheckcommand += " \"";
+ memcheckcommand += this->MemoryTesterOptions[pp];
+ memcheckcommand += "\"";
+ }
+ }
+ // if this is an env option type, then add the env string as a single
+ // argument.
+ if (!memTesterEnvironmentVariable.empty()) {
+ std::string::size_type pos = memTesterEnvironmentVariable.find("??");
+ if (pos != std::string::npos) {
+ memTesterEnvironmentVariable.replace(pos, 2, index);
}
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Memory check command: "
- << memcheckcommand << std::endl);
+ memcheckcommand += " " + memTesterEnvironmentVariable;
+ args.push_back(memTesterEnvironmentVariable);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Memory check command: " << memcheckcommand << std::endl,
+ this->Quiet);
+}
+
+void cmCTestMemCheckHandler::InitializeResultsVectors()
+{
+ // fill these members
+ // cmsys::vector<std::string> ResultStrings;
+ // cmsys::vector<std::string> ResultStringsLong;
+ // cmsys::vector<int> GlobalResults;
+ this->ResultStringsLong.clear();
+ this->ResultStrings.clear();
+ this->GlobalResults.clear();
+ // If we are working with style checkers that dynamically fill
+ // the results strings then return.
+ if (this->MemoryTesterStyle > cmCTestMemCheckHandler::BOUNDS_CHECKER) {
+ return;
+ }
+
+ // define the standard set of errors
+ //----------------------------------------------------------------------
+ static const char* cmCTestMemCheckResultStrings[] = {
+ "ABR", "ABW", "ABWL", "COR", "EXU", "FFM", "FIM", "FMM",
+ "FMR", "FMW", "FUM", "IPR", "IPW", "MAF", "MLK", "MPK",
+ "NPR", "ODS", "PAR", "PLK", "UMC", "UMR", CM_NULLPTR
+ };
+ static const char* cmCTestMemCheckResultLongStrings[] = {
+ "Threading Problem",
+ "ABW",
+ "ABWL",
+ "COR",
+ "EXU",
+ "FFM",
+ "FIM",
+ "Mismatched deallocation",
+ "FMR",
+ "FMW",
+ "FUM",
+ "IPR",
+ "IPW",
+ "MAF",
+ "Memory Leak",
+ "Potential Memory Leak",
+ "NPR",
+ "ODS",
+ "Invalid syscall param",
+ "PLK",
+ "Uninitialized Memory Conditional",
+ "Uninitialized Memory Read",
+ CM_NULLPTR
+ };
+ this->GlobalResults.clear();
+ for (int i = 0; cmCTestMemCheckResultStrings[i] != CM_NULLPTR; ++i) {
+ this->ResultStrings.push_back(cmCTestMemCheckResultStrings[i]);
+ this->ResultStringsLong.push_back(cmCTestMemCheckResultLongStrings[i]);
+ this->GlobalResults.push_back(0);
+ }
}
-//----------------------------------------------------------------------
-void cmCTestMemCheckHandler::PopulateCustomVectors(cmMakefile *mf)
+void cmCTestMemCheckHandler::PopulateCustomVectors(cmMakefile* mf)
{
this->cmCTestTestHandler::PopulateCustomVectors(mf);
this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_PRE_MEMCHECK",
- this->CustomPreMemCheck);
+ this->CustomPreMemCheck);
this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_POST_MEMCHECK",
- this->CustomPostMemCheck);
+ this->CustomPostMemCheck);
- this->CTest->PopulateCustomVector(mf,
- "CTEST_CUSTOM_MEMCHECK_IGNORE",
- this->CustomTestsIgnore);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_MEMCHECK_IGNORE",
+ this->CustomTestsIgnore);
+ std::string cmake = cmSystemTools::GetCMakeCommand();
+ this->CTest->SetCTestConfiguration("CMakeCommand", cmake.c_str(),
+ this->Quiet);
}
-//----------------------------------------------------------------------
-void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
+int cmCTestMemCheckHandler::GetDefectCount()
{
- if ( !this->CTest->GetProduceXML() )
- {
- return;
- }
+ return this->DefectCount;
+}
- this->CTest->StartXML(os, this->AppendXML);
- os << "<DynamicAnalysis Checker=\"";
- switch ( this->MemoryTesterStyle )
- {
+void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml)
+{
+ if (!this->CTest->GetProduceXML()) {
+ return;
+ }
+ this->CTest->StartXML(xml, this->AppendXML);
+ xml.StartElement("DynamicAnalysis");
+ switch (this->MemoryTesterStyle) {
case cmCTestMemCheckHandler::VALGRIND:
- os << "Valgrind";
+ xml.Attribute("Checker", "Valgrind");
break;
case cmCTestMemCheckHandler::PURIFY:
- os << "Purify";
+ xml.Attribute("Checker", "Purify");
break;
case cmCTestMemCheckHandler::BOUNDS_CHECKER:
- os << "BoundsChecker";
+ xml.Attribute("Checker", "BoundsChecker");
+ break;
+ case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
+ xml.Attribute("Checker", "AddressSanitizer");
+ break;
+ case cmCTestMemCheckHandler::LEAK_SANITIZER:
+ xml.Attribute("Checker", "LeakSanitizer");
+ break;
+ case cmCTestMemCheckHandler::THREAD_SANITIZER:
+ xml.Attribute("Checker", "ThreadSanitizer");
+ break;
+ case cmCTestMemCheckHandler::MEMORY_SANITIZER:
+ xml.Attribute("Checker", "MemorySanitizer");
+ break;
+ case cmCTestMemCheckHandler::UB_SANITIZER:
+ xml.Attribute("Checker", "UndefinedBehaviorSanitizer");
break;
default:
- os << "Unknown";
- }
- os << "\">" << std::endl;
+ xml.Attribute("Checker", "Unknown");
+ }
- os << "\t<StartDateTime>" << this->StartTest << "</StartDateTime>\n"
- << "\t<StartTestTime>" << this->StartTestTime << "</StartTestTime>\n"
- << "\t<TestList>\n";
+ xml.Element("StartDateTime", this->StartTest);
+ xml.Element("StartTestTime", this->StartTestTime);
+ xml.StartElement("TestList");
cmCTestMemCheckHandler::TestResultsVector::size_type cc;
- for ( cc = 0; cc < this->TestResults.size(); cc ++ )
- {
- cmCTestTestResult *result = &this->TestResults[cc];
+ for (cc = 0; cc < this->TestResults.size(); cc++) {
+ cmCTestTestResult* result = &this->TestResults[cc];
std::string testPath = result->Path + "/" + result->Name;
- os << "\t\t<Test>" << cmXMLSafe(
- this->CTest->GetShortPathToFile(testPath.c_str()))
- << "</Test>" << std::endl;
- }
- os << "\t</TestList>\n";
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- "-- Processing memory checking output: ");
+ xml.Element("Test", this->CTest->GetShortPathToFile(testPath.c_str()));
+ }
+ xml.EndElement(); // TestList
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "-- Processing memory checking output:\n", this->Quiet);
size_t total = this->TestResults.size();
- size_t step = total / 10;
- size_t current = 0;
- for ( cc = 0; cc < this->TestResults.size(); cc ++ )
- {
- cmCTestTestResult *result = &this->TestResults[cc];
+ for (cc = 0; cc < this->TestResults.size(); cc++) {
+ cmCTestTestResult* result = &this->TestResults[cc];
std::string memcheckstr;
- int memcheckresults[cmCTestMemCheckHandler::NO_MEMORY_FAULT];
- int kk;
+ std::vector<int> memcheckresults(this->ResultStrings.size(), 0);
bool res = this->ProcessMemCheckOutput(result->Output, memcheckstr,
- memcheckresults);
- if ( res && result->Status == cmCTestMemCheckHandler::COMPLETED )
- {
+ memcheckresults);
+ if (res && result->Status == cmCTestMemCheckHandler::COMPLETED) {
continue;
- }
- this->CleanTestOutput(memcheckstr,
+ }
+ this->CleanTestOutput(
+ memcheckstr,
static_cast<size_t>(this->CustomMaximumFailedTestOutputSize));
- this->WriteTestResultHeader(os, result);
- os << "\t\t<Results>" << std::endl;
- for ( kk = 0; cmCTestMemCheckResultLongStrings[kk]; kk ++ )
- {
- if ( memcheckresults[kk] )
- {
- os << "\t\t\t<Defect type=\"" << cmCTestMemCheckResultLongStrings[kk]
- << "\">"
- << memcheckresults[kk]
- << "</Defect>" << std::endl;
- }
- this->MemoryTesterGlobalResults[kk] += memcheckresults[kk];
+ this->WriteTestResultHeader(xml, result);
+ xml.StartElement("Results");
+ int memoryErrors = 0;
+ for (std::vector<int>::size_type kk = 0; kk < memcheckresults.size();
+ ++kk) {
+ if (memcheckresults[kk]) {
+ xml.StartElement("Defect");
+ xml.Attribute("type", this->ResultStringsLong[kk]);
+ xml.Content(memcheckresults[kk]);
+ memoryErrors += memcheckresults[kk];
+ xml.EndElement(); // Defect
}
-
- std::string logTag;
- if(this->CTest->ShouldCompressMemCheckOutput())
- {
+ this->GlobalResults[kk] += memcheckresults[kk];
+ }
+ xml.EndElement(); // Results
+ if (memoryErrors > 0) {
+ const int maxTestNameWidth = this->CTest->GetMaxTestNameWidth();
+ std::string outname = result->Name + " ";
+ outname.resize(maxTestNameWidth + 4, '.');
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, cc + 1
+ << "/" << total << " MemCheck: #"
+ << result->TestCount << ": " << outname
+ << " Defects: " << memoryErrors << std::endl,
+ this->Quiet);
+ }
+ xml.StartElement("Log");
+ if (this->CTest->ShouldCompressTestOutput()) {
this->CTest->CompressString(memcheckstr);
- logTag = "\t<Log compression=\"gzip\" encoding=\"base64\">\n";
- }
- else
- {
- logTag = "\t<Log>\n";
- }
-
- os
- << "\t\t</Results>\n"
- << logTag << cmXMLSafe(memcheckstr) << std::endl
- << "\t</Log>\n";
- this->WriteTestResultFooter(os, result);
- if ( current < cc )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "#" << std::flush);
- current += step;
- }
+ xml.Attribute("compression", "gzip");
+ xml.Attribute("encoding", "base64");
}
- cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory checking results:"
- << std::endl);
- os << "\t<DefectList>" << std::endl;
- for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
- {
- if ( this->MemoryTesterGlobalResults[cc] )
- {
-#ifdef cerr
-# undef cerr
-#endif
+ xml.Content(memcheckstr);
+ xml.EndElement(); // Log
+
+ this->WriteTestResultFooter(xml, result);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "MemCheck log files can be found here: "
+ "( * corresponds to test number)"
+ << std::endl,
+ this->Quiet);
+ std::string output = this->MemoryTesterOutputFile;
+ cmSystemTools::ReplaceString(output, "??", "*");
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, output << std::endl,
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "Memory checking results:" << std::endl, this->Quiet);
+ xml.StartElement("DefectList");
+ for (cc = 0; cc < this->GlobalResults.size(); cc++) {
+ if (this->GlobalResults[cc]) {
std::cerr.width(35);
-#define cerr no_cerr
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- cmCTestMemCheckResultLongStrings[cc] << " - "
- << this->MemoryTesterGlobalResults[cc] << std::endl);
- os << "\t\t<Defect Type=\"" << cmCTestMemCheckResultLongStrings[cc]
- << "\"/>" << std::endl;
- }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ this->ResultStringsLong[cc]
+ << " - " << this->GlobalResults[cc] << std::endl,
+ this->Quiet);
+ xml.StartElement("Defect");
+ xml.Attribute("Type", this->ResultStringsLong[cc]);
+ xml.EndElement();
}
- os << "\t</DefectList>" << std::endl;
-
- os << "\t<EndDateTime>" << this->EndTest << "</EndDateTime>" << std::endl;
- os << "\t<EndTestTime>" << this->EndTestTime
- << "</EndTestTime>" << std::endl;
- os << "<ElapsedMinutes>"
- << static_cast<int>(this->ElapsedTestingTime/6)/10.0
- << "</ElapsedMinutes>\n";
-
- os << "</DynamicAnalysis>" << std::endl;
- this->CTest->EndXML(os);
+ }
+ xml.EndElement(); // DefectList
+ xml.Element("EndDateTime", this->EndTest);
+ xml.Element("EndTestTime", this->EndTestTime);
+ xml.Element("ElapsedMinutes",
+ static_cast<int>(this->ElapsedTestingTime / 6) / 10.0);
+ xml.EndElement(); // DynamicAnalysis
+ this->CTest->EndXML(xml);
}
-//----------------------------------------------------------------------
bool cmCTestMemCheckHandler::InitializeMemoryChecking()
{
+ this->MemoryTesterEnvironmentVariable = "";
+ this->MemoryTester = "";
// Setup the command
- if ( cmSystemTools::FileExists(this->CTest->GetCTestConfiguration(
- "MemoryCheckCommand").c_str()) )
- {
- this->MemoryTester
- = this->CTest->GetCTestConfiguration("MemoryCheckCommand").c_str();
-
+ if (cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("MemoryCheckCommand").c_str())) {
+ this->MemoryTester =
+ this->CTest->GetCTestConfiguration("MemoryCheckCommand");
+ std::string testerName =
+ cmSystemTools::GetFilenameName(this->MemoryTester);
// determine the checker type
- if ( this->MemoryTester.find("valgrind") != std::string::npos )
- {
- this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
- }
- else if ( this->MemoryTester.find("purify") != std::string::npos )
- {
+ if (testerName.find("valgrind") != std::string::npos ||
+ this->CTest->GetCTestConfiguration("MemoryCheckType") == "Valgrind") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
+ } else if (testerName.find("purify") != std::string::npos) {
this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
- }
- else if ( this->MemoryTester.find("BC") != std::string::npos )
- {
+ } else if (testerName.find("BC") != std::string::npos) {
this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
- }
- else
- {
+ } else {
this->MemoryTesterStyle = cmCTestMemCheckHandler::UNKNOWN;
- }
}
- else if ( cmSystemTools::FileExists(this->CTest->GetCTestConfiguration(
- "PurifyCommand").c_str()) )
- {
- this->MemoryTester
- = this->CTest->GetCTestConfiguration("PurifyCommand").c_str();
+ } else if (cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("PurifyCommand").c_str())) {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("PurifyCommand");
this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
- }
- else if ( cmSystemTools::FileExists(this->CTest->GetCTestConfiguration(
- "ValgrindCommand").c_str()) )
- {
- this->MemoryTester
- = this->CTest->GetCTestConfiguration("ValgrindCommand").c_str();
+ } else if (cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("ValgrindCommand")
+ .c_str())) {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("ValgrindCommand");
this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
- }
- else if ( cmSystemTools::FileExists(this->CTest->GetCTestConfiguration(
- "BoundsCheckerCommand").c_str()) )
- {
- this->MemoryTester
- = this->CTest->GetCTestConfiguration("BoundsCheckerCommand").c_str();
+ } else if (cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("BoundsCheckerCommand")
+ .c_str())) {
+ this->MemoryTester =
+ this->CTest->GetCTestConfiguration("BoundsCheckerCommand");
this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
+ }
+ if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "AddressSanitizer") {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::ADDRESS_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "LeakSanitizer") {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::LEAK_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "ThreadSanitizer") {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::THREAD_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "MemorySanitizer") {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::MEMORY_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+ "UndefinedBehaviorSanitizer") {
+ this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand");
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::UB_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
+ // Check the MemoryCheckType
+ if (this->MemoryTesterStyle == cmCTestMemCheckHandler::UNKNOWN) {
+ std::string checkType =
+ this->CTest->GetCTestConfiguration("MemoryCheckType");
+ if (checkType == "Purify") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
+ } else if (checkType == "BoundsChecker") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
+ } else if (checkType == "Valgrind") {
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
}
- else
- {
- cmCTestLog(this->CTest, WARNING,
- "Memory checker (MemoryCheckCommand) "
- "not set, or cannot find the specified program."
- << std::endl);
+ }
+ if (this->MemoryTester.empty()) {
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "Memory checker (MemoryCheckCommand) "
+ "not set, or cannot find the specified program."
+ << std::endl,
+ this->Quiet);
return false;
- }
+ }
// Setup the options
std::string memoryTesterOptions;
- if ( this->CTest->GetCTestConfiguration(
- "MemoryCheckCommandOptions").size() )
- {
- memoryTesterOptions = this->CTest->GetCTestConfiguration(
- "MemoryCheckCommandOptions");
- }
- else if ( this->CTest->GetCTestConfiguration(
- "ValgrindCommandOptions").size() )
- {
- memoryTesterOptions = this->CTest->GetCTestConfiguration(
- "ValgrindCommandOptions");
- }
- this->MemoryTesterOptions
- = cmSystemTools::ParseArguments(memoryTesterOptions.c_str());
-
- this->MemoryTesterOutputFile
- = this->CTest->GetBinaryDir()
- + "/Testing/Temporary/MemoryChecker.??.log";
-
- switch ( this->MemoryTesterStyle )
- {
- case cmCTestMemCheckHandler::VALGRIND:
- {
- if ( this->MemoryTesterOptions.empty() )
- {
+ if (!this->CTest->GetCTestConfiguration("MemoryCheckCommandOptions")
+ .empty()) {
+ memoryTesterOptions =
+ this->CTest->GetCTestConfiguration("MemoryCheckCommandOptions");
+ } else if (!this->CTest->GetCTestConfiguration("ValgrindCommandOptions")
+ .empty()) {
+ memoryTesterOptions =
+ this->CTest->GetCTestConfiguration("ValgrindCommandOptions");
+ }
+ this->MemoryTesterOptions =
+ cmSystemTools::ParseArguments(memoryTesterOptions.c_str());
+
+ this->MemoryTesterOutputFile =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/MemoryChecker.??.log";
+
+ switch (this->MemoryTesterStyle) {
+ case cmCTestMemCheckHandler::VALGRIND: {
+ if (this->MemoryTesterOptions.empty()) {
this->MemoryTesterOptions.push_back("-q");
this->MemoryTesterOptions.push_back("--tool=memcheck");
this->MemoryTesterOptions.push_back("--leak-check=yes");
this->MemoryTesterOptions.push_back("--show-reachable=yes");
this->MemoryTesterOptions.push_back("--num-callers=50");
- }
- if ( this->CTest->GetCTestConfiguration(
- "MemoryCheckSuppressionFile").size() )
- {
- if ( !cmSystemTools::FileExists(this->CTest->GetCTestConfiguration(
- "MemoryCheckSuppressionFile").c_str()) )
- {
+ }
+ if (!this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .empty()) {
+ if (!cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .c_str())) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot find memory checker suppression file: "
- << this->CTest->GetCTestConfiguration(
- "MemoryCheckSuppressionFile").c_str() << std::endl);
+ "Cannot find memory checker suppression file: "
+ << this->CTest->GetCTestConfiguration(
+ "MemoryCheckSuppressionFile")
+ << std::endl);
return false;
- }
- std::string suppressions = "--suppressions="
- + this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile");
- this->MemoryTesterOptions.push_back(suppressions);
}
- std::string outputFile = "--log-file="
- + this->MemoryTesterOutputFile;
+ std::string suppressions = "--suppressions=" +
+ this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile");
+ this->MemoryTesterOptions.push_back(suppressions);
+ }
+ std::string outputFile = "--log-file=" + this->MemoryTesterOutputFile;
this->MemoryTesterDynamicOptions.push_back(outputFile);
break;
- }
- case cmCTestMemCheckHandler::PURIFY:
- {
+ }
+ case cmCTestMemCheckHandler::PURIFY: {
std::string outputFile;
#ifdef _WIN32
- if( this->CTest->GetCTestConfiguration(
- "MemoryCheckSuppressionFile").size() )
- {
- if( !cmSystemTools::FileExists(this->CTest->GetCTestConfiguration(
- "MemoryCheckSuppressionFile").c_str()) )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot find memory checker suppression file: "
- << this->CTest->GetCTestConfiguration(
- "MemoryCheckSuppressionFile").c_str() << std::endl);
+ if (this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .size()) {
+ if (!cmSystemTools::FileExists(
+ this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .c_str())) {
+ cmCTestLog(
+ this->CTest, ERROR_MESSAGE,
+ "Cannot find memory checker suppression file: "
+ << this->CTest
+ ->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .c_str()
+ << std::endl);
return false;
- }
- std::string filterFiles = "/FilterFiles="
- + this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile");
- this->MemoryTesterOptions.push_back(filterFiles);
}
+ std::string filterFiles = "/FilterFiles=" +
+ this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile");
+ this->MemoryTesterOptions.push_back(filterFiles);
+ }
outputFile = "/SAVETEXTDATA=";
#else
outputFile = "-log-file=";
@@ -558,12 +580,11 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
outputFile += this->MemoryTesterOutputFile;
this->MemoryTesterDynamicOptions.push_back(outputFile);
break;
- }
- case cmCTestMemCheckHandler::BOUNDS_CHECKER:
- {
+ }
+ case cmCTestMemCheckHandler::BOUNDS_CHECKER: {
this->BoundsCheckerXMLFile = this->MemoryTesterOutputFile;
- std::string dpbdFile = this->CTest->GetBinaryDir()
- + "/Testing/Temporary/MemoryChecker.??.DPbd";
+ std::string dpbdFile = this->CTest->GetBinaryDir() +
+ "/Testing/Temporary/MemoryChecker.??.DPbd";
this->BoundsCheckerDPBDFile = dpbdFile;
this->MemoryTesterDynamicOptions.push_back("/B");
this->MemoryTesterDynamicOptions.push_back(dpbdFile);
@@ -571,127 +592,223 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
this->MemoryTesterDynamicOptions.push_back(this->MemoryTesterOutputFile);
this->MemoryTesterOptions.push_back("/M");
break;
+ }
+ // these are almost the same but the env var used is different
+ case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
+ case cmCTestMemCheckHandler::LEAK_SANITIZER:
+ case cmCTestMemCheckHandler::THREAD_SANITIZER:
+ case cmCTestMemCheckHandler::MEMORY_SANITIZER:
+ case cmCTestMemCheckHandler::UB_SANITIZER: {
+ // To pass arguments to ThreadSanitizer the environment variable
+ // TSAN_OPTIONS is used. This is done with the cmake -E env command.
+ // The MemoryTesterDynamicOptions is setup with the -E env
+ // Then the MemoryTesterEnvironmentVariable gets the
+ // TSAN_OPTIONS string with the log_path in it.
+ this->MemoryTesterDynamicOptions.push_back("-E");
+ this->MemoryTesterDynamicOptions.push_back("env");
+ std::string envVar;
+ std::string extraOptions;
+ std::string suppressionsOption;
+ if (!this->CTest->GetCTestConfiguration("MemoryCheckSanitizerOptions")
+ .empty()) {
+ extraOptions = ":" +
+ this->CTest->GetCTestConfiguration("MemoryCheckSanitizerOptions");
+ }
+ if (!this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+ .empty()) {
+ suppressionsOption = ":suppressions=" +
+ this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile");
}
+ if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::ADDRESS_SANITIZER) {
+ envVar = "ASAN_OPTIONS";
+ } else if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::LEAK_SANITIZER) {
+ envVar = "LSAN_OPTIONS";
+ } else if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::THREAD_SANITIZER) {
+ envVar = "TSAN_OPTIONS";
+ } else if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::MEMORY_SANITIZER) {
+ envVar = "MSAN_OPTIONS";
+ } else if (this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::UB_SANITIZER) {
+ envVar = "UBSAN_OPTIONS";
+ }
+ // Quote log_path with single quotes; see
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=467936
+ std::string outputFile =
+ envVar + "=log_path='" + this->MemoryTesterOutputFile + "'";
+ this->MemoryTesterEnvironmentVariable =
+ outputFile + suppressionsOption + extraOptions;
+ break;
+ }
default:
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Do not understand memory checker: " << this->MemoryTester.c_str()
- << std::endl);
+ "Do not understand memory checker: " << this->MemoryTester
+ << std::endl);
return false;
- }
+ }
- std::vector<cmStdString>::size_type cc;
- for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
- {
- this->MemoryTesterGlobalResults[cc] = 0;
- }
+ this->InitializeResultsVectors();
+ // std::vector<std::string>::size_type cc;
+ // for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
+ // {
+ // this->MemoryTesterGlobalResults[cc] = 0;
+ // }
return true;
}
-//----------------------------------------------------------------------
bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str,
- std::string& log, int* results)
+ std::string& log,
+ std::vector<int>& results)
{
- std::string::size_type cc;
- for ( cc = 0; cc < cmCTestMemCheckHandler::NO_MEMORY_FAULT; cc ++ )
- {
- results[cc] = 0;
- }
+ switch (this->MemoryTesterStyle) {
+ case cmCTestMemCheckHandler::VALGRIND:
+ return this->ProcessMemCheckValgrindOutput(str, log, results);
+ case cmCTestMemCheckHandler::PURIFY:
+ return this->ProcessMemCheckPurifyOutput(str, log, results);
+ case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
+ case cmCTestMemCheckHandler::LEAK_SANITIZER:
+ case cmCTestMemCheckHandler::THREAD_SANITIZER:
+ case cmCTestMemCheckHandler::MEMORY_SANITIZER:
+ case cmCTestMemCheckHandler::UB_SANITIZER:
+ return this->ProcessMemCheckSanitizerOutput(str, log, results);
+ case cmCTestMemCheckHandler::BOUNDS_CHECKER:
+ return this->ProcessMemCheckBoundsCheckerOutput(str, log, results);
+ default:
+ log.append("\nMemory checking style used was: ");
+ log.append("None that I know");
+ log = str;
+ return true;
+ }
+}
- if ( this->MemoryTesterStyle == cmCTestMemCheckHandler::VALGRIND )
- {
- return this->ProcessMemCheckValgrindOutput(str, log, results);
- }
- else if ( this->MemoryTesterStyle == cmCTestMemCheckHandler::PURIFY )
- {
- return this->ProcessMemCheckPurifyOutput(str, log, results);
+std::vector<int>::size_type cmCTestMemCheckHandler::FindOrAddWarning(
+ const std::string& warning)
+{
+ for (std::vector<std::string>::size_type i = 0;
+ i < this->ResultStrings.size(); ++i) {
+ if (this->ResultStrings[i] == warning) {
+ return i;
}
- else if ( this->MemoryTesterStyle ==
- cmCTestMemCheckHandler::BOUNDS_CHECKER )
- {
- return this->ProcessMemCheckBoundsCheckerOutput(str, log, results);
+ }
+ this->GlobalResults.push_back(0); // this must stay the same size
+ this->ResultStrings.push_back(warning);
+ this->ResultStringsLong.push_back(warning);
+ return this->ResultStrings.size() - 1;
+}
+bool cmCTestMemCheckHandler::ProcessMemCheckSanitizerOutput(
+ const std::string& str, std::string& log, std::vector<int>& result)
+{
+ std::string regex;
+ switch (this->MemoryTesterStyle) {
+ case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
+ regex = "ERROR: AddressSanitizer: (.*) on.*";
+ break;
+ case cmCTestMemCheckHandler::LEAK_SANITIZER:
+ // use leakWarning regex
+ break;
+ case cmCTestMemCheckHandler::THREAD_SANITIZER:
+ regex = "WARNING: ThreadSanitizer: (.*) \\(pid=.*\\)";
+ break;
+ case cmCTestMemCheckHandler::MEMORY_SANITIZER:
+ regex = "WARNING: MemorySanitizer: (.*)";
+ break;
+ case cmCTestMemCheckHandler::UB_SANITIZER:
+ regex = "runtime error: (.*)";
+ break;
+ default:
+ break;
+ }
+ cmsys::RegularExpression sanitizerWarning(regex);
+ cmsys::RegularExpression leakWarning("(Direct|Indirect) leak of .*");
+ int defects = 0;
+ std::vector<std::string> lines;
+ cmSystemTools::Split(str.c_str(), lines);
+ std::ostringstream ostr;
+ log = "";
+ for (std::vector<std::string>::iterator i = lines.begin(); i != lines.end();
+ ++i) {
+ std::string resultFound;
+ if (leakWarning.find(*i)) {
+ resultFound = leakWarning.match(1) + " leak";
+ } else if (sanitizerWarning.find(*i)) {
+ resultFound = sanitizerWarning.match(1);
}
- else
- {
- log.append("\nMemory checking style used was: ");
- log.append("None that I know");
- log = str;
+ if (!resultFound.empty()) {
+ std::vector<int>::size_type idx = this->FindOrAddWarning(resultFound);
+ if (result.empty() || idx > result.size() - 1) {
+ result.push_back(1);
+ } else {
+ result[idx]++;
+ }
+ defects++;
+ ostr << "<b>" << this->ResultStrings[idx] << "</b> ";
}
-
-
- return true;
+ ostr << *i << std::endl;
+ }
+ log = ostr.str();
+ this->DefectCount += defects;
+ return defects == 0;
}
-
-//----------------------------------------------------------------------
bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
- const std::string& str, std::string& log,
- int* results)
+ const std::string& str, std::string& log, std::vector<int>& results)
{
- std::vector<cmStdString> lines;
+ std::vector<std::string> lines;
cmSystemTools::Split(str.c_str(), lines);
- cmOStringStream ostr;
+ std::ostringstream ostr;
log = "";
cmsys::RegularExpression pfW("^\\[[WEI]\\] ([A-Z][A-Z][A-Z][A-Z]*): ");
int defects = 0;
- for( std::vector<cmStdString>::iterator i = lines.begin();
- i != lines.end(); ++i)
- {
- int failure = cmCTestMemCheckHandler::NO_MEMORY_FAULT;
- if ( pfW.find(*i) )
- {
- int cc;
- for ( cc = 0; cc < cmCTestMemCheckHandler::NO_MEMORY_FAULT; cc ++ )
- {
- if ( pfW.match(1) == cmCTestMemCheckResultStrings[cc] )
- {
+ for (std::vector<std::string>::iterator i = lines.begin(); i != lines.end();
+ ++i) {
+ std::vector<int>::size_type failure = this->ResultStrings.size();
+ if (pfW.find(*i)) {
+ std::vector<int>::size_type cc;
+ for (cc = 0; cc < this->ResultStrings.size(); cc++) {
+ if (pfW.match(1) == this->ResultStrings[cc]) {
failure = cc;
break;
- }
}
- if ( cc == cmCTestMemCheckHandler::NO_MEMORY_FAULT )
- {
+ }
+ if (cc == this->ResultStrings.size()) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown Purify memory fault: "
- << pfW.match(1) << std::endl);
+ << pfW.match(1) << std::endl);
ostr << "*** Unknown Purify memory fault: " << pfW.match(1)
- << std::endl;
- }
- }
- if ( failure != NO_MEMORY_FAULT )
- {
- ostr << "<b>" << cmCTestMemCheckResultStrings[failure] << "</b> ";
- results[failure] ++;
- defects ++;
+ << std::endl;
}
- ostr << cmXMLSafe(*i) << std::endl;
}
+ if (failure != this->ResultStrings.size()) {
+ ostr << "<b>" << this->ResultStrings[failure] << "</b> ";
+ results[failure]++;
+ defects++;
+ }
+ ostr << *i << std::endl;
+ }
log = ostr.str();
- if ( defects )
- {
- return false;
- }
- return true;
+ this->DefectCount += defects;
+ return defects == 0;
}
-//----------------------------------------------------------------------
bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
- const std::string& str, std::string& log,
- int* results)
+ const std::string& str, std::string& log, std::vector<int>& results)
{
- std::vector<cmStdString> lines;
+ std::vector<std::string> lines;
cmSystemTools::Split(str.c_str(), lines);
bool unlimitedOutput = false;
- if(str.find("CTEST_FULL_OUTPUT") != str.npos ||
- this->CustomMaximumFailedTestOutputSize == 0)
- {
+ if (str.find("CTEST_FULL_OUTPUT") != std::string::npos ||
+ this->CustomMaximumFailedTestOutputSize == 0) {
unlimitedOutput = true;
- }
+ }
std::string::size_type cc;
- cmOStringStream ostr;
+ std::ostringstream ostr;
log = "";
int defects = 0;
@@ -704,7 +821,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
"== .*Mismatched free\\(\\) / delete / delete \\[\\]");
cmsys::RegularExpression vgMLK1(
"== .*[0-9,]+ bytes in [0-9,]+ blocks are definitely lost"
- " in loss record [0-9,]+ of [0-9,]+");
+ " in loss record [0-9,]+ of [0-9,]+");
cmsys::RegularExpression vgMLK2(
"== .*[0-9,]+ \\([0-9,]+ direct, [0-9,]+ indirect\\)"
" bytes in [0-9,]+ blocks are definitely lost"
@@ -723,300 +840,261 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
"== .*Use of uninitialised value of size [0-9,]+");
cmsys::RegularExpression vgUMR2("== .*Invalid read of size [0-9,]+");
cmsys::RegularExpression vgUMR3("== .*Jump to the invalid address ");
- cmsys::RegularExpression vgUMR4("== .*Syscall param .* contains "
+ cmsys::RegularExpression vgUMR4(
+ "== .*Syscall param .* contains "
"uninitialised or unaddressable byte\\(s\\)");
cmsys::RegularExpression vgUMR5("== .*Syscall param .* uninitialised");
cmsys::RegularExpression vgIPW("== .*Invalid write of size [0-9,]+");
cmsys::RegularExpression vgABR("== .*pthread_mutex_unlock: mutex is "
- "locked by a different thread");
+ "locked by a different thread");
std::vector<std::string::size_type> nonValGrindOutput;
double sttime = cmSystemTools::GetTime();
- cmCTestLog(this->CTest, DEBUG, "Start test: " << lines.size() << std::endl);
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Start test: " << lines.size() << std::endl, this->Quiet);
std::string::size_type totalOutputSize = 0;
- bool outputFull = false;
- for ( cc = 0; cc < lines.size(); cc ++ )
- {
- cmCTestLog(this->CTest, DEBUG, "test line "
- << lines[cc] << std::endl);
-
- if ( valgrindLine.find(lines[cc]) )
- {
- cmCTestLog(this->CTest, DEBUG, "valgrind line "
- << lines[cc] << std::endl);
+ for (cc = 0; cc < lines.size(); cc++) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "test line " << lines[cc] << std::endl, this->Quiet);
+
+ if (valgrindLine.find(lines[cc])) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "valgrind line " << lines[cc] << std::endl,
+ this->Quiet);
int failure = cmCTestMemCheckHandler::NO_MEMORY_FAULT;
- if ( vgFIM.find(lines[cc]) )
- {
+ if (vgFIM.find(lines[cc])) {
failure = cmCTestMemCheckHandler::FIM;
- }
- else if ( vgFMM.find(lines[cc]) )
- {
+ } else if (vgFMM.find(lines[cc])) {
failure = cmCTestMemCheckHandler::FMM;
- }
- else if ( vgMLK1.find(lines[cc]) )
- {
+ } else if (vgMLK1.find(lines[cc])) {
failure = cmCTestMemCheckHandler::MLK;
- }
- else if ( vgMLK2.find(lines[cc]) )
- {
+ } else if (vgMLK2.find(lines[cc])) {
failure = cmCTestMemCheckHandler::MLK;
- }
- else if ( vgPAR.find(lines[cc]) )
- {
+ } else if (vgPAR.find(lines[cc])) {
failure = cmCTestMemCheckHandler::PAR;
- }
- else if ( vgMPK1.find(lines[cc]) )
- {
+ } else if (vgMPK1.find(lines[cc])) {
failure = cmCTestMemCheckHandler::MPK;
- }
- else if ( vgMPK2.find(lines[cc]) )
- {
+ } else if (vgMPK2.find(lines[cc])) {
failure = cmCTestMemCheckHandler::MPK;
- }
- else if ( vgUMC.find(lines[cc]) )
- {
+ } else if (vgUMC.find(lines[cc])) {
failure = cmCTestMemCheckHandler::UMC;
- }
- else if ( vgUMR1.find(lines[cc]) )
- {
+ } else if (vgUMR1.find(lines[cc])) {
failure = cmCTestMemCheckHandler::UMR;
- }
- else if ( vgUMR2.find(lines[cc]) )
- {
+ } else if (vgUMR2.find(lines[cc])) {
failure = cmCTestMemCheckHandler::UMR;
- }
- else if ( vgUMR3.find(lines[cc]) )
- {
+ } else if (vgUMR3.find(lines[cc])) {
failure = cmCTestMemCheckHandler::UMR;
- }
- else if ( vgUMR4.find(lines[cc]) )
- {
+ } else if (vgUMR4.find(lines[cc])) {
failure = cmCTestMemCheckHandler::UMR;
- }
- else if ( vgUMR5.find(lines[cc]) )
- {
+ } else if (vgUMR5.find(lines[cc])) {
failure = cmCTestMemCheckHandler::UMR;
- }
- else if ( vgIPW.find(lines[cc]) )
- {
+ } else if (vgIPW.find(lines[cc])) {
failure = cmCTestMemCheckHandler::IPW;
- }
- else if ( vgABR.find(lines[cc]) )
- {
+ } else if (vgABR.find(lines[cc])) {
failure = cmCTestMemCheckHandler::ABR;
- }
+ }
- if ( failure != cmCTestMemCheckHandler::NO_MEMORY_FAULT )
- {
- ostr << "<b>" << cmCTestMemCheckResultStrings[failure] << "</b> ";
- results[failure] ++;
- defects ++;
- }
- totalOutputSize += lines[cc].size();
- ostr << cmXMLSafe(lines[cc]) << std::endl;
+ if (failure != cmCTestMemCheckHandler::NO_MEMORY_FAULT) {
+ ostr << "<b>" << this->ResultStrings[failure] << "</b> ";
+ results[failure]++;
+ defects++;
}
- else
- {
+ totalOutputSize += lines[cc].size();
+ ostr << lines[cc] << std::endl;
+ } else {
nonValGrindOutput.push_back(cc);
- }
}
+ }
// Now put all all the non valgrind output into the test output
- if(!outputFull)
- {
- for(std::vector<std::string::size_type>::iterator i =
- nonValGrindOutput.begin(); i != nonValGrindOutput.end(); ++i)
- {
- totalOutputSize += lines[*i].size();
- cmCTestLog(this->CTest, DEBUG, "before xml safe "
- << lines[*i] << std::endl);
- cmCTestLog(this->CTest, DEBUG, "after xml safe "
- << cmXMLSafe(lines[*i]) << std::endl);
-
- ostr << cmXMLSafe(lines[*i]) << std::endl;
- if(!unlimitedOutput && totalOutputSize >
- static_cast<size_t>(this->CustomMaximumFailedTestOutputSize))
- {
- outputFull = true;
- ostr << "....\n";
- ostr << "Test Output for this test has been truncated see testing"
- " machine logs for full output,\n";
- ostr << "or put CTEST_FULL_OUTPUT in the output of "
- "this test program.\n";
- }
- }
+ // This should be last in case it gets truncated by the output
+ // limiting code
+ for (std::vector<std::string::size_type>::iterator i =
+ nonValGrindOutput.begin();
+ i != nonValGrindOutput.end(); ++i) {
+ totalOutputSize += lines[*i].size();
+ ostr << lines[*i] << std::endl;
+ if (!unlimitedOutput &&
+ totalOutputSize >
+ static_cast<size_t>(this->CustomMaximumFailedTestOutputSize)) {
+ ostr << "....\n";
+ ostr << "Test Output for this test has been truncated see testing"
+ " machine logs for full output,\n";
+ ostr << "or put CTEST_FULL_OUTPUT in the output of "
+ "this test program.\n";
+ break; // stop the copy of output if we are full
}
- cmCTestLog(this->CTest, DEBUG, "End test (elapsed: "
- << (cmSystemTools::GetTime() - sttime) << std::endl);
+ }
+ cmCTestOptionalLog(this->CTest, DEBUG, "End test (elapsed: "
+ << (cmSystemTools::GetTime() - sttime) << std::endl,
+ this->Quiet);
log = ostr.str();
- if ( defects )
- {
- return false;
- }
- return true;
+ this->DefectCount += defects;
+ return defects == 0;
}
-
-
-//----------------------------------------------------------------------
bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput(
- const std::string& str, std::string& log,
- int* results)
+ const std::string& str, std::string& log, std::vector<int>& results)
{
log = "";
double sttime = cmSystemTools::GetTime();
- std::vector<cmStdString> lines;
+ std::vector<std::string> lines;
cmSystemTools::Split(str.c_str(), lines);
- cmCTestLog(this->CTest, DEBUG, "Start test: " << lines.size() << std::endl);
- std::vector<cmStdString>::size_type cc;
- for ( cc = 0; cc < lines.size(); cc ++ )
- {
- if(lines[cc] == BOUNDS_CHECKER_MARKER)
- {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Start test: " << lines.size() << std::endl, this->Quiet);
+ std::vector<std::string>::size_type cc;
+ for (cc = 0; cc < lines.size(); cc++) {
+ if (lines[cc] == BOUNDS_CHECKER_MARKER) {
break;
- }
}
+ }
cmBoundsCheckerParser parser(this->CTest);
parser.InitializeParser();
- if(cc < lines.size())
- {
- for(cc++; cc < lines.size(); ++cc)
- {
+ if (cc < lines.size()) {
+ for (cc++; cc < lines.size(); ++cc) {
std::string& theLine = lines[cc];
// check for command line arguments that are not escaped
// correctly by BC
- if(theLine.find("TargetArgs=") != theLine.npos)
- {
+ if (theLine.find("TargetArgs=") != std::string::npos) {
// skip this because BC gets it wrong and we can't parse it
- }
- else if(!parser.ParseChunk(theLine.c_str(), theLine.size()))
- {
+ } else if (!parser.ParseChunk(theLine.c_str(), theLine.size())) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error in ParseChunk: " << theLine.c_str()
- << std::endl);
- }
+ "Error in ParseChunk: " << theLine << std::endl);
}
}
+ }
int defects = 0;
- for(cc =0; cc < parser.Errors.size(); ++cc)
- {
+ for (cc = 0; cc < parser.Errors.size(); ++cc) {
results[parser.Errors[cc]]++;
defects++;
- }
- cmCTestLog(this->CTest, DEBUG, "End test (elapsed: "
- << (cmSystemTools::GetTime() - sttime) << std::endl);
- if(defects)
- {
+ }
+ cmCTestOptionalLog(this->CTest, DEBUG, "End test (elapsed: "
+ << (cmSystemTools::GetTime() - sttime) << std::endl,
+ this->Quiet);
+ if (defects) {
// only put the output of Bounds Checker if there were
// errors or leaks detected
log = parser.Log;
- return false;
+ }
+ this->DefectCount += defects;
+ return defects == 0;
+}
+
+// PostProcessTest memcheck results
+void cmCTestMemCheckHandler::PostProcessTest(cmCTestTestResult& res, int test)
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "PostProcessTest memcheck results for : " << res.Name
+ << std::endl,
+ this->Quiet);
+ if (this->MemoryTesterStyle == cmCTestMemCheckHandler::BOUNDS_CHECKER) {
+ this->PostProcessBoundsCheckerTest(res, test);
+ } else {
+ std::vector<std::string> files;
+ this->TestOutputFileNames(test, files);
+ for (std::vector<std::string>::iterator i = files.begin();
+ i != files.end(); ++i) {
+ this->AppendMemTesterOutput(res, *i);
}
- return true;
+ }
}
// This method puts the bounds checker output file into the output
// for the test
-void
-cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(cmCTestTestResult& res,
- int test)
+void cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(
+ cmCTestTestResult& res, int test)
{
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "PostProcessBoundsCheckerTest for : "
- << res.Name.c_str() << std::endl);
- cmStdString ofile = testOutputFileName(test);
- if ( ofile.empty() )
- {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "PostProcessBoundsCheckerTest for : " << res.Name
+ << std::endl,
+ this->Quiet);
+ std::vector<std::string> files;
+ this->TestOutputFileNames(test, files);
+ if (files.empty()) {
return;
- }
+ }
+ std::string ofile = files[0];
+ if (ofile.empty()) {
+ return;
+ }
// put a scope around this to close ifs so the file can be removed
{
- std::ifstream ifs(ofile.c_str());
- if ( !ifs )
- {
- std::string log = "Cannot read memory tester output file: " + ofile;
- cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl);
- return;
+ cmsys::ifstream ifs(ofile.c_str());
+ if (!ifs) {
+ std::string log = "Cannot read memory tester output file: " + ofile;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, log << std::endl);
+ return;
}
- res.Output += BOUNDS_CHECKER_MARKER;
- res.Output += "\n";
- std::string line;
- while ( cmSystemTools::GetLineFromStream(ifs, line) )
- {
- res.Output += line;
+ res.Output += BOUNDS_CHECKER_MARKER;
res.Output += "\n";
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ res.Output += line;
+ res.Output += "\n";
}
}
cmSystemTools::Delay(1000);
- cmSystemTools::RemoveFile(this->BoundsCheckerDPBDFile.c_str());
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Remove: "
- << this->BoundsCheckerDPBDFile.c_str() << std::endl);
- cmSystemTools::RemoveFile(this->BoundsCheckerXMLFile.c_str());
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Remove: "
- << this->BoundsCheckerXMLFile.c_str() << std::endl);
+ cmSystemTools::RemoveFile(this->BoundsCheckerDPBDFile);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Remove: " << this->BoundsCheckerDPBDFile << std::endl,
+ this->Quiet);
+ cmSystemTools::RemoveFile(this->BoundsCheckerXMLFile);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Remove: " << this->BoundsCheckerXMLFile << std::endl,
+ this->Quiet);
}
-void
-cmCTestMemCheckHandler::PostProcessPurifyTest(cmCTestTestResult& res,
- int test)
+void cmCTestMemCheckHandler::AppendMemTesterOutput(cmCTestTestResult& res,
+ std::string const& ofile)
{
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "PostProcessPurifyTest for : "
- << res.Name.c_str() << std::endl);
- appendMemTesterOutput(res, test);
-}
-
-void
-cmCTestMemCheckHandler::PostProcessValgrindTest(cmCTestTestResult& res,
- int test)
-{
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "PostProcessValgrindTest for : "
- << res.Name.c_str() << std::endl);
- appendMemTesterOutput(res, test);
-}
-
-void
-cmCTestMemCheckHandler::appendMemTesterOutput(cmCTestTestResult& res,
- int test)
-{
- cmStdString ofile = testOutputFileName(test);
-
- if ( ofile.empty() )
- {
- return;
- }
- std::ifstream ifs(ofile.c_str());
- if ( !ifs )
- {
- std::string log = "Cannot read memory tester output file: " + ofile;
- cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl);
+ if (ofile.empty()) {
return;
+ }
+ // put ifs in scope so file can be deleted if needed
+ {
+ cmsys::ifstream ifs(ofile.c_str());
+ if (!ifs) {
+ std::string log = "Cannot read memory tester output file: " + ofile;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, log << std::endl);
+ return;
}
- std::string line;
- while ( cmSystemTools::GetLineFromStream(ifs, line) )
- {
- res.Output += line;
- res.Output += "\n";
+ std::string line;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ res.Output += line;
+ res.Output += "\n";
}
+ }
+ if (this->LogWithPID) {
+ cmSystemTools::RemoveFile(ofile);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Remove: " << ofile << "\n", this->Quiet);
+ }
}
-cmStdString
-cmCTestMemCheckHandler::testOutputFileName(int test)
+void cmCTestMemCheckHandler::TestOutputFileNames(
+ int test, std::vector<std::string>& files)
{
- cmStdString index;
- cmOStringStream stream;
+ std::string index;
+ std::ostringstream stream;
stream << test;
index = stream.str();
- cmStdString ofile = this->MemoryTesterOutputFile;
- cmStdString::size_type pos = ofile.find("??");
+ std::string ofile = this->MemoryTesterOutputFile;
+ std::string::size_type pos = ofile.find("??");
ofile.replace(pos, 2, index);
-
- if ( !cmSystemTools::FileExists(ofile.c_str()) )
- {
- std::string log = "Cannot find memory tester output file: "
- + ofile;
- cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl);
- ofile = "";
+ if (this->LogWithPID) {
+ ofile += ".*";
+ cmsys::Glob g;
+ g.FindFiles(ofile);
+ if (g.GetFiles().empty()) {
+ std::string log = "Cannot find memory tester output file: " + ofile;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, log << std::endl);
+ ofile = "";
+ } else {
+ files = g.GetFiles();
+ return;
}
-
- return ofile;
+ } else if (!cmSystemTools::FileExists(ofile.c_str())) {
+ std::string log = "Cannot find memory tester output file: " + ofile;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, log << std::endl);
+ ofile = "";
+ }
+ files.push_back(ofile);
}
diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h
index 040d2e092..333c2e2dd 100644
--- a/Source/CTest/cmCTestMemCheckHandler.h
+++ b/Source/CTest/cmCTestMemCheckHandler.h
@@ -1,23 +1,17 @@
-/*============================================================================
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestMemCheckHandler_h
#define cmCTestMemCheckHandler_h
+#include "cmConfigure.h"
#include "cmCTestTestHandler.h"
-#include "cmListFileCache.h"
+
+#include <string>
+#include <vector>
class cmMakefile;
+class cmXMLWriter;
/** \class cmCTestMemCheckHandler
* \brief A class that handles ctest -S invocations
@@ -26,29 +20,42 @@ class cmMakefile;
class cmCTestMemCheckHandler : public cmCTestTestHandler
{
friend class cmCTestRunTest;
+
public:
- cmTypeMacro(cmCTestMemCheckHandler, cmCTestTestHandler);
+ typedef cmCTestTestHandler Superclass;
- void PopulateCustomVectors(cmMakefile *mf);
+ void PopulateCustomVectors(cmMakefile* mf) CM_OVERRIDE;
cmCTestMemCheckHandler();
- void Initialize();
+ void Initialize() CM_OVERRIDE;
+
+ int GetDefectCount();
+
protected:
- virtual int PreProcessHandler();
- virtual int PostProcessHandler();
- virtual void GenerateTestCommand(std::vector<std::string>& args, int test);
+ int PreProcessHandler() CM_OVERRIDE;
+ int PostProcessHandler() CM_OVERRIDE;
+ void GenerateTestCommand(std::vector<std::string>& args,
+ int test) CM_OVERRIDE;
private:
-
- enum { // Memory checkers
+ enum
+ { // Memory checkers
UNKNOWN = 0,
VALGRIND,
PURIFY,
- BOUNDS_CHECKER
+ BOUNDS_CHECKER,
+ // checkers after here do not use the standard error list
+ ADDRESS_SANITIZER,
+ LEAK_SANITIZER,
+ THREAD_SANITIZER,
+ MEMORY_SANITIZER,
+ UB_SANITIZER
};
+
public:
- enum { // Memory faults
+ enum
+ { // Memory faults
ABR = 0,
ABW,
ABWL,
@@ -73,8 +80,10 @@ public:
UMR,
NO_MEMORY_FAULT
};
+
private:
- enum { // Program statuses
+ enum
+ { // Program statuses
NOT_RUN = 0,
TIMEOUT,
SEGFAULT,
@@ -86,14 +95,25 @@ private:
BAD_COMMAND,
COMPLETED
};
- std::string BoundsCheckerDPBDFile;
- std::string BoundsCheckerXMLFile;
- std::string MemoryTester;
- std::vector<cmStdString> MemoryTesterDynamicOptions;
- std::vector<cmStdString> MemoryTesterOptions;
- int MemoryTesterStyle;
- std::string MemoryTesterOutputFile;
- int MemoryTesterGlobalResults[NO_MEMORY_FAULT];
+ std::string BoundsCheckerDPBDFile;
+ std::string BoundsCheckerXMLFile;
+ std::string MemoryTester;
+ std::vector<std::string> MemoryTesterDynamicOptions;
+ std::vector<std::string> MemoryTesterOptions;
+ int MemoryTesterStyle;
+ std::string MemoryTesterOutputFile;
+ std::string MemoryTesterEnvironmentVariable;
+ // these are used to store the types of errors that can show up
+ std::vector<std::string> ResultStrings;
+ std::vector<std::string> ResultStringsLong;
+ std::vector<int> GlobalResults;
+ bool LogWithPID; // does log file add pid
+ int DefectCount;
+
+ std::vector<int>::size_type FindOrAddWarning(const std::string& warning);
+ // initialize the ResultStrings and ResultStringsLong for
+ // this type of checker
+ void InitializeResultsVectors();
///! Initialize memory checking subsystem.
bool InitializeMemoryChecking();
@@ -101,34 +121,35 @@ private:
/**
* Generate the Dart compatible output
*/
- void GenerateDartOutput(std::ostream& os);
+ void GenerateDartOutput(cmXMLWriter& xml) CM_OVERRIDE;
- std::vector<cmStdString> CustomPreMemCheck;
- std::vector<cmStdString> CustomPostMemCheck;
+ std::vector<std::string> CustomPreMemCheck;
+ std::vector<std::string> CustomPostMemCheck;
//! Parse Valgrind/Purify/Bounds Checker result out of the output
- //string. After running, log holds the output and results hold the
- //different memmory errors.
- bool ProcessMemCheckOutput(const std::string& str,
- std::string& log, int* results);
- bool ProcessMemCheckValgrindOutput(const std::string& str,
- std::string& log, int* results);
- bool ProcessMemCheckPurifyOutput(const std::string& str,
- std::string& log, int* results);
+ // string. After running, log holds the output and results hold the
+ // different memmory errors.
+ bool ProcessMemCheckOutput(const std::string& str, std::string& log,
+ std::vector<int>& results);
+ bool ProcessMemCheckValgrindOutput(const std::string& str, std::string& log,
+ std::vector<int>& results);
+ bool ProcessMemCheckPurifyOutput(const std::string& str, std::string& log,
+ std::vector<int>& results);
+ bool ProcessMemCheckSanitizerOutput(const std::string& str, std::string& log,
+ std::vector<int>& results);
bool ProcessMemCheckBoundsCheckerOutput(const std::string& str,
- std::string& log, int* results);
+ std::string& log,
+ std::vector<int>& results);
- void PostProcessPurifyTest(cmCTestTestResult& res, int test);
+ void PostProcessTest(cmCTestTestResult& res, int test);
void PostProcessBoundsCheckerTest(cmCTestTestResult& res, int test);
- void PostProcessValgrindTest(cmCTestTestResult& res, int test);
///! append MemoryTesterOutputFile to the test log
- void appendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res,
- int test);
+ void AppendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res,
+ std::string const& filename);
///! generate the output filename for the given test index
- cmStdString testOutputFileName(int test);
+ void TestOutputFileNames(int test, std::vector<std::string>& files);
};
#endif
-
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 76ddeea01..2c16a0d1e 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -1,35 +1,41 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestMultiProcessHandler.h"
-#include "cmProcess.h"
-#include "cmStandardIncludes.h"
+
#include "cmCTest.h"
+#include "cmCTestRunTest.h"
+#include "cmCTestScriptHandler.h"
+#include "cmCTestTestHandler.h"
#include "cmSystemTools.h"
-#include <stdlib.h>
+#include "cmWorkingDirectory.h"
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/String.hxx"
+#include "cmsys/SystemInformation.hxx"
+#include <algorithm>
+#include <iomanip>
+#include <list>
+#include <math.h>
+#include <sstream>
#include <stack>
-#include <float.h>
+#include <stdlib.h>
+#include <utility>
class TestComparator
{
public:
- TestComparator(cmCTestMultiProcessHandler* handler) : Handler(handler) {}
+ TestComparator(cmCTestMultiProcessHandler* handler)
+ : Handler(handler)
+ {
+ }
~TestComparator() {}
// Sorts tests in descending order of cost
- bool operator() (int index1, int index2) const
- {
+ bool operator()(int index1, int index2) const
+ {
return Handler->Properties[index1]->Cost >
Handler->Properties[index2]->Cost;
- }
+ }
private:
cmCTestMultiProcessHandler* Handler;
@@ -38,136 +44,155 @@ private:
cmCTestMultiProcessHandler::cmCTestMultiProcessHandler()
{
this->ParallelLevel = 1;
+ this->TestLoad = 0;
this->Completed = 0;
this->RunningCount = 0;
this->StopTimePassed = false;
+ this->HasCycles = false;
+ this->SerialTestRunning = false;
}
cmCTestMultiProcessHandler::~cmCTestMultiProcessHandler()
{
}
- // Set the tests
-void
-cmCTestMultiProcessHandler::SetTests(TestMap& tests,
- PropertiesMap& properties)
+// Set the tests
+void cmCTestMultiProcessHandler::SetTests(TestMap& tests,
+ PropertiesMap& properties)
{
this->Tests = tests;
this->Properties = properties;
this->Total = this->Tests.size();
// set test run map to false for all
- for(TestMap::iterator i = this->Tests.begin();
- i != this->Tests.end(); ++i)
- {
+ for (TestMap::iterator i = this->Tests.begin(); i != this->Tests.end();
+ ++i) {
this->TestRunningMap[i->first] = false;
this->TestFinishMap[i->first] = false;
- }
- if(!this->CTest->GetShowOnly())
- {
+ }
+ if (!this->CTest->GetShowOnly()) {
this->ReadCostData();
- this->CreateTestCostList();
+ this->HasCycles = !this->CheckCycles();
+ if (this->HasCycles) {
+ return;
}
+ this->CreateTestCostList();
+ }
}
- // Set the max number of tests that can be run at the same time.
+// Set the max number of tests that can be run at the same time.
void cmCTestMultiProcessHandler::SetParallelLevel(size_t level)
{
this->ParallelLevel = level < 1 ? 1 : level;
}
-//---------------------------------------------------------
+void cmCTestMultiProcessHandler::SetTestLoad(unsigned long load)
+{
+ this->TestLoad = load;
+}
+
void cmCTestMultiProcessHandler::RunTests()
{
this->CheckResume();
- if(!this->CheckCycles())
- {
+ if (this->HasCycles) {
return;
- }
+ }
this->TestHandler->SetMaxIndex(this->FindMaxIndex());
this->StartNextTests();
- while(this->Tests.size() != 0)
- {
- if(this->StopTimePassed)
- {
+ while (!this->Tests.empty()) {
+ if (this->StopTimePassed) {
return;
- }
+ }
this->CheckOutput();
this->StartNextTests();
- }
+ }
// let all running tests finish
- while(this->CheckOutput())
- {
- }
+ while (this->CheckOutput()) {
+ }
this->MarkFinished();
this->UpdateCostData();
}
-//---------------------------------------------------------
void cmCTestMultiProcessHandler::StartTestProcess(int test)
{
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "test " << test << "\n");
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "test " << test << "\n", this->Quiet);
this->TestRunningMap[test] = true; // mark the test as running
// now remove the test itself
this->EraseTest(test);
this->RunningCount += GetProcessorsUsed(test);
cmCTestRunTest* testRun = new cmCTestRunTest(this->TestHandler);
+ if (this->CTest->GetRepeatUntilFail()) {
+ testRun->SetRunUntilFailOn();
+ testRun->SetNumberOfRuns(this->CTest->GetTestRepeat());
+ }
testRun->SetIndex(test);
testRun->SetTestProperties(this->Properties[test]);
- std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
- cmSystemTools::ChangeDirectory(this->Properties[test]->Directory.c_str());
+ // Find any failed dependencies for this test. We assume the more common
+ // scenario has no failed tests, so make it the outer loop.
+ for (std::vector<std::string>::const_iterator it = this->Failed->begin();
+ it != this->Failed->end(); ++it) {
+ if (this->Properties[test]->RequireSuccessDepends.find(*it) !=
+ this->Properties[test]->RequireSuccessDepends.end()) {
+ testRun->AddFailedDependency(*it);
+ }
+ }
+
+ cmWorkingDirectory workdir(this->Properties[test]->Directory);
// Lock the resources we'll be using
this->LockResources(test);
- if(testRun->StartTest(this->Total))
- {
+ if (testRun->StartTest(this->Total)) {
this->RunningTests.insert(testRun);
- }
- else if(testRun->IsStopTimePassed())
- {
+ } else if (testRun->IsStopTimePassed()) {
this->StopTimePassed = true;
delete testRun;
return;
+ } else {
+
+ for (TestMap::iterator j = this->Tests.begin(); j != this->Tests.end();
+ ++j) {
+ j->second.erase(test);
}
- else
- {
+
this->UnlockResources(test);
this->Completed++;
this->TestFinishMap[test] = true;
this->TestRunningMap[test] = false;
this->RunningCount -= GetProcessorsUsed(test);
testRun->EndTest(this->Completed, this->Total, false);
- this->Failed->push_back(this->Properties[test]->Name);
- delete testRun;
+ if (!this->Properties[test]->Disabled) {
+ this->Failed->push_back(this->Properties[test]->Name);
}
- cmSystemTools::ChangeDirectory(current_dir.c_str());
+ delete testRun;
+ }
}
-//---------------------------------------------------------
void cmCTestMultiProcessHandler::LockResources(int index)
{
- for(std::set<std::string>::iterator i =
- this->Properties[index]->LockedResources.begin();
- i != this->Properties[index]->LockedResources.end(); ++i)
- {
- this->LockedResources.insert(*i);
- }
+ this->LockedResources.insert(
+ this->Properties[index]->LockedResources.begin(),
+ this->Properties[index]->LockedResources.end());
+
+ if (this->Properties[index]->RunSerial) {
+ this->SerialTestRunning = true;
+ }
}
-//---------------------------------------------------------
void cmCTestMultiProcessHandler::UnlockResources(int index)
{
- for(std::set<std::string>::iterator i =
- this->Properties[index]->LockedResources.begin();
- i != this->Properties[index]->LockedResources.end(); ++i)
- {
+ for (std::set<std::string>::iterator i =
+ this->Properties[index]->LockedResources.begin();
+ i != this->Properties[index]->LockedResources.end(); ++i) {
this->LockedResources.erase(*i);
- }
+ }
+ if (this->Properties[index]->RunSerial) {
+ this->SerialTestRunning = false;
+ }
}
-//---------------------------------------------------------
void cmCTestMultiProcessHandler::EraseTest(int test)
{
this->Tests.erase(test);
@@ -175,157 +200,202 @@ void cmCTestMultiProcessHandler::EraseTest(int test)
std::find(this->SortedTests.begin(), this->SortedTests.end(), test));
}
-//---------------------------------------------------------
inline size_t cmCTestMultiProcessHandler::GetProcessorsUsed(int test)
{
- size_t processors =
- static_cast<int>(this->Properties[test]->Processors);
- //If this is set to run serially, it must run alone.
- //Also, if processors setting is set higher than the -j
- //setting, we default to using all of the process slots.
- if(this->Properties[test]->RunSerial
- || processors > this->ParallelLevel)
- {
+ size_t processors = static_cast<int>(this->Properties[test]->Processors);
+ // If processors setting is set higher than the -j
+ // setting, we default to using all of the process slots.
+ if (processors > this->ParallelLevel) {
processors = this->ParallelLevel;
- }
+ }
return processors;
}
-//---------------------------------------------------------
+std::string cmCTestMultiProcessHandler::GetName(int test)
+{
+ return this->Properties[test]->Name;
+}
+
bool cmCTestMultiProcessHandler::StartTest(int test)
{
- //Check for locked resources
- for(std::set<std::string>::iterator i =
- this->Properties[test]->LockedResources.begin();
- i != this->Properties[test]->LockedResources.end(); ++i)
- {
- if(this->LockedResources.find(*i) != this->LockedResources.end())
- {
+ // Check for locked resources
+ for (std::set<std::string>::iterator i =
+ this->Properties[test]->LockedResources.begin();
+ i != this->Properties[test]->LockedResources.end(); ++i) {
+ if (this->LockedResources.find(*i) != this->LockedResources.end()) {
return false;
- }
}
+ }
- // 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;
- }
+ }
// This test was not able to start because it is waiting
// on depends to run
return false;
}
-//---------------------------------------------------------
void cmCTestMultiProcessHandler::StartNextTests()
{
size_t numToStart = 0;
- if(this->RunningCount < this->ParallelLevel)
- {
+ if (this->RunningCount < this->ParallelLevel) {
numToStart = this->ParallelLevel - this->RunningCount;
- }
+ }
- if(numToStart == 0)
- {
+ if (numToStart == 0) {
+ return;
+ }
+
+ // Don't start any new tests if one with the RUN_SERIAL property
+ // is already running.
+ if (this->SerialTestRunning) {
return;
+ }
+
+ bool allTestsFailedTestLoadCheck = false;
+ bool usedFakeLoadForTesting = false;
+ size_t minProcessorsRequired = this->ParallelLevel;
+ std::string testWithMinProcessors;
+
+ cmsys::SystemInformation info;
+
+ unsigned long systemLoad = 0;
+ size_t spareLoad = 0;
+ if (this->TestLoad > 0) {
+ // Activate possible wait.
+ allTestsFailedTestLoadCheck = true;
+
+ // Check for a fake load average value used in testing.
+ std::string fake_load_value;
+ if (cmSystemTools::GetEnv("__CTEST_FAKE_LOAD_AVERAGE_FOR_TESTING",
+ fake_load_value)) {
+ usedFakeLoadForTesting = true;
+ if (!cmSystemTools::StringToULong(fake_load_value.c_str(),
+ &systemLoad)) {
+ cmSystemTools::Error("Failed to parse fake load value: ",
+ fake_load_value.c_str());
+ }
+ }
+ // If it's not set, look up the true load average.
+ else {
+ systemLoad = static_cast<unsigned long>(ceil(info.GetLoadAverage()));
}
+ spareLoad =
+ (this->TestLoad > systemLoad ? this->TestLoad - systemLoad : 0);
+
+ // Don't start more tests than the spare load can support.
+ if (numToStart > spareLoad) {
+ numToStart = spareLoad;
+ }
+ }
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])
- {
+ for (TestList::iterator test = copy.begin(); test != copy.end(); ++test) {
+ // Take a nap if we're currently performing a RUN_SERIAL test.
+ if (this->SerialTestRunning) {
+ break;
+ }
+ // We can only start a RUN_SERIAL test if no other tests are also running.
+ if (this->Properties[*test]->RunSerial && this->RunningCount > 0) {
continue;
- }
+ }
+
size_t processors = GetProcessorsUsed(*test);
- if(processors > numToStart)
- {
- return;
+ bool testLoadOk = true;
+ if (this->TestLoad > 0) {
+ if (processors <= spareLoad) {
+ cmCTestLog(this->CTest, DEBUG, "OK to run "
+ << GetName(*test) << ", it requires " << processors
+ << " procs & system load is: " << systemLoad
+ << std::endl);
+ allTestsFailedTestLoadCheck = false;
+ } else {
+ testLoadOk = false;
}
- if(this->StartTest(*test))
- {
- if(this->StopTimePassed)
- {
+ }
+
+ if (processors <= minProcessorsRequired) {
+ minProcessorsRequired = processors;
+ testWithMinProcessors = GetName(*test);
+ }
+
+ if (testLoadOk && processors <= numToStart && this->StartTest(*test)) {
+ if (this->StopTimePassed) {
return;
- }
- numToStart -= processors;
}
- if(numToStart == 0)
- {
- return;
- }
- }
+
+ numToStart -= processors;
+ } else if (numToStart == 0) {
+ break;
+ }
+ }
+
+ if (allTestsFailedTestLoadCheck) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***** WAITING, ");
+ if (this->SerialTestRunning) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ "Waiting for RUN_SERIAL test to finish.");
+ } else {
+ /* clang-format off */
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ "System Load: " << systemLoad << ", "
+ "Max Allowed Load: " << this->TestLoad << ", "
+ "Smallest test " << testWithMinProcessors <<
+ " requires " << minProcessorsRequired);
+ /* clang-format on */
+ }
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "*****" << std::endl);
+
+ if (usedFakeLoadForTesting) {
+ // Break out of the infinite loop of waiting for our fake load
+ // to come down.
+ this->StopTimePassed = true;
+ } else {
+ // Wait between 1 and 5 seconds before trying again.
+ cmCTestScriptHandler::SleepInSeconds(cmSystemTools::RandomSeed() % 5 +
+ 1);
+ }
+ }
}
-//---------------------------------------------------------
bool cmCTestMultiProcessHandler::CheckOutput()
{
// no more output we are done
- if(this->RunningTests.size() == 0)
- {
+ if (this->RunningTests.empty()) {
return false;
- }
+ }
std::vector<cmCTestRunTest*> finished;
std::string out, err;
- for(std::set<cmCTestRunTest*>::const_iterator i = this->RunningTests.begin();
- i != this->RunningTests.end(); ++i)
- {
+ for (std::set<cmCTestRunTest*>::const_iterator i =
+ this->RunningTests.begin();
+ i != this->RunningTests.end(); ++i) {
cmCTestRunTest* p = *i;
- if(!p->CheckOutput())
- {
+ if (!p->CheckOutput()) {
finished.push_back(p);
- }
}
- for( std::vector<cmCTestRunTest*>::iterator i = finished.begin();
- i != finished.end(); ++i)
- {
+ }
+ for (std::vector<cmCTestRunTest*>::iterator i = finished.begin();
+ i != finished.end(); ++i) {
this->Completed++;
cmCTestRunTest* p = *i;
int test = p->GetIndex();
- if(p->EndTest(this->Completed, this->Total, true))
- {
+ bool testResult = p->EndTest(this->Completed, this->Total, true);
+ if (p->StartAgain()) {
+ this->Completed--; // remove the completed test because run again
+ continue;
+ }
+ if (testResult) {
this->Passed->push_back(p->GetTestProperties()->Name);
- }
- else
- {
+ } else {
this->Failed->push_back(p->GetTestProperties()->Name);
- }
- for(TestMap::iterator j = this->Tests.begin();
- j != this->Tests.end(); ++j)
- {
+ }
+ for (TestMap::iterator j = this->Tests.begin(); j != this->Tests.end();
+ ++j) {
j->second.erase(test);
- }
+ }
this->TestFinishMap[test] = true;
this->TestRunningMap[test] = false;
this->RunningTests.erase(p);
@@ -333,300 +403,385 @@ bool cmCTestMultiProcessHandler::CheckOutput()
this->UnlockResources(test);
this->RunningCount -= GetProcessorsUsed(test);
delete p;
- }
+ }
return true;
}
-//---------------------------------------------------------
void cmCTestMultiProcessHandler::UpdateCostData()
{
std::string fname = this->CTest->GetCostDataFile();
std::string tmpout = fname + ".tmp";
- std::fstream fout;
- fout.open(tmpout.c_str(), std::ios::out);
+ cmsys::ofstream fout;
+ fout.open(tmpout.c_str());
PropertiesMap temp = this->Properties;
- if(cmSystemTools::FileExists(fname.c_str()))
- {
- std::ifstream fin;
+ if (cmSystemTools::FileExists(fname.c_str())) {
+ cmsys::ifstream fin;
fin.open(fname.c_str());
std::string line;
- while(std::getline(fin, line))
- {
- if(line == "---") break;
- std::vector<cmsys::String> parts =
- cmSystemTools::SplitString(line.c_str(), ' ');
- //Format: <name> <previous_runs> <avg_cost>
- if(parts.size() < 3) break;
+ while (std::getline(fin, line)) {
+ if (line == "---") {
+ break;
+ }
+ std::vector<cmsys::String> parts = cmSystemTools::SplitString(line, ' ');
+ // Format: <name> <previous_runs> <avg_cost>
+ if (parts.size() < 3) {
+ break;
+ }
std::string name = parts[0];
int prev = atoi(parts[1].c_str());
float cost = static_cast<float>(atof(parts[2].c_str()));
int index = this->SearchByName(name);
- if(index == -1)
- {
+ if (index == -1) {
// This test is not in memory. We just rewrite the entry
fout << name << " " << prev << " " << cost << "\n";
- }
- else
- {
+ } else {
// Update with our new average cost
fout << name << " " << this->Properties[index]->PreviousRuns << " "
- << this->Properties[index]->Cost << "\n";
+ << this->Properties[index]->Cost << "\n";
temp.erase(index);
- }
}
- fin.close();
- cmSystemTools::RemoveFile(fname.c_str());
}
+ fin.close();
+ cmSystemTools::RemoveFile(fname);
+ }
// Add all tests not previously listed in the file
- for(PropertiesMap::iterator i = temp.begin(); i != temp.end(); ++i)
- {
+ for (PropertiesMap::iterator i = temp.begin(); i != temp.end(); ++i) {
fout << i->second->Name << " " << i->second->PreviousRuns << " "
- << i->second->Cost << "\n";
- }
+ << i->second->Cost << "\n";
+ }
// Write list of failed tests
fout << "---\n";
- for(std::vector<cmStdString>::iterator i = this->Failed->begin();
- i != this->Failed->end(); ++i)
- {
- fout << i->c_str() << "\n";
- }
+ for (std::vector<std::string>::iterator i = this->Failed->begin();
+ i != this->Failed->end(); ++i) {
+ fout << *i << "\n";
+ }
fout.close();
cmSystemTools::RenameFile(tmpout.c_str(), fname.c_str());
}
-//---------------------------------------------------------
void cmCTestMultiProcessHandler::ReadCostData()
{
std::string fname = this->CTest->GetCostDataFile();
- if(cmSystemTools::FileExists(fname.c_str(), true))
- {
- std::ifstream fin;
+ if (cmSystemTools::FileExists(fname.c_str(), true)) {
+ cmsys::ifstream fin;
fin.open(fname.c_str());
std::string line;
- while(std::getline(fin, line))
- {
- if(line == "---") break;
+ while (std::getline(fin, line)) {
+ if (line == "---") {
+ break;
+ }
- std::vector<cmsys::String> parts =
- cmSystemTools::SplitString(line.c_str(), ' ');
+ std::vector<cmsys::String> parts = cmSystemTools::SplitString(line, ' ');
// Probably an older version of the file, will be fixed next run
- if(parts.size() < 3)
- {
+ if (parts.size() < 3) {
fin.close();
return;
- }
+ }
std::string name = parts[0];
int prev = atoi(parts[1].c_str());
float cost = static_cast<float>(atof(parts[2].c_str()));
int index = this->SearchByName(name);
- if(index == -1) continue;
+ if (index == -1) {
+ continue;
+ }
this->Properties[index]->PreviousRuns = prev;
// When not running in parallel mode, don't use cost data
- if(this->ParallelLevel > 1 &&
- this->Properties[index] &&
- this->Properties[index]->Cost == 0)
- {
+ if (this->ParallelLevel > 1 && this->Properties[index] &&
+ this->Properties[index]->Cost == 0) {
this->Properties[index]->Cost = cost;
- }
}
+ }
// Next part of the file is the failed tests
- while(std::getline(fin, line))
- {
- if(line != "")
- {
+ while (std::getline(fin, line)) {
+ if (line != "") {
this->LastTestsFailed.push_back(line);
- }
}
- fin.close();
}
+ fin.close();
+ }
}
-//---------------------------------------------------------
-int cmCTestMultiProcessHandler::SearchByName(std::string name)
+int cmCTestMultiProcessHandler::SearchByName(std::string const& name)
{
int index = -1;
- for(PropertiesMap::iterator i = this->Properties.begin();
- i != this->Properties.end(); ++i)
- {
- if(i->second->Name == name)
- {
+ for (PropertiesMap::iterator i = this->Properties.begin();
+ i != this->Properties.end(); ++i) {
+ if (i->second->Name == name) {
index = i->first;
- }
}
+ }
return index;
}
-//---------------------------------------------------------
void cmCTestMultiProcessHandler::CreateTestCostList()
{
- for(TestMap::iterator i = this->Tests.begin();
- i != this->Tests.end(); ++i)
- {
- SortedTests.push_back(i->first);
-
- //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(),
- this->Properties[i->first]->Name) != this->LastTestsFailed.end())
- {
- this->Properties[i->first]->Cost = FLT_MAX;
+ if (this->ParallelLevel > 1) {
+ CreateParallelTestCostList();
+ } else {
+ CreateSerialTestCostList();
+ }
+}
+
+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()) {
+ // 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().empty()) {
+ 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];
+ currentSet.insert(dependencies.begin(), dependencies.end());
+ }
+
+ 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;
+
+ sortedCopy.insert(sortedCopy.end(), currentSet.begin(), currentSet.end());
+
+ 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);
+ }
}
-//---------------------------------------------------------
void cmCTestMultiProcessHandler::WriteCheckpoint(int index)
{
- std::string fname = this->CTest->GetBinaryDir()
- + "/Testing/Temporary/CTestCheckpoint.txt";
- std::fstream fout;
- fout.open(fname.c_str(), std::ios::app | std::ios::out);
+ std::string fname =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/CTestCheckpoint.txt";
+ cmsys::ofstream fout;
+ fout.open(fname.c_str(), std::ios::app);
fout << index << "\n";
fout.close();
}
-//---------------------------------------------------------
void cmCTestMultiProcessHandler::MarkFinished()
{
- std::string fname = this->CTest->GetBinaryDir()
- + "/Testing/Temporary/CTestCheckpoint.txt";
- cmSystemTools::RemoveFile(fname.c_str());
+ std::string fname =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/CTestCheckpoint.txt";
+ cmSystemTools::RemoveFile(fname);
}
-//---------------------------------------------------------
-//For ShowOnly mode
+// For ShowOnly mode
void cmCTestMultiProcessHandler::PrintTestList()
{
this->TestHandler->SetMaxIndex(this->FindMaxIndex());
int count = 0;
for (PropertiesMap::iterator it = this->Properties.begin();
- it != this->Properties.end(); ++it)
- {
+ it != this->Properties.end(); ++it) {
count++;
cmCTestTestHandler::cmCTestTestProperties& p = *it->second;
- //push working dir
- std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
- cmSystemTools::ChangeDirectory(p.Directory.c_str());
+ cmWorkingDirectory workdir(p.Directory);
cmCTestRunTest testRun(this->TestHandler);
testRun.SetIndex(p.Index);
testRun.SetTestProperties(&p);
- testRun.ComputeArguments(); //logs the command in verbose mode
+ testRun.ComputeArguments(); // logs the command in verbose mode
- if(p.Labels.size()) //print the labels
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Labels:");
- }
- for(std::vector<std::string>::iterator label = p.Labels.begin();
- label != p.Labels.end(); ++label)
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " " << *label);
- }
- if(p.Labels.size()) //print the labels
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl);
- }
+ if (!p.Labels.empty()) // print the labels
+ {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Labels:",
+ this->Quiet);
+ }
+ for (std::vector<std::string>::iterator label = p.Labels.begin();
+ label != p.Labels.end(); ++label) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " " << *label,
+ this->Quiet);
+ }
+ if (!p.Labels.empty()) // print the labels
+ {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl,
+ this->Quiet);
+ }
- if (this->TestHandler->MemCheck)
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Memory Check");
- }
- else
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Test");
- }
- cmOStringStream indexStr;
+ if (this->TestHandler->MemCheck) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Memory Check",
+ this->Quiet);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Test", this->Quiet);
+ }
+ std::ostringstream indexStr;
indexStr << " #" << p.Index << ":";
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
std::setw(3 + getNumWidth(this->TestHandler->GetMaxIndex()))
- << indexStr.str().c_str());
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
- cmCTestLog(this->CTest, HANDLER_OUTPUT, p.Name.c_str() << std::endl);
- //pop working dir
- cmSystemTools::ChangeDirectory(current_dir.c_str());
- }
-
- cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl << "Total Tests: "
- << this->Total << std::endl);
+ << indexStr.str(),
+ this->Quiet);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " " << p.Name,
+ this->Quiet);
+ if (p.Disabled) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " (Disabled)",
+ this->Quiet);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, std::endl, this->Quiet);
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, std::endl
+ << "Total Tests: " << this->Total << std::endl,
+ this->Quiet);
}
void cmCTestMultiProcessHandler::PrintLabels()
{
std::set<std::string> allLabels;
for (PropertiesMap::iterator it = this->Properties.begin();
- it != this->Properties.end(); ++it)
- {
+ it != this->Properties.end(); ++it) {
cmCTestTestHandler::cmCTestTestProperties& p = *it->second;
allLabels.insert(p.Labels.begin(), p.Labels.end());
- }
-
- if(allLabels.size())
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "All Labels:" << std::endl);
- }
- else
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "No Labels Exist" << std::endl);
- }
- for(std::set<std::string>::iterator label = allLabels.begin();
- label != allLabels.end(); ++label)
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " " << *label << std::endl);
- }
+ }
+
+ if (!allLabels.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "All Labels:" << std::endl,
+ this->Quiet);
+ } else {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "No Labels Exist" << std::endl, this->Quiet);
+ }
+ for (std::set<std::string>::iterator label = allLabels.begin();
+ label != allLabels.end(); ++label) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " " << *label << std::endl, this->Quiet);
+ }
}
-//---------------------------------------------------------
void cmCTestMultiProcessHandler::CheckResume()
{
- std::string fname = this->CTest->GetBinaryDir()
- + "/Testing/Temporary/CTestCheckpoint.txt";
- if(this->CTest->GetFailover())
- {
- if(cmSystemTools::FileExists(fname.c_str(), true))
- {
- *this->TestHandler->LogFile << "Resuming previously interrupted test set"
- << std::endl
+ std::string fname =
+ this->CTest->GetBinaryDir() + "/Testing/Temporary/CTestCheckpoint.txt";
+ if (this->CTest->GetFailover()) {
+ if (cmSystemTools::FileExists(fname.c_str(), true)) {
+ *this->TestHandler->LogFile
+ << "Resuming previously interrupted test set" << std::endl
<< "----------------------------------------------------------"
<< std::endl;
- std::ifstream fin;
+ cmsys::ifstream fin;
fin.open(fname.c_str());
std::string line;
- while(std::getline(fin, line))
- {
+ while (std::getline(fin, line)) {
int index = atoi(line.c_str());
this->RemoveTest(index);
- }
- fin.close();
}
+ fin.close();
}
- else if(cmSystemTools::FileExists(fname.c_str(), true))
- {
- cmSystemTools::RemoveFile(fname.c_str());
- }
+ } else if (cmSystemTools::FileExists(fname.c_str(), true)) {
+ cmSystemTools::RemoveFile(fname);
+ }
}
-//---------------------------------------------------------
void cmCTestMultiProcessHandler::RemoveTest(int index)
{
this->EraseTest(index);
@@ -636,61 +791,54 @@ void cmCTestMultiProcessHandler::RemoveTest(int index)
this->Completed++;
}
-//---------------------------------------------------------
int cmCTestMultiProcessHandler::FindMaxIndex()
{
int max = 0;
cmCTestMultiProcessHandler::TestMap::iterator i = this->Tests.begin();
- for(; i != this->Tests.end(); ++i)
- {
- if(i->first > max)
- {
+ for (; i != this->Tests.end(); ++i) {
+ if (i->first > max) {
max = i->first;
- }
}
+ }
return max;
}
-//Returns true if no cycles exist in the dependency graph
+// Returns true if no cycles exist in the dependency graph
bool cmCTestMultiProcessHandler::CheckCycles()
{
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Checking test dependency graph..." << std::endl);
- for(TestMap::iterator it = this->Tests.begin();
- it != this->Tests.end(); ++it)
- {
- //DFS from each element to itself
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Checking test dependency graph..." << std::endl,
+ this->Quiet);
+ for (TestMap::iterator it = this->Tests.begin(); it != this->Tests.end();
+ ++it) {
+ // DFS from each element to itself
int root = it->first;
std::set<int> visited;
std::stack<int> s;
s.push(root);
- while(!s.empty())
- {
+ while (!s.empty()) {
int test = s.top();
s.pop();
- if(visited.insert(test).second)
- {
- for(TestSet::iterator d = this->Tests[test].begin();
- d != this->Tests[test].end(); ++d)
- {
- if(*d == root)
- {
- //cycle exists
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error: a cycle exists in the test dependency graph "
- "for the test \"" << this->Properties[root]->Name <<
- "\".\nPlease fix the cycle and run ctest again.\n");
+ if (visited.insert(test).second) {
+ for (TestSet::iterator d = this->Tests[test].begin();
+ d != this->Tests[test].end(); ++d) {
+ if (*d == root) {
+ // cycle exists
+ cmCTestLog(
+ this->CTest, ERROR_MESSAGE,
+ "Error: a cycle exists in the test dependency graph "
+ "for the test \""
+ << this->Properties[root]->Name
+ << "\".\nPlease fix the cycle and run ctest again.\n");
return false;
- }
- else
- {
- s.push(*d);
- }
}
+ s.push(*d);
}
}
}
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Checking test dependency graph end" << std::endl);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Checking test dependency graph end" << std::endl,
+ this->Quiet);
return true;
}
diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h
index cd21d9187..dccc2c896 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.h
+++ b/Source/CTest/cmCTestMultiProcessHandler.h
@@ -1,20 +1,19 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestMultiProcessHandler_h
#define cmCTestMultiProcessHandler_h
-#include <cmStandardIncludes.h>
-#include <cmCTestTestHandler.h>
-#include <cmCTestRunTest.h>
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmCTestTestHandler.h"
+#include <map>
+#include <set>
+#include <stddef.h>
+#include <string>
+#include <vector>
+
+class cmCTest;
+class cmCTestRunTest;
/** \class cmCTestMultiProcessHandler
* \brief run parallel ctest
@@ -24,12 +23,21 @@
class cmCTestMultiProcessHandler
{
friend class TestComparator;
+
public:
- struct TestSet : public std::set<int> {};
- struct TestMap : public std::map<int, TestSet> {};
- struct TestList : public std::vector<int> {};
- struct PropertiesMap : public
- std::map<int, cmCTestTestHandler::cmCTestTestProperties*> {};
+ struct TestSet : public std::set<int>
+ {
+ };
+ struct TestMap : public std::map<int, TestSet>
+ {
+ };
+ struct TestList : public std::vector<int>
+ {
+ };
+ struct PropertiesMap
+ : public std::map<int, cmCTestTestHandler::cmCTestTestProperties*>
+ {
+ };
cmCTestMultiProcessHandler();
virtual ~cmCTestMultiProcessHandler();
@@ -37,26 +45,32 @@ public:
void SetTests(TestMap& tests, PropertiesMap& properties);
// Set the max number of tests that can be run at the same time.
void SetParallelLevel(size_t);
+ void SetTestLoad(unsigned long load);
virtual void RunTests();
void PrintTestList();
void PrintLabels();
- void SetPassFailVectors(std::vector<cmStdString>* passed,
- std::vector<cmStdString>* failed)
- {
+ void SetPassFailVectors(std::vector<std::string>* passed,
+ std::vector<std::string>* failed)
+ {
this->Passed = passed;
this->Failed = failed;
- }
+ }
void SetTestResults(std::vector<cmCTestTestHandler::cmCTestTestResult>* r)
- { this->TestResults = r; }
+ {
+ this->TestResults = r;
+ }
- void SetCTest(cmCTest* ctest) { this->CTest = ctest;}
+ void SetCTest(cmCTest* ctest) { this->CTest = ctest; }
- void SetTestHandler(cmCTestTestHandler * handler)
- { this->TestHandler = handler; }
+ void SetTestHandler(cmCTestTestHandler* handler)
+ {
+ this->TestHandler = handler;
+ }
- cmCTestTestHandler * GetTestHandler()
- { return this->TestHandler; }
+ cmCTestTestHandler* GetTestHandler() { return this->TestHandler; }
+
+ void SetQuiet(bool b) { this->Quiet = b; }
protected:
// Start the next test or tests as many as are allowed by
// ParallelLevel
@@ -69,9 +83,15 @@ protected:
void UpdateCostData();
void ReadCostData();
// Return index of a test based on its name
- int SearchByName(std::string name);
+ int SearchByName(std::string const& name);
void CreateTestCostList();
+
+ void GetAllTestDependencies(int test, TestList& dependencies);
+ void CreateSerialTestCostList();
+
+ void CreateParallelTestCostList();
+
// Removes the checkpoint file
void MarkFinished();
void EraseTest(int index);
@@ -79,38 +99,43 @@ protected:
// check all running processes for output and exit case
bool CheckOutput();
void RemoveTest(int index);
- //Check if we need to resume an interrupted test set
+ // Check if we need to resume an interrupted test set
void CheckResume();
- //Check if there are any circular dependencies
+ // Check if there are any circular dependencies
bool CheckCycles();
int FindMaxIndex();
inline size_t GetProcessorsUsed(int index);
+ std::string GetName(int index);
void LockResources(int index);
void UnlockResources(int index);
// map from test number to set of depend tests
TestMap Tests;
TestList SortedTests;
- //Total number of tests we'll be running
+ // Total number of tests we'll be running
size_t Total;
- //Number of tests that are complete
+ // Number of tests that are complete
size_t Completed;
size_t RunningCount;
bool StopTimePassed;
- //list of test properties (indices concurrent to the test map)
+ // list of test properties (indices concurrent to the test map)
PropertiesMap Properties;
std::map<int, bool> TestRunningMap;
std::map<int, bool> TestFinishMap;
- std::map<int, cmStdString> TestOutput;
- std::vector<cmStdString>* Passed;
- std::vector<cmStdString>* Failed;
+ std::map<int, std::string> TestOutput;
+ std::vector<std::string>* Passed;
+ std::vector<std::string>* Failed;
std::vector<std::string> LastTestsFailed;
std::set<std::string> LockedResources;
std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults;
size_t ParallelLevel; // max number of process that can be run at once
- std::set<cmCTestRunTest*> RunningTests; // current running tests
- cmCTestTestHandler * TestHandler;
+ unsigned long TestLoad;
+ std::set<cmCTestRunTest*> RunningTests; // current running tests
+ cmCTestTestHandler* TestHandler;
cmCTest* CTest;
+ bool HasCycles;
+ bool Quiet;
+ bool SerialTestRunning;
};
#endif
diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx
new file mode 100644
index 000000000..c80221634
--- /dev/null
+++ b/Source/CTest/cmCTestP4.cxx
@@ -0,0 +1,529 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestP4.h"
+
+#include "cmCTest.h"
+#include "cmCTestVC.h"
+#include "cmProcessTools.h"
+#include "cmSystemTools.h"
+
+#include "cmsys/RegularExpression.hxx"
+#include <algorithm>
+#include <ostream>
+#include <time.h>
+#include <utility>
+
+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() CM_OVERRIDE
+ {
+ 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() CM_OVERRIDE
+ {
+ 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() CM_OVERRIDE
+ {
+ 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() CM_OVERRIDE
+ {
+ 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(CM_NULLPTR);
+
+ 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;
+
+ bool ProcessLine() CM_OVERRIDE
+ {
+ 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.empty()) {
+ 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<std::string> args =
+ cmSystemTools::ParseArguments(opts.c_str());
+
+ P4Options.insert(P4Options.end(), args.begin(), args.end());
+ }
+
+ 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(CM_NULLPTR);
+
+ std::string rev;
+ IdentifyParser out(this, "p4_changes-out> ", rev);
+ OutputLogger err(this->Log, "p4_changes-err> ");
+
+ bool result = RunChild(&p4_identify[0], &out, &err);
+
+ // If there was a problem contacting the server return "<unknown>"
+ if (!result) {
+ return "<unknown>";
+ }
+
+ if (rev.empty()) {
+ return "0";
+ }
+ return rev;
+}
+
+bool cmCTestP4::NoteOldRevision()
+{
+ this->OldRevision = this->GetWorkingRevision();
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " Old revision of repository is: "
+ << this->OldRevision << "\n");
+ this->PriorRev.Rev = this->OldRevision;
+ return true;
+}
+
+bool cmCTestP4::NoteNewRevision()
+{
+ this->NewRevision = this->GetWorkingRevision();
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " New revision of repository is: "
+ << this->NewRevision << "\n");
+ return true;
+}
+
+bool 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 any revision is unknown it means we couldn't contact the server.
+ // Do not process updates
+ if (this->OldRevision == "<unknown>" || this->NewRevision == "<unknown>") {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " At least one of the revisions "
+ << "is unknown. No repository changes will be reported.\n");
+ return false;
+ }
+
+ range.append("@")
+ .append(this->OldRevision)
+ .append(",")
+ .append(this->NewRevision);
+
+ p4_changes.push_back("changes");
+ p4_changes.push_back(range.c_str());
+ p4_changes.push_back(CM_NULLPTR);
+
+ ChangesParser out(this, "p4_changes-out> ");
+ OutputLogger err(this->Log, "p4_changes-err> ");
+
+ ChangeLists.clear();
+ this->RunChild(&p4_changes[0], &out, &err);
+
+ if (ChangeLists.empty()) {
+ return true;
+ }
+
+ // 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(CM_NULLPTR);
+
+ DescribeParser outDescribe(this, "p4_describe-out> ");
+ OutputLogger errDescribe(this->Log, "p4_describe-err> ");
+ this->RunChild(&p4_describe[0], &outDescribe, &errDescribe);
+ }
+ return true;
+}
+
+bool 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(CM_NULLPTR);
+
+ DiffParser out(this, "p4_diff-out> ");
+ OutputLogger err(this->Log, "p4_diff-err> ");
+ this->RunChild(&p4_diff[0], &out, &err);
+ return true;
+}
+
+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(CM_NULLPTR);
+
+ OutputLogger custom_out(this->Log, "p4_customsync-out> ");
+ OutputLogger custom_err(this->Log, "p4_customsync-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);
+ }
+
+ // If we couldn't get a revision number before updating, abort.
+ if (this->OldRevision == "<unknown>") {
+ this->UpdateCommandLine = "Unknown current revision";
+ cmCTestLog(this->CTest, ERROR_MESSAGE, " Unknown current revision\n");
+ return false;
+ }
+
+ 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<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ for (std::vector<std::string>::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(CM_NULLPTR);
+
+ OutputLogger out(this->Log, "p4_sync-out> ");
+ OutputLogger err(this->Log, "p4_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 000000000..e234efbfb
--- /dev/null
+++ b/Source/CTest/cmCTestP4.h
@@ -0,0 +1,76 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmCTestP4_h
+#define cmCTestP4_h
+
+#include "cmConfigure.h"
+
+#include "cmCTestGlobalVC.h"
+
+#include <iosfwd>
+#include <map>
+#include <string>
+#include <vector>
+
+class cmCTest;
+
+/** \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);
+
+ ~cmCTestP4() CM_OVERRIDE;
+
+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();
+ bool NoteOldRevision() CM_OVERRIDE;
+ bool NoteNewRevision() CM_OVERRIDE;
+ bool UpdateImpl() CM_OVERRIDE;
+ bool UpdateCustom(const std::string& custom);
+
+ bool LoadRevisions() CM_OVERRIDE;
+ bool LoadModifications() CM_OVERRIDE;
+
+ class ChangesParser;
+ class DescribeParser;
+ class DiffParser;
+ // Parsing helper classes.
+ class IdentifyParser;
+ class UserParser;
+
+ friend class IdentifyParser;
+ friend class ChangesParser;
+ friend class UserParser;
+ friend class DescribeParser;
+ friend class DiffParser;
+};
+
+#endif
diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.cxx b/Source/CTest/cmCTestReadCustomFilesCommand.cxx
index 5db01f98d..b21be872f 100644
--- a/Source/CTest/cmCTestReadCustomFilesCommand.cxx
+++ b/Source/CTest/cmCTestReadCustomFilesCommand.cxx
@@ -1,35 +1,23 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestReadCustomFilesCommand.h"
#include "cmCTest.h"
-bool cmCTestReadCustomFilesCommand
-::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
+class cmExecutionStatus;
+
+bool cmCTestReadCustomFilesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus& /*unused*/)
{
- if (args.size() < 1)
- {
+ if (args.empty()) {
this->SetError("called with incorrect number of arguments");
return false;
- }
+ }
std::vector<std::string>::const_iterator dit;
- for ( dit = args.begin(); dit != args.end(); ++ dit )
- {
- this->CTest->ReadCustomConfigurationFileTree(dit->c_str(),
- this->Makefile);
- }
+ for (dit = args.begin(); dit != args.end(); ++dit) {
+ this->CTest->ReadCustomConfigurationFileTree(dit->c_str(), this->Makefile);
+ }
return true;
}
-
-
diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.h b/Source/CTest/cmCTestReadCustomFilesCommand.h
index b984c84e9..5989fa0fc 100644
--- a/Source/CTest/cmCTestReadCustomFilesCommand.h
+++ b/Source/CTest/cmCTestReadCustomFilesCommand.h
@@ -1,19 +1,18 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestReadCustomFilesCommand_h
#define cmCTestReadCustomFilesCommand_h
+#include "cmConfigure.h"
+
#include "cmCTestCommand.h"
+#include <string>
+#include <vector>
+
+class cmCommand;
+class cmExecutionStatus;
+
/** \class cmCTestReadCustomFiles
* \brief Run a ctest script
*
@@ -23,53 +22,24 @@
class cmCTestReadCustomFilesCommand : public cmCTestCommand
{
public:
-
cmCTestReadCustomFilesCommand() {}
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestReadCustomFilesCommand* ni = new cmCTestReadCustomFilesCommand;
ni->CTest = this->CTest;
return ni;
- }
+ }
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
- virtual bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus &status);
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- 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);
-
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
};
-
#endif
diff --git a/Source/CTest/cmCTestRunScriptCommand.cxx b/Source/CTest/cmCTestRunScriptCommand.cxx
index fe429bd9d..238284a3f 100644
--- a/Source/CTest/cmCTestRunScriptCommand.cxx
+++ b/Source/CTest/cmCTestRunScriptCommand.cxx
@@ -1,65 +1,49 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestRunScriptCommand.h"
#include "cmCTestScriptHandler.h"
+#include "cmMakefile.h"
+
+#include <sstream>
-bool cmCTestRunScriptCommand
-::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
+class cmExecutionStatus;
+
+bool cmCTestRunScriptCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& /*unused*/)
{
- if(args.size() < 1 )
- {
+ if (args.empty()) {
this->CTestScriptHandler->RunCurrentScript();
return true;
- }
+ }
bool np = false;
unsigned int i = 0;
- if (args[i] == "NEW_PROCESS")
- {
+ if (args[i] == "NEW_PROCESS") {
np = true;
i++;
- }
+ }
int start = i;
// run each script
std::string returnVariable;
- for (i = start; i < args.size(); ++i)
- {
- if(args[i] == "RETURN_VALUE")
- {
+ for (i = start; i < args.size(); ++i) {
+ if (args[i] == "RETURN_VALUE") {
++i;
- if(i < args.size())
- {
+ if (i < args.size()) {
returnVariable = args[i];
- }
}
}
- for (i = start; i < args.size(); ++i)
- {
- if(args[i] == "RETURN_VALUE")
- {
+ }
+ for (i = start; i < args.size(); ++i) {
+ if (args[i] == "RETURN_VALUE") {
++i;
- }
- else
- {
+ } else {
int ret;
- cmCTestScriptHandler::RunScript(this->CTest, args[i].c_str(), !np,
- &ret);
- cmOStringStream str;
+ cmCTestScriptHandler::RunScript(this->CTest, args[i].c_str(), !np, &ret);
+ std::ostringstream str;
str << ret;
- this->Makefile->AddDefinition(returnVariable.c_str(), str.str().c_str());
- }
+ this->Makefile->AddDefinition(returnVariable, str.str().c_str());
}
+ }
return true;
}
-
-
diff --git a/Source/CTest/cmCTestRunScriptCommand.h b/Source/CTest/cmCTestRunScriptCommand.h
index 05e78991a..9bd09659d 100644
--- a/Source/CTest/cmCTestRunScriptCommand.h
+++ b/Source/CTest/cmCTestRunScriptCommand.h
@@ -1,19 +1,18 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestRunScriptCommand_h
#define cmCTestRunScriptCommand_h
+#include "cmConfigure.h"
+
#include "cmCTestCommand.h"
+#include <string>
+#include <vector>
+
+class cmCommand;
+class cmExecutionStatus;
+
/** \class cmCTestRunScript
* \brief Run a ctest script
*
@@ -23,58 +22,25 @@
class cmCTestRunScriptCommand : public cmCTestCommand
{
public:
-
cmCTestRunScriptCommand() {}
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestRunScriptCommand* ni = new cmCTestRunScriptCommand;
ni->CTest = this->CTest;
ni->CTestScriptHandler = this->CTestScriptHandler;
return ni;
- }
+ }
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
- virtual bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus &status);
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- 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);
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
};
-
#endif
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 0e2fa41b9..0c4269e3d 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -1,77 +1,96 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestRunTest.h"
-#include "cmCTestMemCheckHandler.h"
+
#include "cmCTest.h"
+#include "cmCTestMemCheckHandler.h"
+#include "cmCTestTestHandler.h"
+#include "cmProcess.h"
#include "cmSystemTools.h"
-#include "cm_curl.h"
+#include "cmWorkingDirectory.h"
-#include <cm_zlib.h>
-#include <cmsys/Base64.h>
+#include "cmConfigure.h"
+#include "cm_curl.h"
+#include "cm_zlib.h"
+#include "cmsys/Base64.h"
+#include "cmsys/Process.h"
+#include "cmsys/RegularExpression.hxx"
+#include <iomanip>
+#include <sstream>
+#include <stdio.h>
+#include <time.h>
+#include <utility>
cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler)
{
this->CTest = handler->CTest;
this->TestHandler = handler;
- this->TestProcess = 0;
- this->TestResult.ExecutionTime =0;
+ this->TestProcess = CM_NULLPTR;
+ this->TestResult.ExecutionTime = 0;
this->TestResult.ReturnValue = 0;
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
this->TestResult.TestCount = 0;
- this->TestResult.Properties = 0;
+ this->TestResult.Properties = CM_NULLPTR;
this->ProcessOutput = "";
this->CompressedOutput = "";
this->CompressionRatio = 2;
this->StopTimePassed = false;
+ this->NumberOfRunsLeft = 1; // default to 1 run of the test
+ this->RunUntilFail = false; // default to run the test once
+ this->RunAgain = false; // default to not having to run again
}
cmCTestRunTest::~cmCTestRunTest()
{
}
-//----------------------------------------------------------------------------
bool cmCTestRunTest::CheckOutput()
{
// Read lines for up to 0.1 seconds of total time.
double timeout = 0.1;
double timeEnd = cmSystemTools::GetTime() + timeout;
std::string line;
- while((timeout = timeEnd - cmSystemTools::GetTime(), timeout > 0))
- {
+ while ((timeout = timeEnd - cmSystemTools::GetTime(), timeout > 0)) {
int p = this->TestProcess->GetNextOutputLine(line, timeout);
- if(p == cmsysProcess_Pipe_None)
- {
+ if (p == cmsysProcess_Pipe_None) {
// Process has terminated and all output read.
return false;
- }
- else if(p == cmsysProcess_Pipe_STDOUT ||
- p == cmsysProcess_Pipe_STDERR)
- {
+ }
+ if (p == cmsysProcess_Pipe_STDOUT) {
// Store this line of output.
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- this->GetIndex() << ": " << line << std::endl);
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex()
+ << ": " << line << std::endl);
this->ProcessOutput += line;
this->ProcessOutput += "\n";
+
+ // Check for TIMEOUT_AFTER_MATCH property.
+ if (!this->TestProperties->TimeoutRegularExpressions.empty()) {
+ std::vector<
+ std::pair<cmsys::RegularExpression, std::string> >::iterator regIt;
+ for (regIt = this->TestProperties->TimeoutRegularExpressions.begin();
+ regIt != this->TestProperties->TimeoutRegularExpressions.end();
+ ++regIt) {
+ if (regIt->first.find(this->ProcessOutput.c_str())) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex()
+ << ": "
+ << "Test timeout changed to "
+ << this->TestProperties->AlternateTimeout
+ << std::endl);
+ this->TestProcess->ResetStartTime();
+ this->TestProcess->ChangeTimeout(
+ this->TestProperties->AlternateTimeout);
+ this->TestProperties->TimeoutRegularExpressions.clear();
+ break;
+ }
+ }
}
- else // if(p == cmsysProcess_Pipe_Timeout)
- {
+ } else { // if(p == cmsysProcess_Pipe_Timeout)
break;
- }
}
+ }
return true;
}
-//---------------------------------------------------------
// Streamed compression of test output. The compressed data
// is appended to this->CompressedOutput
void cmCTestRunTest::CompressOutput()
@@ -79,10 +98,9 @@ void cmCTestRunTest::CompressOutput()
int ret;
z_stream strm;
- unsigned char* in =
- reinterpret_cast<unsigned char*>(
+ unsigned char* in = reinterpret_cast<unsigned char*>(
const_cast<char*>(this->ProcessOutput.c_str()));
- //zlib makes the guarantee that this is the maximum output size
+ // zlib makes the guarantee that this is the maximum output size
int outSize = static_cast<int>(
static_cast<double>(this->ProcessOutput.size()) * 1.001 + 13.0);
unsigned char* out = new unsigned char[outSize];
@@ -90,12 +108,11 @@ void cmCTestRunTest::CompressOutput()
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
- ret = deflateInit(&strm, -1); //default compression level
- if (ret != Z_OK)
- {
+ ret = deflateInit(&strm, -1); // default compression level
+ if (ret != Z_OK) {
delete[] out;
return;
- }
+ }
strm.avail_in = static_cast<uInt>(this->ProcessOutput.size());
strm.next_in = in;
@@ -103,134 +120,124 @@ void cmCTestRunTest::CompressOutput()
strm.next_out = out;
ret = deflate(&strm, Z_FINISH);
- if(ret == Z_STREAM_ERROR || ret != Z_STREAM_END)
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Error during output "
- "compression. Sending uncompressed output." << std::endl);
+ if (ret != Z_STREAM_END) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error during output compression. Sending uncompressed output."
+ << std::endl);
delete[] out;
return;
- }
+ }
(void)deflateEnd(&strm);
- unsigned char *encoded_buffer
- = new unsigned char[static_cast<int>(outSize * 1.5)];
+ unsigned char* encoded_buffer =
+ new unsigned char[static_cast<int>(outSize * 1.5)];
- unsigned long rlen
- = cmsysBase64_Encode(out, strm.total_out, encoded_buffer, 1);
+ size_t rlen = cmsysBase64_Encode(out, strm.total_out, encoded_buffer, 1);
- for(unsigned long i = 0; i < rlen; i++)
- {
+ this->CompressedOutput.clear();
+ for (size_t i = 0; i < rlen; i++) {
this->CompressedOutput += encoded_buffer[i];
- }
+ }
- if(strm.total_in)
- {
- this->CompressionRatio = static_cast<double>(strm.total_out) /
- static_cast<double>(strm.total_in);
- }
+ if (strm.total_in) {
+ this->CompressionRatio =
+ static_cast<double>(strm.total_out) / static_cast<double>(strm.total_in);
+ }
- delete [] encoded_buffer;
- delete [] out;
+ delete[] encoded_buffer;
+ delete[] out;
}
-//---------------------------------------------------------
bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
{
if ((!this->TestHandler->MemCheck &&
- this->CTest->ShouldCompressTestOutput()) ||
+ this->CTest->ShouldCompressTestOutput()) ||
(this->TestHandler->MemCheck &&
- this->CTest->ShouldCompressMemCheckOutput()))
- {
+ this->CTest->ShouldCompressTestOutput())) {
this->CompressOutput();
- }
+ }
this->WriteLogOutputTop(completed, total);
std::string reason;
bool passed = true;
- int res = started ? this->TestProcess->GetProcessStatus()
- : cmsysProcess_State_Error;
+ int res =
+ started ? this->TestProcess->GetProcessStatus() : cmsysProcess_State_Error;
int retVal = this->TestProcess->GetExitValue();
- std::vector<std::pair<cmsys::RegularExpression,
- std::string> >::iterator passIt;
+ std::vector<std::pair<cmsys::RegularExpression, std::string> >::iterator
+ passIt;
bool forceFail = false;
+ bool skipped = false;
bool outputTestErrorsToConsole = false;
- if ( this->TestProperties->RequiredRegularExpressions.size() > 0 )
- {
+ if (!this->TestProperties->RequiredRegularExpressions.empty() &&
+ this->FailedDependencies.empty()) {
bool found = false;
- for ( passIt = this->TestProperties->RequiredRegularExpressions.begin();
- passIt != this->TestProperties->RequiredRegularExpressions.end();
- ++ passIt )
- {
- if ( passIt->first.find(this->ProcessOutput.c_str()) )
- {
+ for (passIt = this->TestProperties->RequiredRegularExpressions.begin();
+ passIt != this->TestProperties->RequiredRegularExpressions.end();
+ ++passIt) {
+ if (passIt->first.find(this->ProcessOutput.c_str())) {
found = true;
reason = "Required regular expression found.";
break;
- }
}
- if ( !found )
- {
+ }
+ if (!found) {
reason = "Required regular expression not found.";
forceFail = true;
- }
- reason += "Regex=[";
- for ( passIt = this->TestProperties->RequiredRegularExpressions.begin();
- passIt != this->TestProperties->RequiredRegularExpressions.end();
- ++ passIt )
- {
+ }
+ reason += "Regex=[";
+ for (passIt = this->TestProperties->RequiredRegularExpressions.begin();
+ passIt != this->TestProperties->RequiredRegularExpressions.end();
+ ++passIt) {
reason += passIt->second;
reason += "\n";
- }
- reason += "]";
}
- if ( this->TestProperties->ErrorRegularExpressions.size() > 0 )
- {
- for ( passIt = this->TestProperties->ErrorRegularExpressions.begin();
- passIt != this->TestProperties->ErrorRegularExpressions.end();
- ++ passIt )
- {
- if ( passIt->first.find(this->ProcessOutput.c_str()) )
- {
+ reason += "]";
+ }
+ if (!this->TestProperties->ErrorRegularExpressions.empty() &&
+ this->FailedDependencies.empty()) {
+ for (passIt = this->TestProperties->ErrorRegularExpressions.begin();
+ passIt != this->TestProperties->ErrorRegularExpressions.end();
+ ++passIt) {
+ if (passIt->first.find(this->ProcessOutput.c_str())) {
reason = "Error regular expression found in output.";
reason += " Regex=[";
reason += passIt->second;
reason += "]";
forceFail = true;
break;
- }
}
}
- if (res == cmsysProcess_State_Exited)
- {
- bool success =
- !forceFail && (retVal == 0 ||
- this->TestProperties->RequiredRegularExpressions.size());
- if((success && !this->TestProperties->WillFail)
- || (!success && this->TestProperties->WillFail))
- {
+ }
+ if (res == cmsysProcess_State_Exited) {
+ bool success = !forceFail &&
+ (retVal == 0 ||
+ !this->TestProperties->RequiredRegularExpressions.empty());
+ if (this->TestProperties->SkipReturnCode >= 0 &&
+ this->TestProperties->SkipReturnCode == retVal) {
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ std::ostringstream s;
+ s << "SKIP_RETURN_CODE=" << this->TestProperties->SkipReturnCode;
+ this->TestResult.CompletionStatus = s.str();
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Skipped ");
+ skipped = true;
+ } else if ((success && !this->TestProperties->WillFail) ||
+ (!success && this->TestProperties->WillFail)) {
this->TestResult.Status = cmCTestTestHandler::COMPLETED;
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Passed " );
- }
- else
- {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " Passed ");
+ } else {
this->TestResult.Status = cmCTestTestHandler::FAILED;
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed " << reason );
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed " << reason);
outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
- }
}
- else if ( res == cmsysProcess_State_Expired )
- {
+ } else if (res == cmsysProcess_State_Expired) {
cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout ");
this->TestResult.Status = cmCTestTestHandler::TIMEOUT;
outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
- }
- else if ( res == cmsysProcess_State_Exception )
- {
+ } else if (res == cmsysProcess_State_Exception) {
outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Exception: ");
- switch(this->TestProcess->GetExitException())
- {
+ switch (this->TestProcess->GetExitException()) {
case cmsysProcess_Exception_Fault:
cmCTestLog(this->CTest, HANDLER_OUTPUT, "SegFault");
this->TestResult.Status = cmCTestTestHandler::SEGFAULT;
@@ -250,59 +257,52 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
default:
cmCTestLog(this->CTest, HANDLER_OUTPUT, "Other");
this->TestResult.Status = cmCTestTestHandler::OTHER_FAULT;
- }
}
- else //cmsysProcess_State_Error
- {
+ } else if ("Disabled" == this->TestResult.CompletionStatus) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Not Run (Disabled) ");
+ } else // cmsysProcess_State_Error
+ {
cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Not Run ");
- }
+ }
passed = this->TestResult.Status == cmCTestTestHandler::COMPLETED;
char buf[1024];
sprintf(buf, "%6.2f sec", this->TestProcess->GetTotalTime());
- cmCTestLog(this->CTest, HANDLER_OUTPUT, buf << "\n" );
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, buf << "\n");
- if ( outputTestErrorsToConsole )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, this->ProcessOutput << std::endl );
- }
+ if (outputTestErrorsToConsole) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, this->ProcessOutput << std::endl);
+ }
- if ( this->TestHandler->LogFile )
- {
+ if (this->TestHandler->LogFile) {
*this->TestHandler->LogFile << "Test time = " << buf << std::endl;
- }
-
- // Set the working directory to the tests directory
- std::string oldpath = cmSystemTools::GetCurrentWorkingDirectory();
- cmSystemTools::ChangeDirectory(this->TestProperties->Directory.c_str());
-
- this->DartProcessing();
-
- // restore working directory
- cmSystemTools::ChangeDirectory(oldpath.c_str());
+ }
+ // Set the working directory to the tests directory to process Dart files.
+ {
+ cmWorkingDirectory workdir(this->TestProperties->Directory);
+ this->DartProcessing();
+ }
// if this is doing MemCheck then all the output needs to be put into
// Output since that is what is parsed by cmCTestMemCheckHandler
- if(!this->TestHandler->MemCheck && started)
- {
- this->TestHandler->CleanTestOutput(this->ProcessOutput,
- static_cast<size_t>
- (this->TestResult.Status == cmCTestTestHandler::COMPLETED ?
- this->TestHandler->CustomMaximumPassedTestOutputSize :
- this->TestHandler->CustomMaximumFailedTestOutputSize));
- }
+ if (!this->TestHandler->MemCheck && started) {
+ this->TestHandler->CleanTestOutput(
+ this->ProcessOutput,
+ static_cast<size_t>(
+ this->TestResult.Status == cmCTestTestHandler::COMPLETED
+ ? this->TestHandler->CustomMaximumPassedTestOutputSize
+ : this->TestHandler->CustomMaximumFailedTestOutputSize));
+ }
this->TestResult.Reason = reason;
- if (this->TestHandler->LogFile)
- {
+ if (this->TestHandler->LogFile) {
bool pass = true;
const char* reasonType = "Test Pass Reason";
- if(this->TestResult.Status != cmCTestTestHandler::COMPLETED &&
- this->TestResult.Status != cmCTestTestHandler::NOT_RUN)
- {
+ if (this->TestResult.Status != cmCTestTestHandler::COMPLETED &&
+ this->TestResult.Status != cmCTestTestHandler::NOT_RUN) {
reasonType = "Test Fail Reason";
pass = false;
- }
+ }
double ttime = this->TestProcess->GetTotalTime();
int hours = static_cast<int>(ttime / (60 * 60));
int minutes = static_cast<int>(ttime / 60) % 60;
@@ -312,105 +312,134 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
*this->TestHandler->LogFile
<< "----------------------------------------------------------"
<< std::endl;
- if(this->TestResult.Reason.size())
- {
+ if (!this->TestResult.Reason.empty()) {
*this->TestHandler->LogFile << reasonType << ":\n"
- << this->TestResult.Reason << "\n";
- }
- else
- {
- if(pass)
- {
+ << this->TestResult.Reason << "\n";
+ } else {
+ if (pass) {
*this->TestHandler->LogFile << "Test Passed.\n";
- }
- else
- {
+ } else {
*this->TestHandler->LogFile << "Test Failed.\n";
- }
}
- *this->TestHandler->LogFile << "\"" << this->TestProperties->Name.c_str()
+ }
+ *this->TestHandler->LogFile
+ << "\"" << this->TestProperties->Name
<< "\" end time: " << this->CTest->CurrentTime() << std::endl
- << "\"" << this->TestProperties->Name.c_str() << "\" time elapsed: "
- << buffer << std::endl
+ << "\"" << this->TestProperties->Name << "\" time elapsed: " << buffer
+ << std::endl
<< "----------------------------------------------------------"
- << std::endl << std::endl;
- }
+ << std::endl
+ << std::endl;
+ }
// if the test actually started and ran
// record the results in TestResult
- if(started)
- {
+ if (started) {
bool compress = !this->TestHandler->MemCheck &&
- this->CompressionRatio < 1 &&
- this->CTest->ShouldCompressTestOutput();
- this->TestResult.Output = compress ? this->CompressedOutput
- : this->ProcessOutput;
+ this->CompressionRatio < 1 && this->CTest->ShouldCompressTestOutput();
+ this->TestResult.Output =
+ compress ? this->CompressedOutput : this->ProcessOutput;
this->TestResult.CompressOutput = compress;
this->TestResult.ReturnValue = this->TestProcess->GetExitValue();
- this->TestResult.CompletionStatus = "Completed";
+ if (!skipped) {
+ this->TestResult.CompletionStatus = "Completed";
+ }
this->TestResult.ExecutionTime = this->TestProcess->GetTotalTime();
this->MemCheckPostProcess();
this->ComputeWeightedCost();
- }
- // Always push the current TestResult onto the
+ }
+ // If the test does not need to rerun push the current TestResult onto the
// TestHandler vector
- this->TestHandler->TestResults.push_back(this->TestResult);
+ if (!this->NeedsToRerun()) {
+ this->TestHandler->TestResults.push_back(this->TestResult);
+ }
delete this->TestProcess;
- return passed;
+ return passed || skipped;
}
-//----------------------------------------------------------------------
+bool cmCTestRunTest::StartAgain()
+{
+ if (!this->RunAgain) {
+ return false;
+ }
+ this->RunAgain = false; // reset
+ // change to tests directory
+ cmWorkingDirectory workdir(this->TestProperties->Directory);
+ this->StartTest(this->TotalNumberOfTests);
+ return true;
+}
+
+bool cmCTestRunTest::NeedsToRerun()
+{
+ this->NumberOfRunsLeft--;
+ if (this->NumberOfRunsLeft == 0) {
+ return false;
+ }
+ // if number of runs left is not 0, and we are running until
+ // we find a failed test, then return true so the test can be
+ // restarted
+ if (this->RunUntilFail &&
+ this->TestResult.Status == cmCTestTestHandler::COMPLETED) {
+ this->RunAgain = true;
+ return true;
+ }
+ return false;
+}
void cmCTestRunTest::ComputeWeightedCost()
{
double prev = static_cast<double>(this->TestProperties->PreviousRuns);
double avgcost = static_cast<double>(this->TestProperties->Cost);
double current = this->TestResult.ExecutionTime;
- if(this->TestResult.Status == cmCTestTestHandler::COMPLETED)
- {
+ if (this->TestResult.Status == cmCTestTestHandler::COMPLETED) {
this->TestProperties->Cost =
static_cast<float>(((prev * avgcost) + current) / (prev + 1.0));
this->TestProperties->PreviousRuns++;
- }
+ }
}
-//----------------------------------------------------------------------
void cmCTestRunTest::MemCheckPostProcess()
{
- if(!this->TestHandler->MemCheck)
- {
+ if (!this->TestHandler->MemCheck) {
return;
- }
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index
- << ": process test output now: "
- << this->TestProperties->Name.c_str() << " "
- << this->TestResult.Name.c_str() << std::endl);
- cmCTestMemCheckHandler * handler = static_cast<cmCTestMemCheckHandler*>
- (this->TestHandler);
- switch ( handler->MemoryTesterStyle )
- {
- case cmCTestMemCheckHandler::VALGRIND:
- handler->PostProcessValgrindTest(this->TestResult, this->Index);
- break;
- case cmCTestMemCheckHandler::PURIFY:
- handler->PostProcessPurifyTest(this->TestResult, this->Index);
- break;
- case cmCTestMemCheckHandler::BOUNDS_CHECKER:
- handler->PostProcessBoundsCheckerTest(this->TestResult, this->Index);
- break;
- default:
- break;
- }
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index
+ << ": process test output now: "
+ << this->TestProperties->Name << " "
+ << this->TestResult.Name << std::endl,
+ this->TestHandler->GetQuiet());
+ cmCTestMemCheckHandler* handler =
+ static_cast<cmCTestMemCheckHandler*>(this->TestHandler);
+ handler->PostProcessTest(this->TestResult, this->Index);
}
-//----------------------------------------------------------------------
// Starts the execution of a test. Returns once it has started
bool cmCTestRunTest::StartTest(size_t total)
{
- cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(2*getNumWidth(total) + 8)
- << "Start "
- << std::setw(getNumWidth(this->TestHandler->GetMaxIndex()))
- << this->TestProperties->Index << ": "
- << this->TestProperties->Name << std::endl);
+ this->TotalNumberOfTests = total; // save for rerun case
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(2 * getNumWidth(total) + 8)
+ << "Start "
+ << std::setw(getNumWidth(this->TestHandler->GetMaxIndex()))
+ << this->TestProperties->Index << ": "
+ << this->TestProperties->Name << std::endl);
+ this->ProcessOutput.clear();
+
+ // Return immediately if test is disabled
+ if (this->TestProperties->Disabled) {
+ this->TestResult.Properties = this->TestProperties;
+ this->TestResult.ExecutionTime = 0;
+ this->TestResult.CompressOutput = false;
+ this->TestResult.ReturnValue = -1;
+ this->TestResult.CompletionStatus = "Disabled";
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ this->TestResult.TestCount = this->TestProperties->Index;
+ this->TestResult.Name = this->TestProperties->Name;
+ this->TestResult.Path = this->TestProperties->Directory;
+ this->TestProcess = new cmProcess;
+ this->TestResult.Output = "Disabled";
+ this->TestResult.FullCommandLine = "";
+ return false;
+ }
+
this->ComputeArguments();
std::vector<std::string>& args = this->TestProperties->Args;
this->TestResult.Properties = this->TestProperties;
@@ -421,167 +450,175 @@ bool cmCTestRunTest::StartTest(size_t total)
this->TestResult.Status = cmCTestTestHandler::BAD_COMMAND;
this->TestResult.TestCount = this->TestProperties->Index;
this->TestResult.Name = this->TestProperties->Name;
- this->TestResult.Path = this->TestProperties->Directory.c_str();
+ this->TestResult.Path = this->TestProperties->Directory;
- if(args.size() >= 2 && args[1] == "NOT_AVAILABLE")
- {
+ if (!this->FailedDependencies.empty()) {
+ this->TestProcess = new cmProcess;
+ std::string msg = "Failed test dependencies:";
+ for (std::set<std::string>::const_iterator it =
+ this->FailedDependencies.begin();
+ it != this->FailedDependencies.end(); ++it) {
+ msg += " " + *it;
+ }
+ *this->TestHandler->LogFile << msg << std::endl;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, msg << std::endl);
+ this->TestResult.Output = msg;
+ this->TestResult.FullCommandLine = "";
+ this->TestResult.CompletionStatus = "Fixture dependency failed";
+ this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+ return false;
+ }
+
+ if (args.size() >= 2 && args[1] == "NOT_AVAILABLE") {
this->TestProcess = new cmProcess;
std::string msg;
- if(this->CTest->GetConfigType().empty())
- {
+ if (this->CTest->GetConfigType().empty()) {
msg = "Test not available without configuration.";
msg += " (Missing \"-C <config>\"?)";
- }
- else
- {
+ } else {
msg = "Test not available in configuration \"";
msg += this->CTest->GetConfigType();
msg += "\".";
- }
+ }
*this->TestHandler->LogFile << msg << std::endl;
cmCTestLog(this->CTest, ERROR_MESSAGE, msg << std::endl);
this->TestResult.Output = msg;
this->TestResult.FullCommandLine = "";
- this->TestResult.CompletionStatus = "Not Run";
+ this->TestResult.CompletionStatus = "Missing Configuration";
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
return false;
- }
+ }
// Check if all required files exist
- for(std::vector<std::string>::iterator i =
- this->TestProperties->RequiredFiles.begin();
- i != this->TestProperties->RequiredFiles.end(); ++i)
- {
+ for (std::vector<std::string>::iterator i =
+ this->TestProperties->RequiredFiles.begin();
+ i != this->TestProperties->RequiredFiles.end(); ++i) {
std::string file = *i;
- if(!cmSystemTools::FileExists(file.c_str()))
- {
- //Required file was not found
+ if (!cmSystemTools::FileExists(file.c_str())) {
+ // Required file was not found
this->TestProcess = new cmProcess;
- *this->TestHandler->LogFile << "Unable to find required file: "
- << file.c_str() << std::endl;
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Unable to find required file: "
- << file.c_str() << std::endl);
+ *this->TestHandler->LogFile << "Unable to find required file: " << file
+ << std::endl;
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unable to find required file: " << file << std::endl);
this->TestResult.Output = "Unable to find required file: " + file;
this->TestResult.FullCommandLine = "";
- this->TestResult.CompletionStatus = "Not Run";
+ this->TestResult.CompletionStatus = "Required Files Missing";
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
return false;
- }
}
+ }
// log and return if we did not find the executable
- if (this->ActualCommand == "")
- {
+ if (this->ActualCommand == "") {
// if the command was not found create a TestResult object
// that has that information
this->TestProcess = new cmProcess;
- *this->TestHandler->LogFile << "Unable to find executable: "
- << args[1].c_str() << std::endl;
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Unable to find executable: "
- << args[1].c_str() << std::endl);
+ *this->TestHandler->LogFile << "Unable to find executable: " << args[1]
+ << std::endl;
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Unable to find executable: " << args[1] << std::endl);
this->TestResult.Output = "Unable to find executable: " + args[1];
this->TestResult.FullCommandLine = "";
- this->TestResult.CompletionStatus = "Not Run";
+ this->TestResult.CompletionStatus = "Unable to find executable";
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
return false;
- }
+ }
this->StartTime = this->CTest->CurrentTime();
double timeout = this->ResolveTimeout();
- if(this->StopTimePassed)
- {
+ if (this->StopTimePassed) {
return false;
- }
+ }
return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout,
&this->TestProperties->Environment);
}
-//----------------------------------------------------------------------
void cmCTestRunTest::ComputeArguments()
{
+ this->Arguments.clear(); // reset becaue this might be a rerun
std::vector<std::string>::const_iterator j =
this->TestProperties->Args.begin();
++j; // skip test name
-
// find the test executable
- if(this->TestHandler->MemCheck)
- {
- cmCTestMemCheckHandler * handler = static_cast<cmCTestMemCheckHandler*>
- (this->TestHandler);
- this->ActualCommand = handler->MemoryTester.c_str();
+ if (this->TestHandler->MemCheck) {
+ cmCTestMemCheckHandler* handler =
+ static_cast<cmCTestMemCheckHandler*>(this->TestHandler);
+ this->ActualCommand = handler->MemoryTester;
this->TestProperties->Args[1] = this->TestHandler->FindTheExecutable(
this->TestProperties->Args[1].c_str());
- }
- else
- {
- this->ActualCommand =
- this->TestHandler->FindTheExecutable(
+ } else {
+ this->ActualCommand = this->TestHandler->FindTheExecutable(
this->TestProperties->Args[1].c_str());
- ++j; //skip the executable (it will be actualCommand)
- }
- std::string testCommand
- = cmSystemTools::ConvertToOutputPath(this->ActualCommand.c_str());
+ ++j; // skip the executable (it will be actualCommand)
+ }
+ std::string testCommand =
+ cmSystemTools::ConvertToOutputPath(this->ActualCommand.c_str());
- //Prepends memcheck args to our command string
+ // Prepends memcheck args to our command string
this->TestHandler->GenerateTestCommand(this->Arguments, this->Index);
- for(std::vector<std::string>::iterator i = this->Arguments.begin();
- i != this->Arguments.end(); ++i)
- {
+ for (std::vector<std::string>::iterator i = this->Arguments.begin();
+ i != this->Arguments.end(); ++i) {
testCommand += " \"";
testCommand += *i;
testCommand += "\"";
- }
+ }
- for(;j != this->TestProperties->Args.end(); ++j)
- {
+ for (; j != this->TestProperties->Args.end(); ++j) {
testCommand += " \"";
testCommand += *j;
testCommand += "\"";
this->Arguments.push_back(*j);
- }
+ }
this->TestResult.FullCommandLine = testCommand;
+ // Print the test command in verbose mode
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
- << this->Index << ": "
- << (this->TestHandler->MemCheck?"MemCheck":"Test")
- << " command: " << testCommand
- << std::endl);
+ << this->Index << ": "
+ << (this->TestHandler->MemCheck ? "MemCheck" : "Test")
+ << " command: " << testCommand << std::endl);
+
+ // Print any test-specific env vars in verbose mode
+ if (!this->TestProperties->Environment.empty()) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index
+ << ": "
+ << "Environment variables: " << std::endl);
+ }
+ for (std::vector<std::string>::const_iterator e =
+ this->TestProperties->Environment.begin();
+ e != this->TestProperties->Environment.end(); ++e) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index << ": " << *e
+ << std::endl);
+ }
}
-//----------------------------------------------------------------------
void cmCTestRunTest::DartProcessing()
{
if (!this->ProcessOutput.empty() &&
- this->ProcessOutput.find("<DartMeasurement") != this->ProcessOutput.npos)
- {
- if (this->TestHandler->DartStuff.find(this->ProcessOutput.c_str()))
- {
- std::string dartString = this->TestHandler->DartStuff.match(1);
+ this->ProcessOutput.find("<DartMeasurement") != std::string::npos) {
+ if (this->TestHandler->DartStuff.find(this->ProcessOutput.c_str())) {
+ this->TestResult.DartString = this->TestHandler->DartStuff.match(1);
// keep searching and replacing until none are left
- while (this->TestHandler->DartStuff1.find(this->ProcessOutput.c_str()))
- {
+ while (this->TestHandler->DartStuff1.find(this->ProcessOutput.c_str())) {
// replace the exact match for the string
- cmSystemTools::ReplaceString(this->ProcessOutput,
- this->TestHandler->DartStuff1.match(1).c_str(), "");
- }
- this->TestResult.RegressionImages
- = this->TestHandler->GenerateRegressionImages(dartString);
+ cmSystemTools::ReplaceString(
+ this->ProcessOutput, this->TestHandler->DartStuff1.match(1).c_str(),
+ "");
}
}
+ }
}
-//----------------------------------------------------------------------
double cmCTestRunTest::ResolveTimeout()
{
double timeout = this->TestProperties->Timeout;
- if(this->CTest->GetStopTime() == "")
- {
+ if (this->CTest->GetStopTime() == "") {
return timeout;
- }
+ }
struct tm* lctime;
- time_t current_time = time(0);
+ time_t current_time = time(CM_NULLPTR);
lctime = gmtime(&current_time);
int gm_hour = lctime->tm_hour;
time_t gm_time = mktime(lctime);
@@ -589,87 +626,77 @@ double cmCTestRunTest::ResolveTimeout()
int local_hour = lctime->tm_hour;
int tzone_offset = local_hour - gm_hour;
- if(gm_time > current_time && gm_hour < local_hour)
- {
+ if (gm_time > current_time && gm_hour < local_hour) {
// this means gm_time is on the next day
tzone_offset -= 24;
- }
- else if(gm_time < current_time && gm_hour > local_hour)
- {
+ } else if (gm_time < current_time && gm_hour > local_hour) {
// this means gm_time is on the previous day
tzone_offset += 24;
- }
+ }
tzone_offset *= 100;
char buf[1024];
// add todays year day and month to the time in str because
// curl_getdate no longer assumes the day is today
- sprintf(buf, "%d%02d%02d %s %+05i",
- lctime->tm_year + 1900,
- lctime->tm_mon + 1,
- lctime->tm_mday,
- this->CTest->GetStopTime().c_str(),
- tzone_offset);
+ sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900,
+ lctime->tm_mon + 1, lctime->tm_mday,
+ this->CTest->GetStopTime().c_str(), tzone_offset);
time_t stop_time = curl_getdate(buf, &current_time);
- if(stop_time == -1)
- {
+ if (stop_time == -1) {
return timeout;
- }
-
- //the stop time refers to the next day
- if(this->CTest->NextDayStopTime)
- {
- stop_time += 24*60*60;
- }
- int stop_timeout = static_cast<int>(stop_time - current_time) % (24*60*60);
+ }
+
+ // the stop time refers to the next day
+ if (this->CTest->NextDayStopTime) {
+ stop_time += 24 * 60 * 60;
+ }
+ int stop_timeout =
+ static_cast<int>(stop_time - current_time) % (24 * 60 * 60);
this->CTest->LastStopTimeout = stop_timeout;
- if(stop_timeout <= 0 || stop_timeout > this->CTest->LastStopTimeout)
- {
+ if (stop_timeout <= 0 || stop_timeout > this->CTest->LastStopTimeout) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. "
- "Stopping all tests." << std::endl);
+ "Stopping all tests."
+ << std::endl);
this->StopTimePassed = true;
return 0;
- }
- return timeout == 0 ? stop_timeout :
- (timeout < stop_timeout ? timeout : stop_timeout);
+ }
+ return timeout == 0 ? stop_timeout
+ : (timeout < stop_timeout ? timeout : stop_timeout);
}
-//----------------------------------------------------------------------
bool cmCTestRunTest::ForkProcess(double testTimeOut, bool explicitTimeout,
- std::vector<std::string>* environment)
+ std::vector<std::string>* environment)
{
this->TestProcess = new cmProcess;
this->TestProcess->SetId(this->Index);
this->TestProcess->SetWorkingDirectory(
- this->TestProperties->Directory.c_str());
+ this->TestProperties->Directory.c_str());
this->TestProcess->SetCommand(this->ActualCommand.c_str());
this->TestProcess->SetCommandArguments(this->Arguments);
// determine how much time we have
double timeout = this->CTest->GetRemainingTimeAllowed() - 120;
- if (this->CTest->GetTimeOut() > 0 && this->CTest->GetTimeOut() < timeout)
- {
+ if (this->CTest->GetTimeOut() > 0 && this->CTest->GetTimeOut() < timeout) {
timeout = this->CTest->GetTimeOut();
- }
- if (testTimeOut > 0
- && testTimeOut < this->CTest->GetRemainingTimeAllowed())
- {
+ }
+ if (testTimeOut > 0 &&
+ testTimeOut < this->CTest->GetRemainingTimeAllowed()) {
timeout = testTimeOut;
- }
+ }
// always have at least 1 second if we got to here
- if (timeout <= 0)
- {
+ if (timeout <= 0) {
timeout = 1;
- }
+ }
// handle timeout explicitly set to 0
- if (testTimeOut == 0 && explicitTimeout)
- {
+ if (testTimeOut == 0 && explicitTimeout) {
timeout = 0;
- }
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index << ": "
- << "Test timeout computed to be: " << timeout << "\n");
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index
+ << ": "
+ << "Test timeout computed to be: " << timeout << "\n",
+ this->TestHandler->GetQuiet());
this->TestProcess->SetTimeout(timeout);
@@ -677,67 +704,82 @@ bool cmCTestRunTest::ForkProcess(double testTimeOut, bool explicitTimeout,
cmSystemTools::SaveRestoreEnvironment sre;
#endif
- if (environment && environment->size()>0)
- {
+ if (environment && !environment->empty()) {
cmSystemTools::AppendEnv(*environment);
- }
+ }
return this->TestProcess->StartProcess();
}
void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total)
{
- cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(getNumWidth(total))
- << completed << "/");
- cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(getNumWidth(total))
- << total << " ");
-
- if ( this->TestHandler->MemCheck )
- {
+ // if this is the last or only run of this test
+ // then print out completed / total
+ // Only issue is if a test fails and we are running until fail
+ // then it will never print out the completed / total, same would
+ // got for run until pass. Trick is when this is called we don't
+ // yet know if we are passing or failing.
+ if (this->NumberOfRunsLeft == 1) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(getNumWidth(total))
+ << completed << "/");
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(getNumWidth(total))
+ << total << " ");
+ }
+ // if this is one of several runs of a test just print blank space
+ // to keep things neat
+ else {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(getNumWidth(total))
+ << " "
+ << " ");
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(getNumWidth(total))
+ << " "
+ << " ");
+ }
+
+ if (this->TestHandler->MemCheck) {
cmCTestLog(this->CTest, HANDLER_OUTPUT, "MemCheck");
- }
- else
- {
+ } else {
cmCTestLog(this->CTest, HANDLER_OUTPUT, "Test");
- }
+ }
- cmOStringStream indexStr;
+ std::ostringstream indexStr;
indexStr << " #" << this->Index << ":";
cmCTestLog(this->CTest, HANDLER_OUTPUT,
std::setw(3 + getNumWidth(this->TestHandler->GetMaxIndex()))
- << indexStr.str().c_str());
+ << indexStr.str());
cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
const int maxTestNameWidth = this->CTest->GetMaxTestNameWidth();
std::string outname = this->TestProperties->Name + " ";
outname.resize(maxTestNameWidth + 4, '.');
*this->TestHandler->LogFile << this->TestProperties->Index << "/"
- << this->TestHandler->TotalNumberOfTests << " Testing: "
- << this->TestProperties->Name << std::endl;
+ << this->TestHandler->TotalNumberOfTests
+ << " Testing: " << this->TestProperties->Name
+ << std::endl;
*this->TestHandler->LogFile << this->TestProperties->Index << "/"
- << this->TestHandler->TotalNumberOfTests
- << " Test: " << this->TestProperties->Name.c_str() << std::endl;
+ << this->TestHandler->TotalNumberOfTests
+ << " Test: " << this->TestProperties->Name
+ << std::endl;
*this->TestHandler->LogFile << "Command: \"" << this->ActualCommand << "\"";
for (std::vector<std::string>::iterator i = this->Arguments.begin();
- i != this->Arguments.end(); ++i)
- {
- *this->TestHandler->LogFile
- << " \"" << i->c_str() << "\"";
- }
- *this->TestHandler->LogFile << std::endl
+ i != this->Arguments.end(); ++i) {
+ *this->TestHandler->LogFile << " \"" << *i << "\"";
+ }
+ *this->TestHandler->LogFile
+ << std::endl
<< "Directory: " << this->TestProperties->Directory << std::endl
- << "\"" << this->TestProperties->Name.c_str() << "\" start time: "
- << this->StartTime << std::endl;
+ << "\"" << this->TestProperties->Name
+ << "\" start time: " << this->StartTime << std::endl;
*this->TestHandler->LogFile
<< "Output:" << std::endl
<< "----------------------------------------------------------"
<< std::endl;
- *this->TestHandler->LogFile
- << this->ProcessOutput.c_str() << "<end of output>" << std::endl;
+ *this->TestHandler->LogFile << this->ProcessOutput << "<end of output>"
+ << std::endl;
cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str());
- cmCTestLog(this->CTest, DEBUG, "Testing "
- << this->TestProperties->Name.c_str() << " ... ");
+ cmCTestLog(this->CTest, DEBUG, "Testing " << this->TestProperties->Name
+ << " ... ");
}
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index 476f3e126..d3bb2296f 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -1,20 +1,19 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestRunTest_h
#define cmCTestRunTest_h
-#include <cmStandardIncludes.h>
-#include <cmCTestTestHandler.h>
-#include <cmProcess.h>
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <set>
+#include <stddef.h>
+#include <string>
+#include <vector>
+
+#include "cmCTestTestHandler.h"
+
+class cmCTest;
+class cmProcess;
/** \class cmRunTest
* \brief represents a single test to be run
@@ -27,22 +26,35 @@ public:
cmCTestRunTest(cmCTestTestHandler* handler);
~cmCTestRunTest();
- void SetTestProperties(cmCTestTestHandler::cmCTestTestProperties * prop)
- { this->TestProperties = prop; }
+ void SetNumberOfRuns(int n) { this->NumberOfRunsLeft = n; }
+ void SetRunUntilFailOn() { this->RunUntilFail = true; }
+ void SetTestProperties(cmCTestTestHandler::cmCTestTestProperties* prop)
+ {
+ this->TestProperties = prop;
+ }
- cmCTestTestHandler::cmCTestTestProperties * GetTestProperties()
- { return this->TestProperties; }
+ cmCTestTestHandler::cmCTestTestProperties* GetTestProperties()
+ {
+ return this->TestProperties;
+ }
void SetIndex(int i) { this->Index = i; }
int GetIndex() { return this->Index; }
+ void AddFailedDependency(const std::string& failedTest)
+ {
+ this->FailedDependencies.insert(failedTest);
+ }
+
std::string GetProcessOutput() { return this->ProcessOutput; }
bool IsStopTimePassed() { return this->StopTimePassed; }
cmCTestTestHandler::cmCTestTestResult GetTestResults()
- { return this->TestResult; }
+ {
+ return this->TestResult;
+ }
// Read and store output. Returns true if it must be called again.
bool CheckOutput();
@@ -50,15 +62,19 @@ public:
// Compresses the output, writing to CompressedOutput
void CompressOutput();
- //launch the test process, return whether it started correctly
+ // launch the test process, return whether it started correctly
bool StartTest(size_t total);
- //capture and report the test results
+ // capture and report the test results
bool EndTest(size_t completed, size_t total, bool started);
- //Called by ctest -N to log the command string
+ // Called by ctest -N to log the command string
void ComputeArguments();
void ComputeWeightedCost();
+
+ bool StartAgain();
+
private:
+ bool NeedsToRerun();
void DartProcessing();
void ExeNotFound(std::string exe);
// Figures out a final timeout which is min(STOP_TIME, NOW+TIMEOUT)
@@ -66,18 +82,18 @@ private:
bool ForkProcess(double testTimeOut, bool explicitTimeout,
std::vector<std::string>* environment);
void WriteLogOutputTop(size_t completed, size_t total);
- //Run post processing of the process output for MemCheck
+ // Run post processing of the process output for MemCheck
void MemCheckPostProcess();
- cmCTestTestHandler::cmCTestTestProperties * TestProperties;
- //Pointer back to the "parent"; the handler that invoked this test run
- cmCTestTestHandler * TestHandler;
- cmCTest * CTest;
- cmProcess * TestProcess;
- //If the executable to run is ctest, don't create a new process;
- //just instantiate a new cmTest. (Can be disabled for a single test
- //if this option is set to false.)
- //bool OptimizeForCTest;
+ cmCTestTestHandler::cmCTestTestProperties* TestProperties;
+ // Pointer back to the "parent"; the handler that invoked this test run
+ cmCTestTestHandler* TestHandler;
+ cmCTest* CTest;
+ cmProcess* TestProcess;
+ // If the executable to run is ctest, don't create a new process;
+ // just instantiate a new cmTest. (Can be disabled for a single test
+ // if this option is set to false.)
+ // bool OptimizeForCTest;
bool UsePrefixCommand;
std::string PrefixCommand;
@@ -85,28 +101,30 @@ private:
std::string ProcessOutput;
std::string CompressedOutput;
double CompressionRatio;
- //The test results
+ // The test results
cmCTestTestHandler::cmCTestTestResult TestResult;
int Index;
+ std::set<std::string> FailedDependencies;
std::string StartTime;
std::string ActualCommand;
std::vector<std::string> Arguments;
bool StopTimePassed;
+ bool RunUntilFail;
+ int NumberOfRunsLeft;
+ bool RunAgain;
+ size_t TotalNumberOfTests;
};
inline int getNumWidth(size_t n)
{
int numWidth = 1;
- if(n >= 10)
- {
+ if (n >= 10) {
numWidth = 2;
- }
- if(n >= 100)
- {
+ }
+ if (n >= 100) {
numWidth = 3;
- }
+ }
return numWidth;
}
#endif
-
diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx
index 2668c8eef..f60f78c21 100644
--- a/Source/CTest/cmCTestSVN.cxx
+++ b/Source/CTest/cmCTestSVN.cxx
@@ -1,41 +1,35 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestSVN.h"
#include "cmCTest.h"
+#include "cmCTestVC.h"
+#include "cmProcessTools.h"
#include "cmSystemTools.h"
#include "cmXMLParser.h"
-#include "cmXMLSafe.h"
+#include "cmXMLWriter.h"
-#include <cmsys/RegularExpression.hxx>
+#include "cmsys/RegularExpression.hxx"
+#include <map>
+#include <ostream>
+#include <stdlib.h>
+#include <string.h>
-struct cmCTestSVN::Revision: public cmCTestVC::Revision
+struct cmCTestSVN::Revision : public cmCTestVC::Revision
{
cmCTestSVN::SVNInfo* SVNInfo;
};
-//----------------------------------------------------------------------------
-cmCTestSVN::cmCTestSVN(cmCTest* ct, std::ostream& log):
- cmCTestGlobalVC(ct, log)
+cmCTestSVN::cmCTestSVN(cmCTest* ct, std::ostream& log)
+ : cmCTestGlobalVC(ct, log)
{
this->PriorRev = this->Unknown;
}
-//----------------------------------------------------------------------------
cmCTestSVN::~cmCTestSVN()
{
}
-//----------------------------------------------------------------------------
void cmCTestSVN::CleanupImpl()
{
std::vector<const char*> svn_cleanup;
@@ -45,64 +39,51 @@ void cmCTestSVN::CleanupImpl()
this->RunSVNCommand(svn_cleanup, &out, &err);
}
-//----------------------------------------------------------------------------
-class cmCTestSVN::InfoParser: public cmCTestVC::LineParser
+class cmCTestSVN::InfoParser : public cmCTestVC::LineParser
{
public:
- InfoParser(cmCTestSVN* svn,
- const char* prefix,
- std::string& rev,
- SVNInfo& svninfo):
- Rev(rev), SVNRepo(svninfo)
- {
+ InfoParser(cmCTestSVN* svn, const char* prefix, std::string& rev,
+ SVNInfo& svninfo)
+ : Rev(rev)
+ , SVNRepo(svninfo)
+ {
this->SetLog(&svn->Log, prefix);
this->RegexRev.compile("^Revision: ([0-9]+)");
this->RegexURL.compile("^URL: +([^ ]+) *$");
this->RegexRoot.compile("^Repository Root: +([^ ]+) *$");
- }
+ }
+
private:
std::string& Rev;
cmCTestSVN::SVNInfo& SVNRepo;
cmsys::RegularExpression RegexRev;
cmsys::RegularExpression RegexURL;
cmsys::RegularExpression RegexRoot;
- virtual bool ProcessLine()
- {
- if(this->RegexRev.find(this->Line))
- {
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexRev.find(this->Line)) {
this->Rev = this->RegexRev.match(1);
- }
- else if(this->RegexURL.find(this->Line))
- {
+ } else if (this->RegexURL.find(this->Line)) {
this->SVNRepo.URL = this->RegexURL.match(1);
- }
- else if(this->RegexRoot.find(this->Line))
- {
+ } else if (this->RegexRoot.find(this->Line)) {
this->SVNRepo.Root = this->RegexRoot.match(1);
- }
- return true;
}
+ return true;
+ }
};
-//----------------------------------------------------------------------------
static bool cmCTestSVNPathStarts(std::string const& p1, std::string const& p2)
{
// Does path p1 start with path p2?
- if(p1.size() == p2.size())
- {
+ if (p1.size() == p2.size()) {
return p1 == p2;
- }
- else if(p1.size() > p2.size() && p1[p2.size()] == '/')
- {
+ }
+ if (p1.size() > p2.size() && p1[p2.size()] == '/') {
return strncmp(p1.c_str(), p2.c_str(), p2.size()) == 0;
- }
- else
- {
- return false;
- }
+ }
+ return false;
}
-//----------------------------------------------------------------------------
std::string cmCTestSVN::LoadInfo(SVNInfo& svninfo)
{
// Run "svn info" to get the repository info from the work tree.
@@ -116,51 +97,46 @@ std::string cmCTestSVN::LoadInfo(SVNInfo& svninfo)
return rev;
}
-//----------------------------------------------------------------------------
-void cmCTestSVN::NoteOldRevision()
+bool cmCTestSVN::NoteOldRevision()
{
- // Info for root repository
- this->Repositories.push_back( SVNInfo("") );
- this->RootInfo = &(this->Repositories.back());
- // Info for the external repositories
- this->LoadExternals();
-
- // Get info for all the repositories
- std::list<SVNInfo>::iterator itbeg = this->Repositories.begin();
- std::list<SVNInfo>::iterator itend = this->Repositories.end();
- for( ; itbeg != itend ; itbeg++)
- {
+ if (!this->LoadRepositories()) {
+ return false;
+ }
+
+ std::vector<SVNInfo>::iterator itbeg = this->Repositories.begin();
+ std::vector<SVNInfo>::iterator itend = this->Repositories.end();
+ for (; itbeg != itend; itbeg++) {
SVNInfo& svninfo = *itbeg;
svninfo.OldRevision = this->LoadInfo(svninfo);
this->Log << "Revision for repository '" << svninfo.LocalPath
<< "' before update: " << svninfo.OldRevision << "\n";
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- " Old revision of external repository '"
- << svninfo.LocalPath << "' is: "
- << svninfo.OldRevision << "\n");
- }
+ cmCTestLog(
+ this->CTest, HANDLER_OUTPUT, " Old revision of external repository '"
+ << svninfo.LocalPath << "' is: " << svninfo.OldRevision << "\n");
+ }
// Set the global old revision to the one of the root
this->OldRevision = this->RootInfo->OldRevision;
this->PriorRev.Rev = this->OldRevision;
+ return true;
}
-//----------------------------------------------------------------------------
-void cmCTestSVN::NoteNewRevision()
+bool cmCTestSVN::NoteNewRevision()
{
- // Get info for the external repositories
- std::list<SVNInfo>::iterator itbeg = this->Repositories.begin();
- std::list<SVNInfo>::iterator itend = this->Repositories.end();
- for( ; itbeg != itend ; itbeg++)
- {
+ if (!this->LoadRepositories()) {
+ return false;
+ }
+
+ std::vector<SVNInfo>::iterator itbeg = this->Repositories.begin();
+ std::vector<SVNInfo>::iterator itend = this->Repositories.end();
+ for (; itbeg != itend; itbeg++) {
SVNInfo& svninfo = *itbeg;
svninfo.NewRevision = this->LoadInfo(svninfo);
this->Log << "Revision for repository '" << svninfo.LocalPath
<< "' after update: " << svninfo.NewRevision << "\n";
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- " New revision of external repository '"
- << svninfo.LocalPath << "' is: "
- << svninfo.NewRevision << "\n");
+ cmCTestLog(
+ this->CTest, HANDLER_OUTPUT, " New revision of external repository '"
+ << svninfo.LocalPath << "' is: " << svninfo.NewRevision << "\n");
// svninfo.Root = ""; // uncomment to test GuessBase
this->Log << "Repository '" << svninfo.LocalPath
@@ -170,23 +146,21 @@ void cmCTestSVN::NoteNewRevision()
// Compute the base path the working tree has checked out under
// the repository root.
- if(!svninfo.Root.empty()
- && cmCTestSVNPathStarts(svninfo.URL, svninfo.Root))
- {
- svninfo.Base = cmCTest::DecodeURL(
- svninfo.URL.substr(svninfo.Root.size()));
+ if (!svninfo.Root.empty() &&
+ cmCTestSVNPathStarts(svninfo.URL, svninfo.Root)) {
+ svninfo.Base =
+ cmCTest::DecodeURL(svninfo.URL.substr(svninfo.Root.size()));
svninfo.Base += "/";
- }
+ }
this->Log << "Repository '" << svninfo.LocalPath
<< "' Base = " << svninfo.Base << "\n";
-
}
// Set the global new revision to the one of the root
this->NewRevision = this->RootInfo->NewRevision;
+ return true;
}
-//----------------------------------------------------------------------------
void cmCTestSVN::GuessBase(SVNInfo& svninfo,
std::vector<Change> const& changes)
{
@@ -195,21 +169,18 @@ void cmCTestSVN::GuessBase(SVNInfo& svninfo,
// changes under it.
// Consider each possible URL suffix from longest to shortest.
- for(std::string::size_type slash = svninfo.URL.find('/');
- svninfo.Base.empty() && slash != std::string::npos;
- slash = svninfo.URL.find('/', slash+1))
- {
+ for (std::string::size_type slash = svninfo.URL.find('/');
+ svninfo.Base.empty() && slash != std::string::npos;
+ slash = svninfo.URL.find('/', slash + 1)) {
// If the URL suffix is a prefix of at least one path then it is the base.
std::string base = cmCTest::DecodeURL(svninfo.URL.substr(slash));
- for(std::vector<Change>::const_iterator ci = changes.begin();
- svninfo.Base.empty() && ci != changes.end(); ++ci)
- {
- if(cmCTestSVNPathStarts(ci->Path, base))
- {
+ for (std::vector<Change>::const_iterator ci = changes.begin();
+ svninfo.Base.empty() && ci != changes.end(); ++ci) {
+ if (cmCTestSVNPathStarts(ci->Path, base)) {
svninfo.Base = base;
- }
}
}
+ }
// We always append a slash so that we know paths beginning in the
// base lie under its path. If no base was found then the working
@@ -220,89 +191,88 @@ void cmCTestSVN::GuessBase(SVNInfo& svninfo,
this->Log << "Guessed Base = " << svninfo.Base << "\n";
}
-//----------------------------------------------------------------------------
-class cmCTestSVN::UpdateParser: public cmCTestVC::LineParser
+class cmCTestSVN::UpdateParser : public cmCTestVC::LineParser
{
public:
- UpdateParser(cmCTestSVN* svn, const char* prefix): SVN(svn)
- {
+ UpdateParser(cmCTestSVN* svn, const char* prefix)
+ : SVN(svn)
+ {
this->SetLog(&svn->Log, prefix);
this->RegexUpdate.compile("^([ADUCGE ])([ADUCGE ])[B ] +(.+)$");
- }
+ }
+
private:
cmCTestSVN* SVN;
cmsys::RegularExpression RegexUpdate;
- bool ProcessLine()
- {
- if(this->RegexUpdate.find(this->Line))
- {
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexUpdate.find(this->Line)) {
this->DoPath(this->RegexUpdate.match(1)[0],
- this->RegexUpdate.match(2)[0],
- this->RegexUpdate.match(3));
- }
- return true;
+ this->RegexUpdate.match(2)[0], this->RegexUpdate.match(3));
}
+ return true;
+ }
void DoPath(char path_status, char prop_status, std::string const& path)
- {
- char status = (path_status != ' ')? path_status : prop_status;
+ {
+ char status = (path_status != ' ') ? path_status : prop_status;
std::string dir = cmSystemTools::GetFilenamePath(path);
std::string name = cmSystemTools::GetFilenameName(path);
// See "svn help update".
- switch(status)
- {
+ switch (status) {
case 'G':
this->SVN->Dirs[dir][name].Status = PathModified;
break;
case 'C':
this->SVN->Dirs[dir][name].Status = PathConflicting;
break;
- case 'A': case 'D': case 'U':
+ case 'A':
+ case 'D':
+ case 'U':
this->SVN->Dirs[dir][name].Status = PathUpdated;
break;
case 'E': // TODO?
- case '?': case ' ': default:
+ case '?':
+ case ' ':
+ default:
break;
- }
}
+ }
};
-//----------------------------------------------------------------------------
bool cmCTestSVN::UpdateImpl()
{
// Get user-specified update options.
std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions");
- if(opts.empty())
- {
+ if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("SVNUpdateOptions");
- }
- std::vector<cmStdString> args = cmSystemTools::ParseArguments(opts.c_str());
+ }
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
// Specify the start time for nightly testing.
- if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
- {
+ if (this->CTest->GetTestModel() == cmCTest::NIGHTLY) {
args.push_back("-r{" + this->GetNightlyTime() + " +0000}");
- }
+ }
std::vector<char const*> svn_update;
svn_update.push_back("update");
- for(std::vector<cmStdString>::const_iterator ai = args.begin();
- ai != args.end(); ++ai)
- {
+ for (std::vector<std::string>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai) {
svn_update.push_back(ai->c_str());
- }
+ }
UpdateParser out(this, "up-out> ");
OutputLogger err(this->Log, "up-err> ");
return this->RunSVNCommand(svn_update, &out, &err);
}
-//----------------------------------------------------------------------------
bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters,
- OutputParser* out, OutputParser* err)
+ OutputParser* out, OutputParser* err)
{
- if(parameters.empty()) return false;
+ if (parameters.empty()) {
+ return false;
+ }
std::vector<char const*> args;
args.push_back(this->CommandLineTool.c_str());
@@ -311,38 +281,35 @@ bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters,
args.push_back("--non-interactive");
- std::string userOptions =
- this->CTest->GetCTestConfiguration("SVNOptions");
+ std::string userOptions = this->CTest->GetCTestConfiguration("SVNOptions");
- std::vector<cmStdString> parsedUserOptions =
+ std::vector<std::string> parsedUserOptions =
cmSystemTools::ParseArguments(userOptions.c_str());
- for(std::vector<cmStdString>::iterator i = parsedUserOptions.begin();
- i != parsedUserOptions.end(); ++i)
- {
+ for (std::vector<std::string>::iterator i = parsedUserOptions.begin();
+ i != parsedUserOptions.end(); ++i) {
args.push_back(i->c_str());
- }
+ }
- args.push_back(0);
+ args.push_back(CM_NULLPTR);
- if(strcmp(parameters[0], "update") == 0)
- {
+ if (strcmp(parameters[0], "update") == 0) {
return RunUpdateCommand(&args[0], out, err);
- }
- else
- {
- return RunChild(&args[0], out, err);
- }
+ }
+ return RunChild(&args[0], out, err);
}
-//----------------------------------------------------------------------------
-class cmCTestSVN::LogParser: public cmCTestVC::OutputLogger,
- private cmXMLParser
+class cmCTestSVN::LogParser : public cmCTestVC::OutputLogger,
+ private cmXMLParser
{
public:
- LogParser(cmCTestSVN* svn, const char* prefix, SVNInfo& svninfo):
- OutputLogger(svn->Log, prefix), SVN(svn), SVNRepo(svninfo)
- { this->InitializeParser(); }
- ~LogParser() { this->CleanupParser(); }
+ LogParser(cmCTestSVN* svn, const char* prefix, SVNInfo& svninfo)
+ : OutputLogger(svn->Log, prefix)
+ , SVN(svn)
+ , SVNRepo(svninfo)
+ {
+ this->InitializeParser();
+ }
+ ~LogParser() CM_OVERRIDE { this->CleanupParser(); }
private:
cmCTestSVN* SVN;
cmCTestSVN::SVNInfo& SVNRepo;
@@ -354,101 +321,83 @@ private:
Change CurChange;
std::vector<char> CData;
- virtual bool ProcessChunk(const char* data, int length)
- {
+ bool ProcessChunk(const char* data, int length) CM_OVERRIDE
+ {
this->OutputLogger::ProcessChunk(data, length);
this->ParseChunk(data, length);
return true;
- }
+ }
- virtual void StartElement(const char* name, const char** atts)
- {
+ void StartElement(const std::string& name, const char** atts) CM_OVERRIDE
+ {
this->CData.clear();
- if(strcmp(name, "logentry") == 0)
- {
+ if (name == "logentry") {
this->Rev = Revision();
this->Rev.SVNInfo = &SVNRepo;
- if(const char* rev = this->FindAttribute(atts, "revision"))
- {
+ if (const char* rev = this->FindAttribute(atts, "revision")) {
this->Rev.Rev = rev;
- }
- this->Changes.clear();
}
- else if(strcmp(name, "path") == 0)
- {
+ this->Changes.clear();
+ } else if (name == "path") {
this->CurChange = Change();
- if(const char* action = this->FindAttribute(atts, "action"))
- {
+ if (const char* action = this->FindAttribute(atts, "action")) {
this->CurChange.Action = action[0];
- }
}
}
+ }
- virtual void CharacterDataHandler(const char* data, int length)
- {
- this->CData.insert(this->CData.end(), data, data+length);
- }
+ void CharacterDataHandler(const char* data, int length) CM_OVERRIDE
+ {
+ this->CData.insert(this->CData.end(), data, data + length);
+ }
- virtual void EndElement(const char* name)
- {
- if(strcmp(name, "logentry") == 0)
- {
+ void EndElement(const std::string& name) CM_OVERRIDE
+ {
+ if (name == "logentry") {
this->SVN->DoRevisionSVN(this->Rev, this->Changes);
- }
- else if(strcmp(name, "path") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "path") {
std::string orig_path(&this->CData[0], this->CData.size());
- std::string new_path = SVNRepo.BuildLocalPath( orig_path );
+ std::string new_path = SVNRepo.BuildLocalPath(orig_path);
this->CurChange.Path.assign(new_path);
this->Changes.push_back(this->CurChange);
- }
- else if(strcmp(name, "author") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "author") {
this->Rev.Author.assign(&this->CData[0], this->CData.size());
- }
- else if(strcmp(name, "date") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "date") {
this->Rev.Date.assign(&this->CData[0], this->CData.size());
- }
- else if(strcmp(name, "msg") == 0 && !this->CData.empty())
- {
+ } else if (!this->CData.empty() && name == "msg") {
this->Rev.Log.assign(&this->CData[0], this->CData.size());
- }
- this->CData.clear();
}
+ this->CData.clear();
+ }
- virtual void ReportError(int, int, const char* msg)
- {
+ void ReportError(int /*line*/, int /*column*/, const char* msg) CM_OVERRIDE
+ {
this->SVN->Log << "Error parsing svn log xml: " << msg << "\n";
- }
+ }
};
-//----------------------------------------------------------------------------
-void cmCTestSVN::LoadRevisions()
+bool cmCTestSVN::LoadRevisions()
{
+ bool result = true;
// Get revisions for all the external repositories
- std::list<SVNInfo>::iterator itbeg = this->Repositories.begin();
- std::list<SVNInfo>::iterator itend = this->Repositories.end();
- for( ; itbeg != itend ; itbeg++)
- {
+ std::vector<SVNInfo>::iterator itbeg = this->Repositories.begin();
+ std::vector<SVNInfo>::iterator itend = this->Repositories.end();
+ for (; itbeg != itend; itbeg++) {
SVNInfo& svninfo = *itbeg;
- LoadRevisions(svninfo);
- }
+ result = this->LoadRevisions(svninfo) && result;
+ }
+ return result;
}
-//----------------------------------------------------------------------------
-void cmCTestSVN::LoadRevisions(SVNInfo &svninfo)
+bool cmCTestSVN::LoadRevisions(SVNInfo& svninfo)
{
// We are interested in every revision included in the update.
std::string revs;
- if(atoi(svninfo.OldRevision.c_str()) < atoi(svninfo.NewRevision.c_str()))
- {
+ if (atoi(svninfo.OldRevision.c_str()) < atoi(svninfo.NewRevision.c_str())) {
revs = "-r" + svninfo.OldRevision + ":" + svninfo.NewRevision;
- }
- else
- {
+ } else {
revs = "-r" + svninfo.NewRevision;
- }
+ }
// Run "svn log" to get all global revisions of interest.
std::vector<const char*> svn_log;
@@ -459,72 +408,75 @@ void cmCTestSVN::LoadRevisions(SVNInfo &svninfo)
svn_log.push_back(svninfo.LocalPath.c_str());
LogParser out(this, "log-out> ", svninfo);
OutputLogger err(this->Log, "log-err> ");
- this->RunSVNCommand(svn_log, &out, &err);
+ return this->RunSVNCommand(svn_log, &out, &err);
}
-//----------------------------------------------------------------------------
void cmCTestSVN::DoRevisionSVN(Revision const& revision,
std::vector<Change> const& changes)
{
// Guess the base checkout path from the changes if necessary.
- if(this->RootInfo->Base.empty() && !changes.empty())
- {
+ if (this->RootInfo->Base.empty() && !changes.empty()) {
this->GuessBase(*this->RootInfo, changes);
- }
+ }
// Ignore changes in the old revision for external repositories
- if(revision.Rev == revision.SVNInfo->OldRevision
- && revision.SVNInfo->LocalPath != "")
- {
+ if (revision.Rev == revision.SVNInfo->OldRevision &&
+ revision.SVNInfo->LocalPath != "") {
return;
- }
+ }
this->cmCTestGlobalVC::DoRevision(revision, changes);
}
-//----------------------------------------------------------------------------
-class cmCTestSVN::StatusParser: public cmCTestVC::LineParser
+class cmCTestSVN::StatusParser : public cmCTestVC::LineParser
{
public:
- StatusParser(cmCTestSVN* svn, const char* prefix): SVN(svn)
- {
+ StatusParser(cmCTestSVN* svn, const char* prefix)
+ : SVN(svn)
+ {
this->SetLog(&svn->Log, prefix);
this->RegexStatus.compile("^([ACDIMRX?!~ ])([CM ])[ L]... +(.+)$");
- }
+ }
+
private:
cmCTestSVN* SVN;
cmsys::RegularExpression RegexStatus;
- bool ProcessLine()
- {
- if(this->RegexStatus.find(this->Line))
- {
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexStatus.find(this->Line)) {
this->DoPath(this->RegexStatus.match(1)[0],
- this->RegexStatus.match(2)[0],
- this->RegexStatus.match(3));
- }
- return true;
+ this->RegexStatus.match(2)[0], this->RegexStatus.match(3));
}
+ return true;
+ }
void DoPath(char path_status, char prop_status, std::string const& path)
- {
- char status = (path_status != ' ')? path_status : prop_status;
+ {
+ char status = (path_status != ' ') ? path_status : prop_status;
// See "svn help status".
- switch(status)
- {
- case 'M': case '!': case 'A': case 'D': case 'R':
+ switch (status) {
+ case 'M':
+ case '!':
+ case 'A':
+ case 'D':
+ case 'R':
this->SVN->DoModification(PathModified, path);
break;
- case 'C': case '~':
+ case 'C':
+ case '~':
this->SVN->DoModification(PathConflicting, path);
break;
- case 'X': case 'I': case '?': case ' ': default:
+ case 'X':
+ case 'I':
+ case '?':
+ case ' ':
+ default:
break;
- }
}
+ }
};
-//----------------------------------------------------------------------------
-void cmCTestSVN::LoadModifications()
+bool cmCTestSVN::LoadModifications()
{
// Run "svn status" which reports local modifications.
std::vector<const char*> svn_status;
@@ -532,86 +484,85 @@ void cmCTestSVN::LoadModifications()
StatusParser out(this, "status-out> ");
OutputLogger err(this->Log, "status-err> ");
this->RunSVNCommand(svn_status, &out, &err);
+ return true;
}
-//----------------------------------------------------------------------------
-void cmCTestSVN::WriteXMLGlobal(std::ostream& xml)
+void cmCTestSVN::WriteXMLGlobal(cmXMLWriter& xml)
{
this->cmCTestGlobalVC::WriteXMLGlobal(xml);
- xml << "\t<SVNPath>" << this->RootInfo->Base << "</SVNPath>\n";
+ xml.Element("SVNPath", this->RootInfo->Base);
}
-//----------------------------------------------------------------------------
-class cmCTestSVN::ExternalParser: public cmCTestVC::LineParser
+class cmCTestSVN::ExternalParser : public cmCTestVC::LineParser
{
public:
- ExternalParser(cmCTestSVN* svn, const char* prefix): SVN(svn)
- {
+ ExternalParser(cmCTestSVN* svn, const char* prefix)
+ : SVN(svn)
+ {
this->SetLog(&svn->Log, prefix);
this->RegexExternal.compile("^X..... +(.+)$");
- }
+ }
+
private:
cmCTestSVN* SVN;
cmsys::RegularExpression RegexExternal;
- bool ProcessLine()
- {
- if(this->RegexExternal.find(this->Line))
- {
+ bool ProcessLine() CM_OVERRIDE
+ {
+ if (this->RegexExternal.find(this->Line)) {
this->DoPath(this->RegexExternal.match(1));
- }
- return true;
}
+ return true;
+ }
void DoPath(std::string const& path)
- {
+ {
// Get local path relative to the source directory
std::string local_path;
- if(path.size() > this->SVN->SourceDirectory.size() &&
- strncmp(path.c_str(), this->SVN->SourceDirectory.c_str(),
- this->SVN->SourceDirectory.size()) == 0)
- {
+ if (path.size() > this->SVN->SourceDirectory.size() &&
+ strncmp(path.c_str(), this->SVN->SourceDirectory.c_str(),
+ this->SVN->SourceDirectory.size()) == 0) {
local_path = path.c_str() + this->SVN->SourceDirectory.size() + 1;
- }
- else
- {
+ } else {
local_path = path;
- }
- this->SVN->Repositories.push_back( SVNInfo(local_path.c_str()) );
}
+ this->SVN->Repositories.push_back(SVNInfo(local_path.c_str()));
+ }
};
-//----------------------------------------------------------------------------
-void cmCTestSVN::LoadExternals()
+bool cmCTestSVN::LoadRepositories()
{
+ if (!this->Repositories.empty()) {
+ return true;
+ }
+
+ // Info for root repository
+ this->Repositories.push_back(SVNInfo(""));
+ this->RootInfo = &(this->Repositories.back());
+
// Run "svn status" to get the list of external repositories
std::vector<const char*> svn_status;
svn_status.push_back("status");
ExternalParser out(this, "external-out> ");
OutputLogger err(this->Log, "external-err> ");
- this->RunSVNCommand(svn_status, &out, &err);
+ return this->RunSVNCommand(svn_status, &out, &err);
}
-//----------------------------------------------------------------------------
std::string cmCTestSVN::SVNInfo::BuildLocalPath(std::string const& path) const
{
std::string local_path;
// Add local path prefix if not empty
- if (!this->LocalPath.empty())
- {
+ if (!this->LocalPath.empty()) {
local_path += this->LocalPath;
local_path += "/";
- }
+ }
// Add path with base prefix removed
- if(path.size() > this->Base.size() &&
- strncmp(path.c_str(), this->Base.c_str(), this->Base.size()) == 0)
- {
+ if (path.size() > this->Base.size() &&
+ strncmp(path.c_str(), this->Base.c_str(), this->Base.size()) == 0) {
local_path += (path.c_str() + this->Base.size());
- }
- else
- {
+ } else {
local_path += path;
}
diff --git a/Source/CTest/cmCTestSVN.h b/Source/CTest/cmCTestSVN.h
index c6548e3fb..46b077835 100644
--- a/Source/CTest/cmCTestSVN.h
+++ b/Source/CTest/cmCTestSVN.h
@@ -1,45 +1,49 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestSVN_h
#define cmCTestSVN_h
+#include "cmConfigure.h"
+
#include "cmCTestGlobalVC.h"
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+class cmCTest;
+class cmXMLWriter;
+
/** \class cmCTestSVN
* \brief Interaction with subversion command-line tool
*
*/
-class cmCTestSVN: public cmCTestGlobalVC
+class cmCTestSVN : public cmCTestGlobalVC
{
public:
/** Construct with a CTest instance and update log stream. */
cmCTestSVN(cmCTest* ctest, std::ostream& log);
- virtual ~cmCTestSVN();
+ ~cmCTestSVN() CM_OVERRIDE;
private:
// Implement cmCTestVC internal API.
- virtual void CleanupImpl();
- virtual void NoteOldRevision();
- virtual void NoteNewRevision();
- virtual bool UpdateImpl();
+ void CleanupImpl() CM_OVERRIDE;
+ bool NoteOldRevision() CM_OVERRIDE;
+ bool NoteNewRevision() CM_OVERRIDE;
+ bool UpdateImpl() CM_OVERRIDE;
bool RunSVNCommand(std::vector<char const*> const& parameters,
- OutputParser* out, OutputParser* err);
+ OutputParser* out, OutputParser* err);
// Information about an SVN repository (root repository or external)
- struct SVNInfo {
+ struct SVNInfo
+ {
- SVNInfo(const char* path) : LocalPath(path) {}
+ SVNInfo(const char* path)
+ : LocalPath(path)
+ {
+ }
// Remove base from the filename
std::string BuildLocalPath(std::string const& path) const;
@@ -58,38 +62,39 @@ private:
// Old and new repository revisions.
std::string OldRevision;
std::string NewRevision;
-
};
// Extended revision structure to include info about external it refers to.
struct Revision;
+
friend struct Revision;
// Info of all the repositories (root, externals and nested ones).
- std::list<SVNInfo> Repositories;
+ std::vector<SVNInfo> Repositories;
// Pointer to the infos of the root repository.
SVNInfo* RootInfo;
std::string LoadInfo(SVNInfo& svninfo);
- void LoadExternals();
- void LoadModifications();
- void LoadRevisions();
- void LoadRevisions(SVNInfo& svninfo);
+ bool LoadRepositories();
+ bool LoadModifications() CM_OVERRIDE;
+ bool LoadRevisions() CM_OVERRIDE;
+ bool LoadRevisions(SVNInfo& svninfo);
- void GuessBase(SVNInfo &svninfo, std::vector<Change> const& changes);
+ void GuessBase(SVNInfo& svninfo, std::vector<Change> const& changes);
void DoRevisionSVN(Revision const& revision,
std::vector<Change> const& changes);
- void WriteXMLGlobal(std::ostream& xml);
+ void WriteXMLGlobal(cmXMLWriter& xml) CM_OVERRIDE;
+ class ExternalParser;
// Parsing helper classes.
class InfoParser;
class LogParser;
class StatusParser;
class UpdateParser;
- class ExternalParser;
+
friend class InfoParser;
friend class LogParser;
friend class StatusParser;
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 8643cb3f7..1d29dfac2 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -1,44 +1,19 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestScriptHandler.h"
-#include "cmCTest.h"
-#include "cmake.h"
-#include "cmFunctionBlocker.h"
-#include "cmMakefile.h"
-#include "cmLocalGenerator.h"
-#include "cmGlobalGenerator.h"
-#include "cmGeneratedFileStream.h"
-
-//#include <cmsys/RegularExpression.hxx>
-#include <cmsys/Process.h>
-
-// used for sleep
-#ifdef _WIN32
-#include "windows.h"
-#endif
-
+#include "cmsys/Directory.hxx"
+#include "cmsys/Process.h"
+#include <map>
+#include <sstream>
+#include <stdio.h>
#include <stdlib.h>
-#include <time.h>
-#include <math.h>
-#include <float.h>
-
-// needed for sleep
-#if !defined(_WIN32)
-# include <unistd.h>
-#endif
+#include <string.h>
+#include <utility>
+#include "cmCTest.h"
#include "cmCTestBuildCommand.h"
+#include "cmCTestCommand.h"
#include "cmCTestConfigureCommand.h"
#include "cmCTestCoverageCommand.h"
#include "cmCTestEmptyBinaryDirectoryCommand.h"
@@ -51,6 +26,24 @@
#include "cmCTestTestCommand.h"
#include "cmCTestUpdateCommand.h"
#include "cmCTestUploadCommand.h"
+#include "cmFunctionBlocker.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+class cmExecutionStatus;
+struct cmListFileFunction;
#define CTEST_INITIAL_CMAKE_OUTPUT_FILE_NAME "CTestInitialCMakeOutput.log"
@@ -59,44 +52,40 @@ class cmCTestScriptFunctionBlocker : public cmFunctionBlocker
{
public:
cmCTestScriptFunctionBlocker() {}
- virtual ~cmCTestScriptFunctionBlocker() {}
- virtual bool IsFunctionBlocked(const cmListFileFunction& lff,
- cmMakefile &mf,
- cmExecutionStatus &);
- //virtual bool ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf);
- //virtual void ScopeEnded(cmMakefile &mf);
+ ~cmCTestScriptFunctionBlocker() CM_OVERRIDE {}
+ bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf,
+ cmExecutionStatus& /*status*/) CM_OVERRIDE;
+ // virtual bool ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf);
+ // virtual void ScopeEnded(cmMakefile &mf);
cmCTestScriptHandler* CTestScriptHandler;
};
// simply update the time and don't block anything
-bool cmCTestScriptFunctionBlocker::
-IsFunctionBlocked(const cmListFileFunction& , cmMakefile &,
- cmExecutionStatus &)
+bool cmCTestScriptFunctionBlocker::IsFunctionBlocked(
+ const cmListFileFunction& /*lff*/, cmMakefile& /*mf*/,
+ cmExecutionStatus& /*status*/)
{
this->CTestScriptHandler->UpdateElapsedTime();
return false;
}
-//----------------------------------------------------------------------
cmCTestScriptHandler::cmCTestScriptHandler()
{
this->Backup = false;
this->EmptyBinDir = false;
this->EmptyBinDirOnce = false;
- this->Makefile = 0;
- this->LocalGenerator = 0;
- this->CMake = 0;
- this->GlobalGenerator = 0;
+ this->Makefile = CM_NULLPTR;
+ this->CMake = CM_NULLPTR;
+ this->GlobalGenerator = CM_NULLPTR;
this->ScriptStartTime = 0;
// the *60 is becuase the settings are in minutes but GetTime is seconds
- this->MinimumInterval = 30*60;
+ this->MinimumInterval = 30 * 60;
this->ContinuousDuration = -1;
}
-//----------------------------------------------------------------------
void cmCTestScriptHandler::Initialize()
{
this->Superclass::Initialize();
@@ -118,102 +107,71 @@ void cmCTestScriptHandler::Initialize()
this->CMOutFile = "";
this->ExtraUpdates.clear();
- this->MinimumInterval = 20*60;
+ this->MinimumInterval = 20 * 60;
this->ContinuousDuration = -1;
// what time in seconds did this script start running
this->ScriptStartTime = 0;
- this->Makefile = 0;
- if (this->LocalGenerator)
- {
- delete this->LocalGenerator;
- }
- this->LocalGenerator = 0;
- if (this->GlobalGenerator)
- {
- delete this->GlobalGenerator;
- }
- this->GlobalGenerator = 0;
- if (this->CMake)
- {
- delete this->CMake;
- }
+ delete this->Makefile;
+ this->Makefile = CM_NULLPTR;
+
+ delete this->GlobalGenerator;
+ this->GlobalGenerator = CM_NULLPTR;
+
+ delete this->CMake;
}
-//----------------------------------------------------------------------
cmCTestScriptHandler::~cmCTestScriptHandler()
{
- // local generator owns the makefile
- this->Makefile = 0;
- if (this->LocalGenerator)
- {
- delete this->LocalGenerator;
- }
- this->LocalGenerator = 0;
- if (this->GlobalGenerator)
- {
- delete this->GlobalGenerator;
- }
- this->GlobalGenerator = 0;
- if (this->CMake)
- {
- delete this->CMake;
- }
+ delete this->Makefile;
+ delete this->GlobalGenerator;
+ delete this->CMake;
}
-
-//----------------------------------------------------------------------
// just adds an argument to the vector
-void cmCTestScriptHandler::AddConfigurationScript(const char *script,
+void cmCTestScriptHandler::AddConfigurationScript(const char* script,
bool pscope)
{
this->ConfigurationScripts.push_back(script);
this->ScriptProcessScope.push_back(pscope);
}
-
-//----------------------------------------------------------------------
// the generic entry point for handling scripts, this routine will run all
// the scripts provides a -S arguments
int cmCTestScriptHandler::ProcessHandler()
{
int res = 0;
- for (size_t i=0; i < this->ConfigurationScripts.size(); ++i)
- {
+ for (size_t i = 0; i < this->ConfigurationScripts.size(); ++i) {
// for each script run it
- res += this->RunConfigurationScript
- (cmSystemTools::CollapseFullPath(this->ConfigurationScripts[i].c_str()),
- this->ScriptProcessScope[i]);
- }
- if ( res )
- {
+ res |= this->RunConfigurationScript(
+ cmSystemTools::CollapseFullPath(this->ConfigurationScripts[i]),
+ this->ScriptProcessScope[i]);
+ }
+ if (res) {
return -1;
- }
+ }
return 0;
}
void cmCTestScriptHandler::UpdateElapsedTime()
{
- if (this->LocalGenerator)
- {
+ if (this->Makefile) {
// set the current elapsed time
char timeString[20];
- int itime = static_cast<unsigned int>(cmSystemTools::GetTime()
- - this->ScriptStartTime);
- sprintf(timeString,"%i",itime);
- this->LocalGenerator->GetMakefile()->AddDefinition("CTEST_ELAPSED_TIME",
- timeString);
- }
+ int itime = static_cast<unsigned int>(cmSystemTools::GetTime() -
+ this->ScriptStartTime);
+ sprintf(timeString, "%i", itime);
+ this->Makefile->AddDefinition("CTEST_ELAPSED_TIME", timeString);
+ }
}
-//----------------------------------------------------------------------
-void cmCTestScriptHandler::AddCTestCommand(cmCTestCommand* command)
+void cmCTestScriptHandler::AddCTestCommand(std::string const& name,
+ cmCTestCommand* command)
{
- cmCTestCommand* newCom = command;
- newCom->CTest = this->CTest;
- newCom->CTestScriptHandler = this;
- this->CMake->AddCommand(newCom);
+ command->CTest = this->CTest;
+ command->CTestScriptHandler = this;
+ this->CMake->GetState()->AddBuiltinCommand(name, command);
}
int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
@@ -221,153 +179,134 @@ 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");
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Executable for CTest is: "
+ << cmSystemTools::GetCTestCommand() << "\n");
// now pass through all the other arguments
- std::vector<cmStdString> &initArgs =
+ std::vector<std::string>& initArgs =
this->CTest->GetInitialCommandLineArguments();
//*** need to make sure this does not have the current script ***
- for(size_t i=1; i < initArgs.size(); ++i)
- {
+ for (size_t i = 1; i < initArgs.size(); ++i) {
argv.push_back(initArgs[i].c_str());
- }
- argv.push_back(0);
+ }
+ argv.push_back(CM_NULLPTR);
// Now create process object
cmsysProcess* cp = cmsysProcess_New();
cmsysProcess_SetCommand(cp, &*argv.begin());
- //cmsysProcess_SetWorkingDirectory(cp, dir);
+ // cmsysProcess_SetWorkingDirectory(cp, dir);
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
- //cmsysProcess_SetTimeout(cp, timeout);
+ // cmsysProcess_SetTimeout(cp, timeout);
cmsysProcess_Execute(cp);
std::vector<char> out;
std::vector<char> err;
std::string line;
int pipe = cmSystemTools::WaitForLine(cp, line, 100.0, out, err);
- while(pipe != cmsysProcess_Pipe_None)
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Output: "
- << line << "\n");
- if(pipe == cmsysProcess_Pipe_STDERR)
- {
+ while (pipe != cmsysProcess_Pipe_None) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Output: " << line
+ << "\n");
+ if (pipe == cmsysProcess_Pipe_STDERR) {
cmCTestLog(this->CTest, ERROR_MESSAGE, line << "\n");
- }
- else if(pipe == cmsysProcess_Pipe_STDOUT)
- {
+ } else if (pipe == cmsysProcess_Pipe_STDOUT) {
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n");
- }
- pipe = cmSystemTools::WaitForLine(cp, line, 100, out, err);
}
+ pipe = cmSystemTools::WaitForLine(cp, line, 100, out, err);
+ }
// Properly handle output of the build command
- cmsysProcess_WaitForExit(cp, 0);
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
int result = cmsysProcess_GetState(cp);
int retVal = 0;
bool failed = false;
- if(result == cmsysProcess_State_Exited)
- {
+ if (result == cmsysProcess_State_Exited) {
retVal = cmsysProcess_GetExitValue(cp);
- }
- else if(result == cmsysProcess_State_Exception)
- {
+ } else if (result == cmsysProcess_State_Exception) {
retVal = cmsysProcess_GetExitException(cp);
cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was an exception: "
- << cmsysProcess_GetExceptionString(cp) << " " <<
- retVal << std::endl);
+ << cmsysProcess_GetExceptionString(cp) << " " << retVal
+ << std::endl);
failed = true;
- }
- else if(result == cmsysProcess_State_Expired)
- {
+ } else if (result == cmsysProcess_State_Expired) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was a timeout"
- << std::endl);
+ << std::endl);
failed = true;
- }
- else if(result == cmsysProcess_State_Error)
- {
+ } else if (result == cmsysProcess_State_Error) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "\tError executing ctest: "
- << cmsysProcess_GetErrorString(cp) << std::endl);
+ << cmsysProcess_GetErrorString(cp) << std::endl);
failed = true;
- }
+ }
cmsysProcess_Delete(cp);
- if(failed)
- {
- cmOStringStream message;
+ if (failed) {
+ std::ostringstream message;
message << "Error running command: [";
message << result << "] ";
- for(std::vector<const char*>::iterator i = argv.begin();
- i != argv.end(); ++i)
- {
- if(*i)
- {
- message << *i << " ";
- }
+ for (std::vector<const char*>::iterator i = argv.begin(); i != argv.end();
+ ++i) {
+ if (*i) {
+ message << *i << " ";
}
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- message.str() << argv[0] << std::endl);
- return -1;
}
+ cmCTestLog(this->CTest, ERROR_MESSAGE, message.str() << argv[0]
+ << std::endl);
+ return -1;
+ }
return retVal;
}
+static void ctestScriptProgressCallback(const char* m, float /*unused*/,
+ void* cd)
+{
+ cmCTest* ctest = static_cast<cmCTest*>(cd);
+ if (m && *m) {
+ cmCTestLog(ctest, HANDLER_OUTPUT, "-- " << m << std::endl);
+ }
+}
+
void cmCTestScriptHandler::CreateCMake()
{
// create a cmake instance to read the configuration script
- if (this->CMake)
- {
+ if (this->CMake) {
delete this->CMake;
delete this->GlobalGenerator;
- delete this->LocalGenerator;
- }
- this->CMake = new cmake;
+ delete this->Makefile;
+ }
+ this->CMake = new cmake(cmake::RoleScript);
+ this->CMake->SetHomeDirectory("");
+ this->CMake->SetHomeOutputDirectory("");
+ this->CMake->GetCurrentSnapshot().SetDefaultDefinitions();
this->CMake->AddCMakePaths();
- this->GlobalGenerator = new cmGlobalGenerator;
- this->GlobalGenerator->SetCMakeInstance(this->CMake);
-
- this->LocalGenerator = this->GlobalGenerator->CreateLocalGenerator();
- this->Makefile = this->LocalGenerator->GetMakefile();
+ this->GlobalGenerator = new cmGlobalGenerator(this->CMake);
- // Set CMAKE_CURRENT_SOURCE_DIR and CMAKE_CURRENT_BINARY_DIR.
- // Also, some commands need Makefile->GetCurrentDirectory().
+ cmStateSnapshot snapshot = this->CMake->GetCurrentSnapshot();
std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
- this->Makefile->SetStartDirectory(cwd.c_str());
- this->Makefile->SetStartOutputDirectory(cwd.c_str());
-
- // remove all cmake commands which are not scriptable, since they can't be
- // used in ctest scripts
- this->CMake->RemoveUnscriptableCommands();
-
- // add any ctest specific commands, probably should have common superclass
- // for ctest commands to clean this up. If a couple more commands are
- // created with the same format lets do that - ken
- this->AddCTestCommand(new cmCTestBuildCommand);
- this->AddCTestCommand(new cmCTestConfigureCommand);
- this->AddCTestCommand(new cmCTestCoverageCommand);
- this->AddCTestCommand(new cmCTestEmptyBinaryDirectoryCommand);
- this->AddCTestCommand(new cmCTestMemCheckCommand);
- this->AddCTestCommand(new cmCTestReadCustomFilesCommand);
- this->AddCTestCommand(new cmCTestRunScriptCommand);
- this->AddCTestCommand(new cmCTestSleepCommand);
- this->AddCTestCommand(new cmCTestStartCommand);
- this->AddCTestCommand(new cmCTestSubmitCommand);
- this->AddCTestCommand(new cmCTestTestCommand);
- this->AddCTestCommand(new cmCTestUpdateCommand);
- this->AddCTestCommand(new cmCTestUploadCommand);
-}
-
-void cmCTestScriptHandler::GetCommandDocumentation(
- std::vector<cmDocumentationEntry>& v) const
-{
- this->CMake->GetCommandDocumentation(v);
+ snapshot.GetDirectory().SetCurrentSource(cwd);
+ snapshot.GetDirectory().SetCurrentBinary(cwd);
+ this->Makefile = new cmMakefile(this->GlobalGenerator, snapshot);
+
+ this->CMake->SetProgressCallback(ctestScriptProgressCallback, this->CTest);
+
+ this->AddCTestCommand("ctest_build", new cmCTestBuildCommand);
+ this->AddCTestCommand("ctest_configure", new cmCTestConfigureCommand);
+ this->AddCTestCommand("ctest_coverage", new cmCTestCoverageCommand);
+ this->AddCTestCommand("ctest_empty_binary_directory",
+ new cmCTestEmptyBinaryDirectoryCommand);
+ this->AddCTestCommand("ctest_memcheck", new cmCTestMemCheckCommand);
+ this->AddCTestCommand("ctest_read_custom_files",
+ new cmCTestReadCustomFilesCommand);
+ this->AddCTestCommand("ctest_run_script", new cmCTestRunScriptCommand);
+ this->AddCTestCommand("ctest_sleep", new cmCTestSleepCommand);
+ this->AddCTestCommand("ctest_start", new cmCTestStartCommand);
+ this->AddCTestCommand("ctest_submit", new cmCTestSubmitCommand);
+ this->AddCTestCommand("ctest_test", new cmCTestTestCommand);
+ this->AddCTestCommand("ctest_update", new cmCTestUpdateCommand);
+ this->AddCTestCommand("ctest_upload", new cmCTestUploadCommand);
}
-//----------------------------------------------------------------------
// this sets up some variables for the script to use, creates the required
// cmake instance and generators, and then reads in the script
int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
@@ -380,89 +319,81 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
// passed into the scripts as S_ARG
std::string script = total_script_arg;
std::string script_arg;
- if (total_script_arg.find(",") != std::string::npos)
- {
- script = total_script_arg.substr(0,total_script_arg.find(","));
- script_arg = total_script_arg.substr(total_script_arg.find(",")+1);
- }
+ const std::string::size_type comma_pos = total_script_arg.find(',');
+ if (comma_pos != std::string::npos) {
+ script = total_script_arg.substr(0, comma_pos);
+ script_arg = total_script_arg.substr(comma_pos + 1);
+ }
// make sure the file exists
- if (!cmSystemTools::FileExists(script.c_str()))
- {
+ if (!cmSystemTools::FileExists(script.c_str())) {
cmSystemTools::Error("Cannot find file: ", script.c_str());
return 1;
- }
+ }
// read in the list file to fill the cache
// create a cmake instance to read the configuration script
this->CreateCMake();
// set a variable with the path to the current script
- this->Makefile->AddDefinition("CTEST_SCRIPT_DIRECTORY",
- cmSystemTools::GetFilenamePath(script).c_str());
- this->Makefile->AddDefinition("CTEST_SCRIPT_NAME",
- cmSystemTools::GetFilenameName(script).c_str());
+ this->Makefile->AddDefinition(
+ "CTEST_SCRIPT_DIRECTORY", cmSystemTools::GetFilenamePath(script).c_str());
+ 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();
// add the script arg if defined
- if (script_arg.size())
- {
+ if (!script_arg.empty()) {
this->Makefile->AddDefinition("CTEST_SCRIPT_ARG", script_arg.c_str());
- }
+ }
+
+#if defined(__CYGWIN__)
+ this->Makefile->AddDefinition("CMAKE_LEGACY_CYGWIN_WIN32", "0");
+#endif
// always add a function blocker to update the elapsed time
- cmCTestScriptFunctionBlocker *f = new cmCTestScriptFunctionBlocker();
+ cmCTestScriptFunctionBlocker* f = new cmCTestScriptFunctionBlocker();
f->CTestScriptHandler = this;
this->Makefile->AddFunctionBlocker(f);
-
/* Execute CTestScriptMode.cmake, which loads CMakeDetermineSystem and
CMakeSystemSpecificInformation, so
that variables like CMAKE_SYSTEM and also the search paths for libraries,
header and executables are set correctly and can be used. Makes new-style
ctest scripting easier. */
std::string systemFile =
- this->Makefile->GetModulesFile("CTestScriptMode.cmake");
- if (!this->Makefile->ReadListFile(0, systemFile.c_str()) ||
- cmSystemTools::GetErrorOccuredFlag())
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Error in read:"
- << systemFile.c_str() << "\n");
+ this->Makefile->GetModulesFile("CTestScriptMode.cmake");
+ if (!this->Makefile->ReadListFile(systemFile.c_str()) ||
+ cmSystemTools::GetErrorOccuredFlag()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Error in read:" << systemFile
+ << "\n");
return 2;
- }
+ }
// Add definitions of variables passed in on the command line:
- const std::map<std::string, std::string> &defs =
+ const std::map<std::string, std::string>& defs =
this->CTest->GetDefinitions();
for (std::map<std::string, std::string>::const_iterator it = defs.begin();
- it != defs.end(); ++it)
- {
- this->Makefile->AddDefinition(it->first.c_str(), it->second.c_str());
- }
+ it != defs.end(); ++it) {
+ this->Makefile->AddDefinition(it->first, it->second.c_str());
+ }
// finally read in the script
- if (!this->Makefile->ReadListFile(0, script.c_str()) ||
- cmSystemTools::GetErrorOccuredFlag())
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Error in read script: "
- << script.c_str()
- << std::endl);
+ if (!this->Makefile->ReadListFile(script.c_str()) ||
+ cmSystemTools::GetErrorOccuredFlag()) {
// Reset the error flag so that it can run more than
- // one script with an error when you
- // use ctest_run_script
+ // one script with an error when you use ctest_run_script.
cmSystemTools::ResetErrorOccuredFlag();
return 2;
- }
+ }
return 0;
}
-
-//----------------------------------------------------------------------
// extract variabels from the script to set ivars
int cmCTestScriptHandler::ExtractVariables()
{
@@ -470,80 +401,64 @@ int cmCTestScriptHandler::ExtractVariables()
const char* minInterval;
const char* contDuration;
- this->SourceDir
- = this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
- this->BinaryDir
- = this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY");
+ this->SourceDir =
+ this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
+ this->BinaryDir =
+ this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY");
// add in translations for src and bin
- cmSystemTools::AddKeepPath(this->SourceDir.c_str());
- cmSystemTools::AddKeepPath(this->BinaryDir.c_str());
-
- this->CTestCmd
- = this->Makefile->GetSafeDefinition("CTEST_COMMAND");
- this->CVSCheckOut
- = this->Makefile->GetSafeDefinition("CTEST_CVS_CHECKOUT");
- this->CTestRoot
- = this->Makefile->GetSafeDefinition("CTEST_DASHBOARD_ROOT");
- this->UpdateCmd
- = this->Makefile->GetSafeDefinition("CTEST_UPDATE_COMMAND");
- if ( this->UpdateCmd.empty() )
- {
- this->UpdateCmd
- = this->Makefile->GetSafeDefinition("CTEST_CVS_COMMAND");
- }
- this->CTestEnv
- = this->Makefile->GetSafeDefinition("CTEST_ENVIRONMENT");
- this->InitialCache
- = this->Makefile->GetSafeDefinition("CTEST_INITIAL_CACHE");
- this->CMakeCmd
- = this->Makefile->GetSafeDefinition("CTEST_CMAKE_COMMAND");
- this->CMOutFile
- = this->Makefile->GetSafeDefinition("CTEST_CMAKE_OUTPUT_FILE_NAME");
-
- this->Backup
- = this->Makefile->IsOn("CTEST_BACKUP_AND_RESTORE");
- this->EmptyBinDir
- = this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY");
- this->EmptyBinDirOnce
- = this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY_ONCE");
-
- minInterval
- = this->Makefile->GetDefinition("CTEST_CONTINUOUS_MINIMUM_INTERVAL");
- contDuration
- = this->Makefile->GetDefinition("CTEST_CONTINUOUS_DURATION");
+ cmSystemTools::AddKeepPath(this->SourceDir);
+ cmSystemTools::AddKeepPath(this->BinaryDir);
+
+ this->CTestCmd = this->Makefile->GetSafeDefinition("CTEST_COMMAND");
+ this->CVSCheckOut = this->Makefile->GetSafeDefinition("CTEST_CVS_CHECKOUT");
+ this->CTestRoot = this->Makefile->GetSafeDefinition("CTEST_DASHBOARD_ROOT");
+ this->UpdateCmd = this->Makefile->GetSafeDefinition("CTEST_UPDATE_COMMAND");
+ if (this->UpdateCmd.empty()) {
+ this->UpdateCmd = this->Makefile->GetSafeDefinition("CTEST_CVS_COMMAND");
+ }
+ this->CTestEnv = this->Makefile->GetSafeDefinition("CTEST_ENVIRONMENT");
+ this->InitialCache =
+ this->Makefile->GetSafeDefinition("CTEST_INITIAL_CACHE");
+ this->CMakeCmd = this->Makefile->GetSafeDefinition("CTEST_CMAKE_COMMAND");
+ this->CMOutFile =
+ this->Makefile->GetSafeDefinition("CTEST_CMAKE_OUTPUT_FILE_NAME");
+
+ this->Backup = this->Makefile->IsOn("CTEST_BACKUP_AND_RESTORE");
+ this->EmptyBinDir =
+ this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY");
+ this->EmptyBinDirOnce =
+ this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY_ONCE");
+
+ minInterval =
+ this->Makefile->GetDefinition("CTEST_CONTINUOUS_MINIMUM_INTERVAL");
+ contDuration = this->Makefile->GetDefinition("CTEST_CONTINUOUS_DURATION");
char updateVar[40];
int i;
- for (i = 1; i < 10; ++i)
- {
- sprintf(updateVar,"CTEST_EXTRA_UPDATES_%i",i);
- const char *updateVal = this->Makefile->GetDefinition(updateVar);
- if ( updateVal )
- {
- if ( this->UpdateCmd.empty() )
- {
- cmSystemTools::Error(updateVar,
- " specified without specifying CTEST_CVS_COMMAND.");
+ for (i = 1; i < 10; ++i) {
+ sprintf(updateVar, "CTEST_EXTRA_UPDATES_%i", i);
+ const char* updateVal = this->Makefile->GetDefinition(updateVar);
+ if (updateVal) {
+ if (this->UpdateCmd.empty()) {
+ cmSystemTools::Error(
+ updateVar, " specified without specifying CTEST_CVS_COMMAND.");
return 12;
- }
- this->ExtraUpdates.push_back(updateVal);
}
+ this->ExtraUpdates.push_back(updateVal);
}
+ }
// in order to backup and restore we also must have the cvs root
- if (this->Backup && this->CVSCheckOut.empty())
- {
+ if (this->Backup && this->CVSCheckOut.empty()) {
cmSystemTools::Error(
"Backup was requested without specifying CTEST_CVS_CHECKOUT.");
return 3;
- }
+ }
// make sure the required info is here
- if (this->SourceDir.empty() ||
- this->BinaryDir.empty() ||
- this->CTestCmd.empty())
- {
+ if (this->SourceDir.empty() || this->BinaryDir.empty() ||
+ this->CTestCmd.empty()) {
std::string msg = "CTEST_SOURCE_DIRECTORY = ";
msg += (!this->SourceDir.empty()) ? this->SourceDir.c_str() : "(Null)";
msg += "\nCTEST_BINARY_DIRECTORY = ";
@@ -554,45 +469,39 @@ int cmCTestScriptHandler::ExtractVariables()
"Some required settings in the configuration file were missing:\n",
msg.c_str());
return 4;
- }
+ }
// if the dashboard root isn't specified then we can compute it from the
// this->SourceDir
- if (this->CTestRoot.empty() )
- {
- this->CTestRoot = cmSystemTools::GetFilenamePath(this->SourceDir).c_str();
- }
+ if (this->CTestRoot.empty()) {
+ this->CTestRoot = cmSystemTools::GetFilenamePath(this->SourceDir);
+ }
// the script may override the minimum continuous interval
- if (minInterval)
- {
+ if (minInterval) {
this->MinimumInterval = 60 * atof(minInterval);
- }
- if (contDuration)
- {
+ }
+ if (contDuration) {
this->ContinuousDuration = 60.0 * atof(contDuration);
- }
-
+ }
this->UpdateElapsedTime();
return 0;
}
-//----------------------------------------------------------------------
void cmCTestScriptHandler::SleepInSeconds(unsigned int secondsToWait)
{
#if defined(_WIN32)
- Sleep(1000*secondsToWait);
+ Sleep(1000 * secondsToWait);
#else
- sleep(secondsToWait);
+ sleep(secondsToWait);
#endif
}
-//----------------------------------------------------------------------
// run a specific script
-int cmCTestScriptHandler::RunConfigurationScript
-(const std::string& total_script_arg, bool pscope)
+int cmCTestScriptHandler::RunConfigurationScript(
+ const std::string& total_script_arg, bool pscope)
{
#ifdef CMAKE_BUILD_WITH_CMAKE
cmSystemTools::SaveRestoreEnvironment sre;
@@ -600,36 +509,29 @@ int cmCTestScriptHandler::RunConfigurationScript
int result;
- this->ScriptStartTime =
- cmSystemTools::GetTime();
+ this->ScriptStartTime = cmSystemTools::GetTime();
// read in the script
- if (pscope)
- {
+ if (pscope) {
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Reading Script: " << total_script_arg << std::endl);
+ "Reading Script: " << total_script_arg << std::endl);
result = this->ReadInScript(total_script_arg);
- }
- else
- {
+ } else {
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Executing Script: " << total_script_arg << std::endl);
+ "Executing Script: " << total_script_arg << std::endl);
result = this->ExecuteScript(total_script_arg);
- }
- if (result)
- {
+ }
+ if (result) {
return result;
- }
+ }
// only run the curent script if we should
- if (this->Makefile && this->Makefile->IsOn("CTEST_RUN_CURRENT_SCRIPT"))
- {
+ if (this->Makefile && this->Makefile->IsOn("CTEST_RUN_CURRENT_SCRIPT")) {
return this->RunCurrentScript();
- }
+ }
return result;
}
-//----------------------------------------------------------------------
int cmCTestScriptHandler::RunCurrentScript()
{
int result;
@@ -642,57 +544,47 @@ int cmCTestScriptHandler::RunCurrentScript()
// extract the vars from the cache and store in ivars
result = this->ExtractVariables();
- if (result)
- {
+ if (result) {
return result;
- }
+ }
// set any environment variables
- if (!this->CTestEnv.empty())
- {
+ if (!this->CTestEnv.empty()) {
std::vector<std::string> envArgs;
- cmSystemTools::ExpandListArgument(this->CTestEnv.c_str(),envArgs);
+ cmSystemTools::ExpandListArgument(this->CTestEnv, envArgs);
cmSystemTools::AppendEnv(envArgs);
- }
+ }
// now that we have done most of the error checking finally run the
// dashboard, we may be asked to repeatedly run this dashboard, such as
// for a continuous, do we ned to run it more than once?
- if ( this->ContinuousDuration >= 0 )
- {
+ if (this->ContinuousDuration >= 0) {
this->UpdateElapsedTime();
- double ending_time = cmSystemTools::GetTime() + this->ContinuousDuration;
- if (this->EmptyBinDirOnce)
- {
+ double ending_time = cmSystemTools::GetTime() + this->ContinuousDuration;
+ if (this->EmptyBinDirOnce) {
this->EmptyBinDir = true;
- }
- do
- {
+ }
+ do {
double interval = cmSystemTools::GetTime();
result = this->RunConfigurationDashboard();
interval = cmSystemTools::GetTime() - interval;
- if (interval < this->MinimumInterval)
- {
+ if (interval < this->MinimumInterval) {
this->SleepInSeconds(
static_cast<unsigned int>(this->MinimumInterval - interval));
- }
- if (this->EmptyBinDirOnce)
- {
+ }
+ if (this->EmptyBinDirOnce) {
this->EmptyBinDir = false;
- }
}
- while (cmSystemTools::GetTime() < ending_time);
- }
+ } while (cmSystemTools::GetTime() < ending_time);
+ }
// otherwise just run it once
- else
- {
+ else {
result = this->RunConfigurationDashboard();
- }
+ }
return result;
}
-//----------------------------------------------------------------------
int cmCTestScriptHandler::CheckOutSourceDir()
{
std::string command;
@@ -701,26 +593,23 @@ int cmCTestScriptHandler::CheckOutSourceDir()
bool res;
if (!cmSystemTools::FileExists(this->SourceDir.c_str()) &&
- !this->CVSCheckOut.empty())
- {
+ !this->CVSCheckOut.empty()) {
// we must now checkout the src dir
output = "";
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Run cvs: " << this->CVSCheckOut << std::endl);
- res = cmSystemTools::RunSingleCommand(this->CVSCheckOut.c_str(), &output,
- &retVal, this->CTestRoot.c_str(), this->HandlerVerbose,
- 0 /*this->TimeOut*/);
- if (!res || retVal != 0)
- {
+ "Run cvs: " << this->CVSCheckOut << std::endl);
+ res = cmSystemTools::RunSingleCommand(
+ this->CVSCheckOut.c_str(), &output, &output, &retVal,
+ this->CTestRoot.c_str(), this->HandlerVerbose, 0 /*this->TimeOut*/);
+ if (!res || retVal != 0) {
cmSystemTools::Error("Unable to perform cvs checkout:\n",
output.c_str());
return 6;
- }
}
+ }
return 0;
}
-//----------------------------------------------------------------------
int cmCTestScriptHandler::BackupDirectories()
{
int retVal;
@@ -732,17 +621,14 @@ int cmCTestScriptHandler::BackupDirectories()
this->BackupBinaryDir += "_CMakeBackup";
// backup the binary and src directories if requested
- if (this->Backup)
- {
+ if (this->Backup) {
// if for some reason those directories exist then first delete them
- if (cmSystemTools::FileExists(this->BackupSourceDir.c_str()))
- {
- cmSystemTools::RemoveADirectory(this->BackupSourceDir.c_str());
- }
- if (cmSystemTools::FileExists(this->BackupBinaryDir.c_str()))
- {
- cmSystemTools::RemoveADirectory(this->BackupBinaryDir.c_str());
- }
+ if (cmSystemTools::FileExists(this->BackupSourceDir.c_str())) {
+ cmSystemTools::RemoveADirectory(this->BackupSourceDir);
+ }
+ if (cmSystemTools::FileExists(this->BackupBinaryDir.c_str())) {
+ cmSystemTools::RemoveADirectory(this->BackupBinaryDir);
+ }
// first rename the src and binary directories
rename(this->SourceDir.c_str(), this->BackupSourceDir.c_str());
@@ -750,18 +636,15 @@ int cmCTestScriptHandler::BackupDirectories()
// we must now checkout the src dir
retVal = this->CheckOutSourceDir();
- if (retVal)
- {
+ if (retVal) {
this->RestoreBackupDirectories();
return retVal;
- }
}
+ }
return 0;
}
-
-//----------------------------------------------------------------------
int cmCTestScriptHandler::PerformExtraUpdates()
{
std::string command;
@@ -771,39 +654,31 @@ int cmCTestScriptHandler::PerformExtraUpdates()
// do an initial cvs update as required
command = this->UpdateCmd;
- std::vector<cmStdString>::iterator it;
- for (it = this->ExtraUpdates.begin();
- it != this->ExtraUpdates.end();
- ++ it )
- {
+ std::vector<std::string>::iterator it;
+ for (it = this->ExtraUpdates.begin(); it != this->ExtraUpdates.end(); ++it) {
std::vector<std::string> cvsArgs;
- cmSystemTools::ExpandListArgument(it->c_str(),cvsArgs);
- if (cvsArgs.size() == 2)
- {
+ cmSystemTools::ExpandListArgument(*it, cvsArgs);
+ if (cvsArgs.size() == 2) {
std::string fullCommand = command;
fullCommand += " update ";
fullCommand += cvsArgs[1];
output = "";
retVal = 0;
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run Update: "
- << fullCommand.c_str() << std::endl);
- res = cmSystemTools::RunSingleCommand(fullCommand.c_str(), &output,
- &retVal, cvsArgs[0].c_str(),
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run Update: " << fullCommand << std::endl);
+ res = cmSystemTools::RunSingleCommand(
+ fullCommand.c_str(), &output, &output, &retVal, cvsArgs[0].c_str(),
this->HandlerVerbose, 0 /*this->TimeOut*/);
- if (!res || retVal != 0)
- {
- cmSystemTools::Error("Unable to perform extra updates:\n",
- it->c_str(), "\nWith output:\n",
- output.c_str());
+ if (!res || retVal != 0) {
+ cmSystemTools::Error("Unable to perform extra updates:\n", it->c_str(),
+ "\nWith output:\n", output.c_str());
return 0;
- }
}
}
+ }
return 0;
}
-
-//----------------------------------------------------------------------
// run a single dashboard entry
int cmCTestScriptHandler::RunConfigurationDashboard()
{
@@ -816,198 +691,170 @@ int cmCTestScriptHandler::RunConfigurationDashboard()
// make sure the src directory is there, if it isn't then we might be able
// to check it out from cvs
retVal = this->CheckOutSourceDir();
- if (retVal)
- {
+ if (retVal) {
return retVal;
- }
+ }
// backup the dirs if requested
retVal = this->BackupDirectories();
- if (retVal)
- {
+ if (retVal) {
return retVal;
- }
+ }
// clear the binary directory?
- if (this->EmptyBinDir)
- {
- if ( !cmCTestScriptHandler::EmptyBinaryDirectory(
- this->BinaryDir.c_str()) )
- {
+ if (this->EmptyBinDir) {
+ if (!cmCTestScriptHandler::EmptyBinaryDirectory(this->BinaryDir.c_str())) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Problem removing the binary directory" << std::endl);
- }
+ "Problem removing the binary directory" << std::endl);
}
+ }
// make sure the binary directory exists if it isn't the srcdir
if (!cmSystemTools::FileExists(this->BinaryDir.c_str()) &&
- this->SourceDir != this->BinaryDir)
- {
- if (!cmSystemTools::MakeDirectory(this->BinaryDir.c_str()))
- {
+ this->SourceDir != this->BinaryDir) {
+ if (!cmSystemTools::MakeDirectory(this->BinaryDir.c_str())) {
cmSystemTools::Error("Unable to create the binary directory:\n",
this->BinaryDir.c_str());
this->RestoreBackupDirectories();
return 7;
- }
}
+ }
// if the binary directory and the source directory are the same,
// and we are starting with an empty binary directory, then that means
// we must check out the source tree
- if (this->EmptyBinDir && this->SourceDir == this->BinaryDir)
- {
+ if (this->EmptyBinDir && this->SourceDir == this->BinaryDir) {
// make sure we have the required info
- if (this->CVSCheckOut.empty())
- {
- cmSystemTools::Error("You have specified the source and binary "
+ if (this->CVSCheckOut.empty()) {
+ cmSystemTools::Error(
+ "You have specified the source and binary "
"directories to be the same (an in source build). You have also "
"specified that the binary directory is to be erased. This means "
"that the source will have to be checked out from CVS. But you have "
"not specified CTEST_CVS_CHECKOUT");
return 8;
- }
+ }
// we must now checkout the src dir
retVal = this->CheckOutSourceDir();
- if (retVal)
- {
+ if (retVal) {
this->RestoreBackupDirectories();
return retVal;
- }
}
+ }
// backup the dirs if requested
retVal = this->PerformExtraUpdates();
- if (retVal)
- {
+ if (retVal) {
return retVal;
- }
+ }
// put the initial cache into the bin dir
- if (!this->InitialCache.empty())
- {
+ if (!this->InitialCache.empty()) {
if (!this->WriteInitialCache(this->BinaryDir.c_str(),
- this->InitialCache.c_str()))
- {
+ this->InitialCache.c_str())) {
this->RestoreBackupDirectories();
return 9;
- }
}
+ }
// do an initial cmake to setup the DartConfig file
int cmakeFailed = 0;
std::string cmakeFailedOuput;
- if (!this->CMakeCmd.empty())
- {
+ if (!this->CMakeCmd.empty()) {
command = this->CMakeCmd;
command += " \"";
command += this->SourceDir;
output = "";
command += "\"";
retVal = 0;
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run cmake command: "
- << command.c_str() << std::endl);
- res = cmSystemTools::RunSingleCommand(command.c_str(), &output,
- &retVal, this->BinaryDir.c_str(),
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run cmake command: " << command << std::endl);
+ res = cmSystemTools::RunSingleCommand(
+ command.c_str(), &output, &output, &retVal, this->BinaryDir.c_str(),
this->HandlerVerbose, 0 /*this->TimeOut*/);
- if ( !this->CMOutFile.empty() )
- {
+ if (!this->CMOutFile.empty()) {
std::string cmakeOutputFile = this->CMOutFile;
- if ( !cmSystemTools::FileIsFullPath(cmakeOutputFile.c_str()) )
- {
+ if (!cmSystemTools::FileIsFullPath(cmakeOutputFile.c_str())) {
cmakeOutputFile = this->BinaryDir + "/" + cmakeOutputFile;
- }
+ }
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Write CMake output to file: " << cmakeOutputFile.c_str()
- << std::endl);
+ "Write CMake output to file: " << cmakeOutputFile
+ << std::endl);
cmGeneratedFileStream fout(cmakeOutputFile.c_str());
- if ( fout )
- {
+ if (fout) {
fout << output.c_str();
- }
- else
- {
+ } else {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot open CMake output file: "
- << cmakeOutputFile.c_str() << " for writing" << std::endl);
- }
+ "Cannot open CMake output file: "
+ << cmakeOutputFile << " for writing" << std::endl);
}
- if (!res || retVal != 0)
- {
+ }
+ if (!res || retVal != 0) {
// even if this fails continue to the next step
cmakeFailed = 1;
cmakeFailedOuput = output;
- }
}
+ }
// run ctest, it may be more than one command in here
std::vector<std::string> ctestCommands;
- cmSystemTools::ExpandListArgument(this->CTestCmd,ctestCommands);
+ cmSystemTools::ExpandListArgument(this->CTestCmd, ctestCommands);
// for each variable/argument do a putenv
- for (unsigned i = 0; i < ctestCommands.size(); ++i)
- {
+ for (unsigned i = 0; i < ctestCommands.size(); ++i) {
command = ctestCommands[i];
output = "";
retVal = 0;
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run ctest command: "
- << command.c_str() << std::endl);
- res = cmSystemTools::RunSingleCommand(command.c_str(), &output,
- &retVal, this->BinaryDir.c_str(), this->HandlerVerbose,
- 0 /*this->TimeOut*/);
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run ctest command: " << command << std::endl);
+ res = cmSystemTools::RunSingleCommand(
+ command.c_str(), &output, &output, &retVal, this->BinaryDir.c_str(),
+ this->HandlerVerbose, 0 /*this->TimeOut*/);
// did something critical fail in ctest
- if (!res || cmakeFailed ||
- retVal & cmCTest::BUILD_ERRORS)
- {
+ if (!res || cmakeFailed || retVal & cmCTest::BUILD_ERRORS) {
this->RestoreBackupDirectories();
- if (cmakeFailed)
- {
+ if (cmakeFailed) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Unable to run cmake:" << std::endl
- << cmakeFailedOuput.c_str() << std::endl);
+ "Unable to run cmake:" << std::endl
+ << cmakeFailedOuput << std::endl);
return 10;
- }
+ }
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Unable to run ctest:" << std::endl
- << "command: " << command.c_str() << std::endl
- << "output: " << output.c_str() << std::endl);
- if (!res)
- {
+ "Unable to run ctest:" << std::endl
+ << "command: " << command << std::endl
+ << "output: " << output << std::endl);
+ if (!res) {
return 11;
- }
- return retVal * 100;
}
+ return retVal * 100;
}
+ }
// if all was succesful, delete the backup dirs to free up disk space
- if (this->Backup)
- {
- cmSystemTools::RemoveADirectory(this->BackupSourceDir.c_str());
- cmSystemTools::RemoveADirectory(this->BackupBinaryDir.c_str());
- }
+ if (this->Backup) {
+ cmSystemTools::RemoveADirectory(this->BackupSourceDir);
+ cmSystemTools::RemoveADirectory(this->BackupBinaryDir);
+ }
return 0;
}
-//-------------------------------------------------------------------------
bool cmCTestScriptHandler::WriteInitialCache(const char* directory,
const char* text)
{
std::string cacheFile = directory;
cacheFile += "/CMakeCache.txt";
cmGeneratedFileStream fout(cacheFile.c_str());
- if(!fout)
- {
+ if (!fout) {
return false;
- }
+ }
- if (text!=0)
- {
+ if (text != CM_NULLPTR) {
fout.write(text, strlen(text));
- }
+ }
// Make sure the operating system has finished writing the file
// before closing it. This will ensure the file is finished before
@@ -1017,77 +864,111 @@ bool cmCTestScriptHandler::WriteInitialCache(const char* directory,
return true;
}
-//-------------------------------------------------------------------------
void cmCTestScriptHandler::RestoreBackupDirectories()
{
// if we backed up the dirs and the build failed, then restore
// the backed up dirs
- if (this->Backup)
- {
+ if (this->Backup) {
// if for some reason those directories exist then first delete them
- if (cmSystemTools::FileExists(this->SourceDir.c_str()))
- {
- cmSystemTools::RemoveADirectory(this->SourceDir.c_str());
- }
- if (cmSystemTools::FileExists(this->BinaryDir.c_str()))
- {
- cmSystemTools::RemoveADirectory(this->BinaryDir.c_str());
- }
+ if (cmSystemTools::FileExists(this->SourceDir.c_str())) {
+ cmSystemTools::RemoveADirectory(this->SourceDir);
+ }
+ if (cmSystemTools::FileExists(this->BinaryDir.c_str())) {
+ cmSystemTools::RemoveADirectory(this->BinaryDir);
+ }
// rename the src and binary directories
rename(this->BackupSourceDir.c_str(), this->SourceDir.c_str());
rename(this->BackupBinaryDir.c_str(), this->BinaryDir.c_str());
- }
+ }
}
-bool cmCTestScriptHandler::RunScript(cmCTest* ctest, const char *sname,
+bool cmCTestScriptHandler::RunScript(cmCTest* ctest, const char* sname,
bool InProcess, int* returnValue)
{
cmCTestScriptHandler* sh = new cmCTestScriptHandler();
sh->SetCTestInstance(ctest);
- sh->AddConfigurationScript(sname,InProcess);
+ sh->AddConfigurationScript(sname, InProcess);
int res = sh->ProcessHandler();
- if(returnValue)
- {
+ if (returnValue) {
*returnValue = res;
- }
+ }
delete sh;
return true;
}
-bool cmCTestScriptHandler::EmptyBinaryDirectory(const char *sname)
+bool cmCTestScriptHandler::EmptyBinaryDirectory(const char* sname)
{
// try to avoid deleting root
- if (!sname || strlen(sname) < 2)
- {
+ if (!sname || strlen(sname) < 2) {
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;
+ }
+
+ for (int i = 0; i < 5; ++i) {
+ if (TryToRemoveBinaryDirectoryOnce(sname)) {
+ return true;
}
- return true;
+ cmSystemTools::Delay(100);
+ }
+
+ return false;
+}
+
+bool cmCTestScriptHandler::TryToRemoveBinaryDirectoryOnce(
+ const std::string& directoryPath)
+{
+ cmsys::Directory directory;
+ directory.Load(directoryPath);
+
+ 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) &&
+ !cmSystemTools::FileIsSymlink(fullPath);
+
+ if (isDirectory) {
+ if (!cmSystemTools::RemoveADirectory(fullPath)) {
+ return false;
+ }
+ } else {
+ if (!cmSystemTools::RemoveFile(fullPath)) {
+ return false;
+ }
+ }
+ }
+
+ return cmSystemTools::RemoveADirectory(directoryPath);
}
-//-------------------------------------------------------------------------
double cmCTestScriptHandler::GetRemainingTimeAllowed()
{
- if (!this->Makefile)
- {
+ if (!this->Makefile) {
return 1.0e7;
- }
+ }
- const char *timelimitS
- = this->Makefile->GetDefinition("CTEST_TIME_LIMIT");
+ const char* timelimitS = this->Makefile->GetDefinition("CTEST_TIME_LIMIT");
- if (!timelimitS)
- {
+ if (!timelimitS) {
return 1.0e7;
- }
+ }
double timelimit = atof(timelimitS);
diff --git a/Source/CTest/cmCTestScriptHandler.h b/Source/CTest/cmCTestScriptHandler.h
index 9d852cab6..667870260 100644
--- a/Source/CTest/cmCTestScriptHandler.h
+++ b/Source/CTest/cmCTestScriptHandler.h
@@ -1,27 +1,20 @@
-/*============================================================================
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestScriptHandler_h
#define cmCTestScriptHandler_h
+#include "cmConfigure.h"
#include "cmCTestGenericHandler.h"
-#include "cmListFileCache.h"
-class cmMakefile;
-class cmLocalGenerator;
+#include <string>
+#include <vector>
+
+class cmCTest;
+class cmCTestCommand;
class cmGlobalGenerator;
+class cmMakefile;
class cmake;
-class cmCTestCommand;
/** \class cmCTestScriptHandler
* \brief A class that handles ctest -S invocations
@@ -62,29 +55,29 @@ class cmCTestCommand;
class cmCTestScriptHandler : public cmCTestGenericHandler
{
public:
- cmTypeMacro(cmCTestScriptHandler, cmCTestGenericHandler);
+ typedef cmCTestGenericHandler Superclass;
/**
* Add a script to run, and if is should run in the current process
*/
- void AddConfigurationScript(const char *, bool pscope);
+ void AddConfigurationScript(const char*, bool pscope);
/**
* Run a dashboard using a specified confiuration script
*/
- int ProcessHandler();
+ int ProcessHandler() CM_OVERRIDE;
/*
* Run a script
*/
- static bool RunScript(cmCTest* ctest, const char *script, bool InProcess,
- int* returnValue);
+ static bool RunScript(cmCTest* ctest, const char* script, bool InProcess,
+ int* returnValue);
int RunCurrentScript();
/*
* Empty Binary Directory
*/
- static bool EmptyBinaryDirectory(const char *dir);
+ static bool EmptyBinaryDirectory(const char* dir);
/*
* Write an initial CMakeCache.txt from the given contents.
@@ -105,13 +98,12 @@ public:
double GetRemainingTimeAllowed();
cmCTestScriptHandler();
- ~cmCTestScriptHandler();
+ ~cmCTestScriptHandler() CM_OVERRIDE;
- void Initialize();
+ void Initialize() CM_OVERRIDE;
void CreateCMake();
- void GetCommandDocumentation(std::vector<cmDocumentationEntry>& v) const;
- cmake* GetCMake() { return this->CMake;}
+ cmake* GetCMake() { return this->CMake; }
private:
// reads in a script
int ReadInScript(const std::string& total_script_arg);
@@ -134,28 +126,31 @@ private:
int RunConfigurationDashboard();
// Add ctest command
- void AddCTestCommand(cmCTestCommand* command);
+ void AddCTestCommand(std::string const& name, cmCTestCommand* command);
+
+ // Try to remove the binary directory once
+ static bool TryToRemoveBinaryDirectoryOnce(const std::string& directoryPath);
- std::vector<cmStdString> ConfigurationScripts;
+ std::vector<std::string> ConfigurationScripts;
std::vector<bool> ScriptProcessScope;
bool Backup;
bool EmptyBinDir;
bool EmptyBinDirOnce;
- cmStdString SourceDir;
- cmStdString BinaryDir;
- cmStdString BackupSourceDir;
- cmStdString BackupBinaryDir;
- cmStdString CTestRoot;
- cmStdString CVSCheckOut;
- cmStdString CTestCmd;
- cmStdString UpdateCmd;
- cmStdString CTestEnv;
- cmStdString InitialCache;
- cmStdString CMakeCmd;
- cmStdString CMOutFile;
- std::vector<cmStdString> ExtraUpdates;
+ std::string SourceDir;
+ std::string BinaryDir;
+ std::string BackupSourceDir;
+ std::string BackupBinaryDir;
+ std::string CTestRoot;
+ std::string CVSCheckOut;
+ std::string CTestCmd;
+ std::string UpdateCmd;
+ std::string CTestEnv;
+ std::string InitialCache;
+ std::string CMakeCmd;
+ std::string CMOutFile;
+ std::vector<std::string> ExtraUpdates;
double MinimumInterval;
double ContinuousDuration;
@@ -163,10 +158,9 @@ private:
// what time in seconds did this script start running
double ScriptStartTime;
- cmMakefile *Makefile;
- cmLocalGenerator *LocalGenerator;
- cmGlobalGenerator *GlobalGenerator;
- cmake *CMake;
+ cmMakefile* Makefile;
+ cmGlobalGenerator* GlobalGenerator;
+ cmake* CMake;
};
#endif
diff --git a/Source/CTest/cmCTestSleepCommand.cxx b/Source/CTest/cmCTestSleepCommand.cxx
index 7e8755066..2752cd370 100644
--- a/Source/CTest/cmCTestSleepCommand.cxx
+++ b/Source/CTest/cmCTestSleepCommand.cxx
@@ -1,55 +1,43 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestSleepCommand.h"
#include "cmCTestScriptHandler.h"
-#include <stdlib.h> // required for atoi
-bool cmCTestSleepCommand
-::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
+#include <stdlib.h>
+
+class cmExecutionStatus;
+
+bool cmCTestSleepCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& /*unused*/)
{
- if (args.size() < 1)
- {
+ if (args.empty()) {
this->SetError("called with incorrect number of arguments");
return false;
- }
+ }
// sleep for specified seconds
unsigned int time1 = atoi(args[0].c_str());
- if(args.size() == 1 )
- {
+ if (args.size() == 1) {
cmCTestScriptHandler::SleepInSeconds(time1);
// update the elapsed time since it could have slept for a while
this->CTestScriptHandler->UpdateElapsedTime();
return true;
- }
+ }
// sleep up to a duration
- if(args.size() == 3 )
- {
+ if (args.size() == 3) {
unsigned int duration = atoi(args[1].c_str());
unsigned int time2 = atoi(args[2].c_str());
- if (time1 + duration > time2)
- {
+ if (time1 + duration > time2) {
duration = (time1 + duration - time2);
cmCTestScriptHandler::SleepInSeconds(duration);
// update the elapsed time since it could have slept for a while
this->CTestScriptHandler->UpdateElapsedTime();
- }
- return true;
}
+ return true;
+ }
this->SetError("called with incorrect number of arguments");
return false;
}
-
-
diff --git a/Source/CTest/cmCTestSleepCommand.h b/Source/CTest/cmCTestSleepCommand.h
index 0f51ddfeb..f0b5f1eeb 100644
--- a/Source/CTest/cmCTestSleepCommand.h
+++ b/Source/CTest/cmCTestSleepCommand.h
@@ -1,19 +1,18 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestSleepCommand_h
#define cmCTestSleepCommand_h
+#include "cmConfigure.h"
+
#include "cmCTestCommand.h"
+#include <string>
+#include <vector>
+
+class cmCommand;
+class cmExecutionStatus;
+
/** \class cmCTestSleep
* \brief Run a ctest script
*
@@ -23,55 +22,25 @@
class cmCTestSleepCommand : public cmCTestCommand
{
public:
-
cmCTestSleepCommand() {}
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestSleepCommand* ni = new cmCTestSleepCommand;
ni->CTest = this->CTest;
ni->CTestScriptHandler = this->CTestScriptHandler;
return ni;
- }
+ }
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
- virtual bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus &status);
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- 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);
-
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
};
-
#endif
diff --git a/Source/CTest/cmCTestStartCommand.cxx b/Source/CTest/cmCTestStartCommand.cxx
index 228a17300..01a874b45 100644
--- a/Source/CTest/cmCTestStartCommand.cxx
+++ b/Source/CTest/cmCTestStartCommand.cxx
@@ -1,92 +1,84 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestStartCommand.h"
#include "cmCTest.h"
-#include "cmLocalGenerator.h"
-#include "cmGlobalGenerator.h"
#include "cmCTestVC.h"
#include "cmGeneratedFileStream.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+#include <sstream>
+#include <stddef.h>
+
+class cmExecutionStatus;
cmCTestStartCommand::cmCTestStartCommand()
{
this->CreateNewTag = true;
+ this->Quiet = false;
}
-bool cmCTestStartCommand
-::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
+bool cmCTestStartCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& /*unused*/)
{
- if (args.size() < 1)
- {
+ if (args.empty()) {
this->SetError("called with incorrect number of arguments");
return false;
- }
+ }
size_t cnt = 0;
const char* smodel = args[cnt].c_str();
- const char* src_dir = 0;
- const char* bld_dir = 0;
+ const char* src_dir = CM_NULLPTR;
+ const char* bld_dir = CM_NULLPTR;
cnt++;
- this->CTest->SetSpecificTrack(0);
- if ( cnt < args.size() -1 )
- {
- if ( args[cnt] == "TRACK" )
- {
- cnt ++;
+ this->CTest->SetSpecificTrack(CM_NULLPTR);
+ if (cnt < args.size() - 1) {
+ if (args[cnt] == "TRACK") {
+ cnt++;
this->CTest->SetSpecificTrack(args[cnt].c_str());
- cnt ++;
- }
+ cnt++;
}
+ }
- if (cnt < args.size())
- {
- if (args[cnt] == "APPEND")
- {
- cnt ++;
+ if (cnt < args.size()) {
+ if (args[cnt] == "APPEND") {
+ cnt++;
this->CreateNewTag = false;
- }
}
+ }
+ if (cnt < args.size()) {
+ if (args[cnt] == "QUIET") {
+ cnt++;
+ this->Quiet = true;
+ }
+ }
- if ( cnt < args.size() )
- {
+ if (cnt < args.size()) {
src_dir = args[cnt].c_str();
- cnt ++;
- if ( cnt < args.size() )
- {
+ cnt++;
+ if (cnt < args.size()) {
bld_dir = args[cnt].c_str();
- }
}
- if ( !src_dir )
- {
+ }
+ if (!src_dir) {
src_dir = this->Makefile->GetDefinition("CTEST_SOURCE_DIRECTORY");
- }
- if ( !bld_dir)
- {
+ }
+ if (!bld_dir) {
bld_dir = this->Makefile->GetDefinition("CTEST_BINARY_DIRECTORY");
- }
- if ( !src_dir )
- {
+ }
+ if (!src_dir) {
this->SetError("source directory not specified. Specify source directory "
- "as an argument or set CTEST_SOURCE_DIRECTORY");
+ "as an argument or set CTEST_SOURCE_DIRECTORY");
return false;
- }
- if ( !bld_dir)
- {
+ }
+ if (!bld_dir) {
this->SetError("binary directory not specified. Specify binary directory "
- "as an argument or set CTEST_BINARY_DIRECTORY");
+ "as an argument or set CTEST_BINARY_DIRECTORY");
return false;
- }
+ }
cmSystemTools::AddKeepPath(src_dir);
cmSystemTools::AddKeepPath(bld_dir);
@@ -95,45 +87,44 @@ bool cmCTestStartCommand
std::string sourceDir = cmSystemTools::CollapseFullPath(src_dir);
std::string binaryDir = cmSystemTools::CollapseFullPath(bld_dir);
- this->CTest->SetCTestConfiguration("SourceDirectory", sourceDir.c_str());
- this->CTest->SetCTestConfiguration("BuildDirectory", binaryDir.c_str());
-
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "Run dashboard with model "
- << smodel << std::endl
- << " Source directory: " << src_dir << std::endl
- << " Build directory: " << bld_dir << std::endl);
+ this->CTest->SetCTestConfiguration("SourceDirectory", sourceDir.c_str(),
+ this->Quiet);
+ this->CTest->SetCTestConfiguration("BuildDirectory", binaryDir.c_str(),
+ this->Quiet);
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "Run dashboard with model "
+ << smodel << std::endl
+ << " Source directory: " << src_dir << std::endl
+ << " Build directory: " << bld_dir << std::endl,
+ this->Quiet);
const char* track = this->CTest->GetSpecificTrack();
- if ( track )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- " Track: " << track << std::endl);
- }
+ if (track) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Track: " << track << std::endl, this->Quiet);
+ }
// Log startup actions.
std::string startLogFile = binaryDir + "/Testing/Temporary/LastStart.log";
cmGeneratedFileStream ofs(startLogFile.c_str());
- if(!ofs)
- {
+ if (!ofs) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Cannot create log file: LastStart.log" << std::endl);
return false;
- }
+ }
// Make sure the source directory exists.
- if(!this->InitialCheckout(ofs, sourceDir))
- {
+ if (!this->InitialCheckout(ofs, sourceDir)) {
return false;
- }
- if(!cmSystemTools::FileIsDirectory(sourceDir.c_str()))
- {
- cmOStringStream e;
+ }
+ if (!cmSystemTools::FileIsDirectory(sourceDir)) {
+ std::ostringstream e;
e << "given source path\n"
<< " " << sourceDir << "\n"
<< "which is not an existing directory. "
<< "Set CTEST_CHECKOUT_COMMAND to a command line to create it.";
- this->SetError(e.str().c_str());
+ this->SetError(e.str());
return false;
- }
+ }
this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", "OFF");
this->CTest->SetSuppressUpdatingCTestConfiguration(true);
@@ -144,27 +135,23 @@ bool cmCTestStartCommand
return this->CTest->InitializeFromCommand(this);
}
-//----------------------------------------------------------------------------
-bool cmCTestStartCommand::InitialCheckout(
- std::ostream& ofs, std::string const& sourceDir)
+bool cmCTestStartCommand::InitialCheckout(std::ostream& ofs,
+ std::string const& sourceDir)
{
// Use the user-provided command to create the source tree.
- const char* initialCheckoutCommand
- = this->Makefile->GetDefinition("CTEST_CHECKOUT_COMMAND");
- if(!initialCheckoutCommand)
- {
+ const char* initialCheckoutCommand =
+ this->Makefile->GetDefinition("CTEST_CHECKOUT_COMMAND");
+ if (!initialCheckoutCommand) {
initialCheckoutCommand =
this->Makefile->GetDefinition("CTEST_CVS_CHECKOUT");
- }
- if(initialCheckoutCommand)
- {
+ }
+ if (initialCheckoutCommand) {
// Use a generic VC object to run and log the command.
cmCTestVC vc(this->CTest, ofs);
- vc.SetSourceDirectory(sourceDir.c_str());
- if(!vc.InitialCheckout(initialCheckoutCommand))
- {
+ vc.SetSourceDirectory(sourceDir);
+ if (!vc.InitialCheckout(initialCheckoutCommand)) {
return false;
- }
}
+ }
return true;
}
diff --git a/Source/CTest/cmCTestStartCommand.h b/Source/CTest/cmCTestStartCommand.h
index 6be47703e..b4943f92d 100644
--- a/Source/CTest/cmCTestStartCommand.h
+++ b/Source/CTest/cmCTestStartCommand.h
@@ -1,19 +1,19 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestStartCommand_h
#define cmCTestStartCommand_h
+#include "cmConfigure.h"
+
#include "cmCTestCommand.h"
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+class cmCommand;
+class cmExecutionStatus;
+
/** \class cmCTestStart
* \brief Run a ctest script
*
@@ -22,71 +22,42 @@
class cmCTestStartCommand : public cmCTestCommand
{
public:
-
cmCTestStartCommand();
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestStartCommand* ni = new cmCTestStartCommand;
ni->CTest = this->CTest;
ni->CTestScriptHandler = this->CTestScriptHandler;
ni->CreateNewTag = this->CreateNewTag;
+ ni->Quiet = this->Quiet;
return ni;
- }
+ }
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
- virtual bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus &status);
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
/**
* Will this invocation of ctest_start create a new TAG file?
*/
- bool ShouldCreateNewTag()
- {
- return this->CreateNewTag;
- }
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- virtual const char* GetName() const { return "ctest_start";}
+ bool ShouldCreateNewTag() { return this->CreateNewTag; }
/**
- * Succinct documentation.
+ * Should this invocation of ctest_start output non-error messages?
*/
- 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);
+ bool ShouldBeQuiet() { return this->Quiet; }
private:
bool InitialCheckout(std::ostream& ofs, std::string const& sourceDir);
bool CreateNewTag;
+ bool Quiet;
};
-
#endif
diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx
index 24974e3bc..409eb51fc 100644
--- a/Source/CTest/cmCTestSubmitCommand.cxx
+++ b/Source/CTest/cmCTestSubmitCommand.cxx
@@ -1,117 +1,101 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestSubmitCommand.h"
#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
#include "cmCTestSubmitHandler.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <sstream>
+
+class cmExecutionStatus;
cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
{
- const char* ctestDropMethod
- = this->Makefile->GetDefinition("CTEST_DROP_METHOD");
- const char* ctestDropSite
- = this->Makefile->GetDefinition("CTEST_DROP_SITE");
- const char* ctestDropLocation
- = this->Makefile->GetDefinition("CTEST_DROP_LOCATION");
- const char* ctestTriggerSite
- = this->Makefile->GetDefinition("CTEST_TRIGGER_SITE");
- bool ctestDropSiteCDash
- = this->Makefile->IsOn("CTEST_DROP_SITE_CDASH");
-
- if ( !ctestDropMethod )
- {
+ const char* ctestDropMethod =
+ this->Makefile->GetDefinition("CTEST_DROP_METHOD");
+ const char* ctestDropSite = this->Makefile->GetDefinition("CTEST_DROP_SITE");
+ const char* ctestDropLocation =
+ this->Makefile->GetDefinition("CTEST_DROP_LOCATION");
+ const char* ctestTriggerSite =
+ this->Makefile->GetDefinition("CTEST_TRIGGER_SITE");
+ bool ctestDropSiteCDash = this->Makefile->IsOn("CTEST_DROP_SITE_CDASH");
+ const char* ctestProjectName =
+ this->Makefile->GetDefinition("CTEST_PROJECT_NAME");
+ if (!ctestDropMethod) {
ctestDropMethod = "http";
- }
+ }
- if ( !ctestDropSite )
- {
+ if (!ctestDropSite) {
// error: CDash requires CTEST_DROP_SITE definition
// in CTestConfig.cmake
- }
- if ( !ctestDropLocation )
- {
+ }
+ if (!ctestDropLocation) {
// error: CDash requires CTEST_DROP_LOCATION definition
// in CTestConfig.cmake
- }
-
- this->CTest->SetCTestConfiguration("DropMethod", ctestDropMethod);
- this->CTest->SetCTestConfiguration("DropSite", ctestDropSite);
- this->CTest->SetCTestConfiguration("DropLocation", ctestDropLocation);
-
- this->CTest->SetCTestConfiguration("IsCDash",
- ctestDropSiteCDash ? "TRUE" : "FALSE");
+ }
+ this->CTest->SetCTestConfiguration("ProjectName", ctestProjectName,
+ this->Quiet);
+ this->CTest->SetCTestConfiguration("DropMethod", ctestDropMethod,
+ this->Quiet);
+ this->CTest->SetCTestConfiguration("DropSite", ctestDropSite, this->Quiet);
+ this->CTest->SetCTestConfiguration("DropLocation", ctestDropLocation,
+ this->Quiet);
+
+ this->CTest->SetCTestConfiguration(
+ "IsCDash", ctestDropSiteCDash ? "TRUE" : "FALSE", this->Quiet);
// Only propagate TriggerSite for non-CDash projects:
//
- if ( !ctestDropSiteCDash )
- {
- this->CTest->SetCTestConfiguration("TriggerSite", ctestTriggerSite);
- }
-
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "CurlOptions", "CTEST_CURL_OPTIONS");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "DropSiteUser", "CTEST_DROP_SITE_USER");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "DropSitePassword", "CTEST_DROP_SITE_PASSWORD");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "ScpCommand", "CTEST_SCP_COMMAND");
-
- const char* notesFilesVariable
- = this->Makefile->GetDefinition("CTEST_NOTES_FILES");
- if (notesFilesVariable)
- {
+ if (!ctestDropSiteCDash) {
+ this->CTest->SetCTestConfiguration("TriggerSite", ctestTriggerSite,
+ this->Quiet);
+ }
+
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "CurlOptions", "CTEST_CURL_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "DropSiteUser", "CTEST_DROP_SITE_USER", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "DropSitePassword", "CTEST_DROP_SITE_PASSWORD",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "ScpCommand", "CTEST_SCP_COMMAND", this->Quiet);
+
+ const char* notesFilesVariable =
+ this->Makefile->GetDefinition("CTEST_NOTES_FILES");
+ if (notesFilesVariable) {
std::vector<std::string> notesFiles;
- std::vector<cmStdString> newNotesFiles;
- cmSystemTools::ExpandListArgument(notesFilesVariable,notesFiles);
- std::vector<std::string>::iterator it;
- for ( it = notesFiles.begin();
- it != notesFiles.end();
- ++ it )
- {
- newNotesFiles.push_back(*it);
- }
+ cmCTest::VectorOfStrings newNotesFiles;
+ cmSystemTools::ExpandListArgument(notesFilesVariable, notesFiles);
+ newNotesFiles.insert(newNotesFiles.end(), notesFiles.begin(),
+ notesFiles.end());
this->CTest->GenerateNotesFile(newNotesFiles);
- }
+ }
- const char* extraFilesVariable
- = this->Makefile->GetDefinition("CTEST_EXTRA_SUBMIT_FILES");
- if (extraFilesVariable)
- {
+ const char* extraFilesVariable =
+ this->Makefile->GetDefinition("CTEST_EXTRA_SUBMIT_FILES");
+ if (extraFilesVariable) {
std::vector<std::string> extraFiles;
- std::vector<cmStdString> newExtraFiles;
- cmSystemTools::ExpandListArgument(extraFilesVariable,extraFiles);
- std::vector<std::string>::iterator it;
- for ( it = extraFiles.begin();
- it != extraFiles.end();
- ++ it )
- {
- newExtraFiles.push_back(*it);
- }
- if ( !this->CTest->SubmitExtraFiles(newExtraFiles))
- {
+ cmCTest::VectorOfStrings newExtraFiles;
+ cmSystemTools::ExpandListArgument(extraFilesVariable, extraFiles);
+ newExtraFiles.insert(newExtraFiles.end(), extraFiles.begin(),
+ extraFiles.end());
+ if (!this->CTest->SubmitExtraFiles(newExtraFiles)) {
this->SetError("problem submitting extra files.");
- return 0;
- }
+ return CM_NULLPTR;
}
+ }
- cmCTestGenericHandler* handler
- = this->CTest->GetInitializedHandler("submit");
- if ( !handler )
- {
+ cmCTestGenericHandler* handler =
+ this->CTest->GetInitializedHandler("submit");
+ if (!handler) {
this->SetError("internal CTest error. Cannot instantiate submit handler");
- return 0;
- }
+ return CM_NULLPTR;
+ }
// If no FILES or PARTS given, *all* PARTS are submitted by default.
//
@@ -127,8 +111,7 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
// If given explicit FILES to submit, pass them to the handler.
//
- if(this->FilesMentioned)
- {
+ if (this->FilesMentioned) {
// Intentionally select *no* PARTS. (Pass an empty set.) If PARTS
// were also explicitly mentioned, they will be selected below...
// But FILES with no PARTS mentioned should just submit the FILES
@@ -138,117 +121,152 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
static_cast<cmCTestSubmitHandler*>(handler)->SelectParts(noParts);
static_cast<cmCTestSubmitHandler*>(handler)->SelectFiles(this->Files);
- }
+ }
// If a PARTS option was given, select only the named parts for submission.
//
- if(this->PartsMentioned)
- {
+ if (this->PartsMentioned) {
static_cast<cmCTestSubmitHandler*>(handler)->SelectParts(this->Parts);
- }
-
- static_cast<cmCTestSubmitHandler*>(handler)->SetOption("RetryDelay",
- this->RetryDelay.c_str());
- static_cast<cmCTestSubmitHandler*>(handler)->SetOption("RetryCount",
- this->RetryCount.c_str());
- static_cast<cmCTestSubmitHandler*>(handler)->SetOption("InternalTest",
- this->InternalTest ? "ON" : "OFF");
-
+ }
+
+ // Pass along any HTTPHEADER to the handler if this option was given.
+ if (!this->HttpHeaders.empty()) {
+ static_cast<cmCTestSubmitHandler*>(handler)->SetHttpHeaders(
+ this->HttpHeaders);
+ }
+
+ static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
+ "RetryDelay", this->RetryDelay.c_str());
+ static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
+ "RetryCount", this->RetryCount.c_str());
+ static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
+ "InternalTest", this->InternalTest ? "ON" : "OFF");
+
+ handler->SetQuiet(this->Quiet);
+
+ if (this->CDashUpload) {
+ static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
+ "CDashUploadFile", this->CDashUploadFile.c_str());
+ static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
+ "CDashUploadType", this->CDashUploadType.c_str());
+ }
return handler;
}
+bool cmCTestSubmitCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ this->CDashUpload = !args.empty() && args[0] == "CDASH_UPLOAD";
+ return this->cmCTestHandlerCommand::InitialPass(args, status);
+}
-//----------------------------------------------------------------------------
bool cmCTestSubmitCommand::CheckArgumentKeyword(std::string const& arg)
{
- // Look for arguments specific to this command.
- if(arg == "PARTS")
- {
- this->ArgumentDoing = ArgumentDoingParts;
- this->PartsMentioned = true;
- return true;
+ if (this->CDashUpload) {
+ // Arguments specific to the CDASH_UPLOAD signature.
+ if (arg == "CDASH_UPLOAD") {
+ this->ArgumentDoing = ArgumentDoingCDashUpload;
+ return true;
}
- if(arg == "FILES")
- {
- this->ArgumentDoing = ArgumentDoingFiles;
- this->FilesMentioned = true;
- return true;
+ if (arg == "CDASH_UPLOAD_TYPE") {
+ this->ArgumentDoing = ArgumentDoingCDashUploadType;
+ return true;
}
+ } else {
+ // Arguments that cannot be used with CDASH_UPLOAD.
+ if (arg == "PARTS") {
+ this->ArgumentDoing = ArgumentDoingParts;
+ this->PartsMentioned = true;
+ return true;
+ }
+
+ if (arg == "FILES") {
+ this->ArgumentDoing = ArgumentDoingFiles;
+ this->FilesMentioned = true;
+ return true;
+ }
+ }
+ // Arguments used by both modes.
+ if (arg == "HTTPHEADER") {
+ this->ArgumentDoing = ArgumentDoingHttpHeader;
+ return true;
+ }
- if(arg == "RETRY_COUNT")
- {
+ if (arg == "RETRY_COUNT") {
this->ArgumentDoing = ArgumentDoingRetryCount;
return true;
- }
+ }
- if(arg == "RETRY_DELAY")
- {
+ if (arg == "RETRY_DELAY") {
this->ArgumentDoing = ArgumentDoingRetryDelay;
return true;
- }
+ }
- if(arg == "INTERNAL_TEST_CHECKSUM")
- {
+ if (arg == "INTERNAL_TEST_CHECKSUM") {
this->InternalTest = true;
return true;
- }
+ }
// Look for other arguments.
return this->Superclass::CheckArgumentKeyword(arg);
}
-
-//----------------------------------------------------------------------------
bool cmCTestSubmitCommand::CheckArgumentValue(std::string const& arg)
{
// Handle states specific to this command.
- if(this->ArgumentDoing == ArgumentDoingParts)
- {
+ if (this->ArgumentDoing == ArgumentDoingParts) {
cmCTest::Part p = this->CTest->GetPartFromName(arg.c_str());
- if(p != cmCTest::PartCount)
- {
+ if (p != cmCTest::PartCount) {
this->Parts.insert(p);
- }
- else
- {
- cmOStringStream e;
+ } else {
+ std::ostringstream e;
e << "Part name \"" << arg << "\" is invalid.";
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
this->ArgumentDoing = ArgumentDoingError;
- }
- return true;
}
-
- if(this->ArgumentDoing == ArgumentDoingFiles)
- {
- cmStdString filename(arg);
- if(cmSystemTools::FileExists(filename.c_str()))
- {
- this->Files.insert(filename);
- }
- else
- {
- cmOStringStream e;
- e << "File \"" << filename << "\" does not exist. Cannot submit "
- << "a non-existent file.";
+ return true;
+ }
+
+ if (this->ArgumentDoing == ArgumentDoingFiles) {
+ if (cmSystemTools::FileExists(arg.c_str())) {
+ this->Files.insert(arg);
+ } else {
+ std::ostringstream e;
+ e << "File \"" << arg << "\" does not exist. Cannot submit "
+ << "a non-existent file.";
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
this->ArgumentDoing = ArgumentDoingError;
- }
- return true;
}
+ return true;
+ }
- if(this->ArgumentDoing == ArgumentDoingRetryCount)
- {
+ if (this->ArgumentDoing == ArgumentDoingHttpHeader) {
+ this->HttpHeaders.push_back(arg);
+ return true;
+ }
+
+ if (this->ArgumentDoing == ArgumentDoingRetryCount) {
this->RetryCount = arg;
return true;
- }
+ }
- if(this->ArgumentDoing == ArgumentDoingRetryDelay)
- {
+ if (this->ArgumentDoing == ArgumentDoingRetryDelay) {
this->RetryDelay = arg;
return true;
- }
+ }
+
+ if (this->ArgumentDoing == ArgumentDoingCDashUpload) {
+ this->ArgumentDoing = ArgumentDoingNone;
+ this->CDashUploadFile = arg;
+ return true;
+ }
+
+ if (this->ArgumentDoing == ArgumentDoingCDashUploadType) {
+ this->ArgumentDoing = ArgumentDoingNone;
+ this->CDashUploadType = arg;
+ return true;
+ }
// Look for other arguments.
return this->Superclass::CheckArgumentValue(arg);
diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h
index 53ee8754e..cf65cdc8d 100644
--- a/Source/CTest/cmCTestSubmitCommand.h
+++ b/Source/CTest/cmCTestSubmitCommand.h
@@ -1,19 +1,20 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestSubmitCommand_h
#define cmCTestSubmitCommand_h
-#include "cmCTestHandlerCommand.h"
+#include "cmConfigure.h"
+
#include "cmCTest.h"
+#include "cmCTestHandlerCommand.h"
+
+#include <set>
+#include <string>
+#include <vector>
+
+class cmCTestGenericHandler;
+class cmCommand;
+class cmExecutionStatus;
/** \class cmCTestSubmit
* \brief Run a ctest script
@@ -24,77 +25,42 @@
class cmCTestSubmitCommand : public cmCTestHandlerCommand
{
public:
-
cmCTestSubmitCommand()
- {
+ {
this->PartsMentioned = false;
this->FilesMentioned = false;
this->InternalTest = false;
this->RetryCount = "";
this->RetryDelay = "";
- }
+ this->CDashUpload = false;
+ }
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestSubmitCommand* ni = new cmCTestSubmitCommand;
ni->CTest = this->CTest;
ni->CTestScriptHandler = this->CTestScriptHandler;
return ni;
- }
+ }
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- virtual const char* GetName() const { return "ctest_submit";}
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) CM_OVERRIDE;
/**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "Submit results to a dashboard server.";
- }
-
- /**
- * More documentation.
+ * The name of the command as specified in CMakeList.txt.
*/
- 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";
- }
+ std::string GetName() const CM_OVERRIDE { return "ctest_submit"; }
- cmTypeMacro(cmCTestSubmitCommand, cmCTestHandlerCommand);
+ typedef cmCTestHandlerCommand Superclass;
protected:
- cmCTestGenericHandler* InitializeHandler();
+ cmCTestGenericHandler* InitializeHandler() CM_OVERRIDE;
- virtual bool CheckArgumentKeyword(std::string const& arg);
- virtual bool CheckArgumentValue(std::string const& arg);
+ bool CheckArgumentKeyword(std::string const& arg) CM_OVERRIDE;
+ bool CheckArgumentValue(std::string const& arg) CM_OVERRIDE;
enum
{
@@ -102,6 +68,9 @@ protected:
ArgumentDoingFiles,
ArgumentDoingRetryDelay,
ArgumentDoingRetryCount,
+ ArgumentDoingCDashUpload,
+ ArgumentDoingCDashUploadType,
+ ArgumentDoingHttpHeader,
ArgumentDoingLast2
};
@@ -112,7 +81,10 @@ protected:
cmCTest::SetOfStrings Files;
std::string RetryCount;
std::string RetryDelay;
+ bool CDashUpload;
+ std::string CDashUploadFile;
+ std::string CDashUploadType;
+ std::vector<std::string> HttpHeaders;
};
-
#endif
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index 941d34877..8d62fa156 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -1,161 +1,140 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestSubmitHandler.h"
-#include "cmSystemTools.h"
-#include "cmVersion.h"
-#include "cmGeneratedFileStream.h"
+#include "cm_curl.h"
+#include "cm_jsoncpp_reader.h"
+#include "cm_jsoncpp_value.h"
+#include "cmsys/Process.h"
+#include <sstream>
+#include <stdio.h>
+#include <stdlib.h>
+
#include "cmCTest.h"
+#include "cmCTestCurl.h"
+#include "cmCTestScriptHandler.h"
+#include "cmCurl.h"
+#include "cmGeneratedFileStream.h"
+#include "cmProcessOutput.h"
+#include "cmState.h"
+#include "cmSystemTools.h"
+#include "cmThirdParty.h"
+#include "cmWorkingDirectory.h"
#include "cmXMLParser.h"
+#include "cmake.h"
-#include <cmsys/Process.h>
-#include <cmsys/Base64.h>
-
-// For XML-RPC submission
+#if defined(CTEST_USE_XMLRPC)
+#include "cmVersion.h"
+#include "cm_sys_stat.h"
#include "cm_xmlrpc.h"
-
-// For curl submission
-#include "cm_curl.h"
-
-#include <sys/stat.h>
+#endif
#define SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT 120
typedef std::vector<char> cmCTestSubmitHandlerVectorOfChar;
-//----------------------------------------------------------------------------
-class cmCTestSubmitHandler::ResponseParser: public cmXMLParser
+class cmCTestSubmitHandler::ResponseParser : public cmXMLParser
{
public:
ResponseParser() { this->Status = STATUS_OK; }
- ~ResponseParser() {}
+ ~ResponseParser() CM_OVERRIDE {}
public:
-
enum StatusType
- {
+ {
STATUS_OK,
STATUS_WARNING,
STATUS_ERROR
- };
+ };
StatusType Status;
- std::string CDashVersion;
std::string Filename;
std::string MD5;
std::string Message;
private:
-
std::vector<char> CurrentValue;
std::string GetCurrentValue()
- {
+ {
std::string val;
- if(this->CurrentValue.size())
- {
+ if (!this->CurrentValue.empty()) {
val.assign(&this->CurrentValue[0], this->CurrentValue.size());
- }
- return val;
}
+ return val;
+ }
- virtual void StartElement(const char* name, const char** atts)
- {
+ void StartElement(const std::string& /*name*/,
+ const char** /*atts*/) CM_OVERRIDE
+ {
this->CurrentValue.clear();
- if(strcmp(name, "cdash") == 0)
- {
- this->CDashVersion = this->FindAttribute(atts, "version");
- }
- }
+ }
- virtual void CharacterDataHandler(const char* data, int length)
- {
- this->CurrentValue.insert(this->CurrentValue.end(), data, data+length);
- }
+ void CharacterDataHandler(const char* data, int length) CM_OVERRIDE
+ {
+ this->CurrentValue.insert(this->CurrentValue.end(), data, data + length);
+ }
- virtual void EndElement(const char* name)
- {
- if(strcmp(name, "status") == 0)
- {
+ void EndElement(const std::string& name) CM_OVERRIDE
+ {
+ if (name == "status") {
std::string status = cmSystemTools::UpperCase(this->GetCurrentValue());
- if(status == "OK" || status == "SUCCESS")
- {
+ if (status == "OK" || status == "SUCCESS") {
this->Status = STATUS_OK;
- }
- else if(status == "WARNING")
- {
+ } else if (status == "WARNING") {
this->Status = STATUS_WARNING;
- }
- else
- {
+ } else {
this->Status = STATUS_ERROR;
- }
}
- else if(strcmp(name, "filename") == 0)
- {
+ } else if (name == "filename") {
this->Filename = this->GetCurrentValue();
- }
- else if(strcmp(name, "md5") == 0)
- {
+ } else if (name == "md5") {
this->MD5 = this->GetCurrentValue();
- }
- else if(strcmp(name, "message") == 0)
- {
+ } else if (name == "message") {
this->Message = this->GetCurrentValue();
- }
}
+ }
};
-
-static size_t
-cmCTestSubmitHandlerWriteMemoryCallback(void *ptr, size_t size, size_t nmemb,
- void *data)
+static size_t cmCTestSubmitHandlerWriteMemoryCallback(void* ptr, size_t size,
+ size_t nmemb, void* data)
{
int realsize = (int)(size * nmemb);
- cmCTestSubmitHandlerVectorOfChar *vec
- = static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
+ cmCTestSubmitHandlerVectorOfChar* vec =
+ static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
const char* chPtr = static_cast<char*>(ptr);
vec->insert(vec->end(), chPtr, chPtr + realsize);
return realsize;
}
-static size_t
-cmCTestSubmitHandlerCurlDebugCallback(CURL *, curl_infotype, char *chPtr,
- size_t size, void *data)
+static size_t cmCTestSubmitHandlerCurlDebugCallback(CURL* /*unused*/,
+ curl_infotype /*unused*/,
+ char* chPtr, size_t size,
+ void* data)
{
- cmCTestSubmitHandlerVectorOfChar *vec
- = static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
+ cmCTestSubmitHandlerVectorOfChar* vec =
+ static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
vec->insert(vec->end(), chPtr, chPtr + size);
return size;
}
-//----------------------------------------------------------------------------
-cmCTestSubmitHandler::cmCTestSubmitHandler() : HTTPProxy(), FTPProxy()
+cmCTestSubmitHandler::cmCTestSubmitHandler()
+ : HTTPProxy()
+ , FTPProxy()
{
this->Initialize();
}
-//----------------------------------------------------------------------------
void cmCTestSubmitHandler::Initialize()
{
// We submit all available parts by default.
- for(cmCTest::Part p = cmCTest::PartStart;
- p != cmCTest::PartCount; p = cmCTest::Part(p+1))
- {
+ for (cmCTest::Part p = cmCTest::PartStart; p != cmCTest::PartCount;
+ p = cmCTest::Part(p + 1)) {
this->SubmitPart[p] = true;
- }
+ }
this->CDash = false;
this->HasWarnings = false;
this->HasErrors = false;
@@ -165,17 +144,16 @@ void cmCTestSubmitHandler::Initialize()
this->HTTPProxyAuth = "";
this->FTPProxy = "";
this->FTPProxyType = 0;
- this->LogFile = 0;
+ this->LogFile = CM_NULLPTR;
this->Files.clear();
}
-//----------------------------------------------------------------------------
-bool cmCTestSubmitHandler::SubmitUsingFTP(const cmStdString& localprefix,
- const std::set<cmStdString>& files,
- const cmStdString& remoteprefix,
- const cmStdString& url)
+bool cmCTestSubmitHandler::SubmitUsingFTP(const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url)
{
- CURL *curl;
+ CURL* curl;
CURLcode res;
FILE* ftpfile;
char error_buffer[1024];
@@ -184,28 +162,24 @@ bool cmCTestSubmitHandler::SubmitUsingFTP(const cmStdString& localprefix,
::curl_global_init(CURL_GLOBAL_ALL);
cmCTest::SetOfStrings::const_iterator file;
- for ( file = files.begin(); file != files.end(); ++file )
- {
+ for (file = files.begin(); file != files.end(); ++file) {
/* get a curl handle */
curl = curl_easy_init();
- if(curl)
- {
+ if (curl) {
// Using proxy
- if ( this->FTPProxyType > 0 )
- {
+ if (this->FTPProxyType > 0) {
curl_easy_setopt(curl, CURLOPT_PROXY, this->FTPProxy.c_str());
- switch (this->FTPProxyType)
- {
- case 2:
- curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
- break;
- case 3:
- curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
- break;
- default:
- curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
- }
+ switch (this->FTPProxyType) {
+ case 2:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
+ break;
+ case 3:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
+ break;
+ default:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
}
+ }
// enable uploading
::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
@@ -213,193 +187,191 @@ bool cmCTestSubmitHandler::SubmitUsingFTP(const cmStdString& localprefix,
// if there is little to no activity for too long stop submitting
::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME,
- SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
+ SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
- cmStdString local_file = *file;
- if ( !cmSystemTools::FileExists(local_file.c_str()) )
- {
+ std::string local_file = *file;
+ if (!cmSystemTools::FileExists(local_file.c_str())) {
local_file = localprefix + "/" + *file;
- }
- cmStdString upload_as
- = url + "/" + remoteprefix + cmSystemTools::GetFilenameName(*file);
-
- struct stat st;
- if ( ::stat(local_file.c_str(), &st) )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot find file: "
- << local_file.c_str() << std::endl);
+ }
+ std::string upload_as =
+ url + "/" + remoteprefix + cmSystemTools::GetFilenameName(*file);
+
+ if (!cmSystemTools::FileExists(local_file.c_str())) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Cannot find file: " << local_file << std::endl);
::curl_easy_cleanup(curl);
::curl_global_cleanup();
return false;
- }
+ }
+ unsigned long filelen = cmSystemTools::FileLength(local_file);
- ftpfile = ::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: "
- << local_file.c_str() << " to "
- << upload_as.c_str() << std::endl);
+ ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
+ *this->LogFile << "\tUpload file: " << local_file << " to " << upload_as
+ << std::endl;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Upload file: " << local_file << " to "
+ << upload_as << std::endl,
+ this->Quiet);
::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
// specify target
- ::curl_easy_setopt(curl,CURLOPT_URL, upload_as.c_str());
+ ::curl_easy_setopt(curl, CURLOPT_URL, upload_as.c_str());
// now specify which file to upload
::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
// and give the size of the upload (optional)
- ::curl_easy_setopt(curl, CURLOPT_INFILESIZE,
- static_cast<long>(st.st_size));
+ ::curl_easy_setopt(curl, CURLOPT_INFILESIZE, static_cast<long>(filelen));
// and give curl the buffer for errors
::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
// specify handler for output
::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
- cmCTestSubmitHandlerWriteMemoryCallback);
+ cmCTestSubmitHandlerWriteMemoryCallback);
::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
- cmCTestSubmitHandlerCurlDebugCallback);
+ cmCTestSubmitHandlerCurlDebugCallback);
/* we pass our 'chunk' struct to the callback function */
cmCTestSubmitHandlerVectorOfChar chunk;
cmCTestSubmitHandlerVectorOfChar chunkDebug;
- ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
- ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
+ ::curl_easy_setopt(curl, CURLOPT_FILE, (void*)&chunk);
+ ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void*)&chunkDebug);
// Now run off and do what you've been told!
res = ::curl_easy_perform(curl);
- if ( chunk.size() > 0 )
- {
- cmCTestLog(this->CTest, DEBUG, "CURL output: ["
- << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
- << std::endl);
- }
- if ( chunkDebug.size() > 0 )
- {
- cmCTestLog(this->CTest, DEBUG, "CURL debug output: ["
- << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
- << std::endl);
- }
+ if (!chunk.empty()) {
+ cmCTestOptionalLog(this->CTest, DEBUG, "CURL output: ["
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+ << "]" << std::endl,
+ this->Quiet);
+ }
+ if (!chunkDebug.empty()) {
+ cmCTestOptionalLog(
+ this->CTest, DEBUG, "CURL debug output: ["
+ << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
+ << std::endl,
+ this->Quiet);
+ }
fclose(ftpfile);
- if ( res )
- {
+ if (res) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, " Error when uploading file: "
+ << local_file << std::endl);
cmCTestLog(this->CTest, ERROR_MESSAGE,
- " Error when uploading file: "
- << local_file.c_str() << std::endl);
- cmCTestLog(this->CTest, ERROR_MESSAGE, " Error message was: "
- << error_buffer << std::endl);
- *this->LogFile << " Error when uploading file: "
- << local_file.c_str()
+ " Error message was: " << error_buffer << std::endl);
+ *this->LogFile << " Error when uploading file: " << local_file
<< std::endl
- << " Error message was: "
- << error_buffer << std::endl
+ << " Error message was: " << error_buffer << std::endl
<< " Curl output was: ";
// avoid dereference of empty vector
- if(chunk.size())
- {
+ if (!chunk.empty()) {
*this->LogFile << cmCTestLogWrite(&*chunk.begin(), chunk.size());
cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
- << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
- << std::endl);
- }
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
+ << std::endl);
+ }
*this->LogFile << std::endl;
::curl_easy_cleanup(curl);
::curl_global_cleanup();
return false;
- }
+ }
// always cleanup
::curl_easy_cleanup(curl);
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Uploaded: " + local_file
- << std::endl);
- }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Uploaded: " + local_file << std::endl,
+ this->Quiet);
}
+ }
::curl_global_cleanup();
return true;
}
-//----------------------------------------------------------------------------
// Uploading files is simpler
-bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix,
- const std::set<cmStdString>& files,
- const cmStdString& remoteprefix,
- const cmStdString& url)
+bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url)
{
- CURL *curl;
+ CURL* curl;
CURLcode res;
FILE* ftpfile;
char error_buffer[1024];
+ // Set Content-Type to satisfy fussy modsecurity rules.
+ struct curl_slist* headers =
+ ::curl_slist_append(CM_NULLPTR, "Content-Type: text/xml");
+
+ // Add any additional headers that the user specified.
+ for (std::vector<std::string>::const_iterator h = this->HttpHeaders.begin();
+ h != this->HttpHeaders.end(); ++h) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Add HTTP Header: \"" << *h << "\"" << std::endl,
+ this->Quiet);
+ headers = ::curl_slist_append(headers, h->c_str());
+ }
/* In windows, this will init the winsock stuff */
::curl_global_init(CURL_GLOBAL_ALL);
- cmStdString dropMethod(this->CTest->GetCTestConfiguration("DropMethod"));
- cmStdString curlopt(this->CTest->GetCTestConfiguration("CurlOptions"));
+ std::string dropMethod(this->CTest->GetCTestConfiguration("DropMethod"));
+ std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions"));
std::vector<std::string> args;
- cmSystemTools::ExpandListArgument(curlopt.c_str(), args);
+ cmSystemTools::ExpandListArgument(curlopt, args);
bool verifyPeerOff = false;
bool verifyHostOff = false;
- for( std::vector<std::string>::iterator i = args.begin();
- i != args.end(); ++i)
- {
- if(*i == "CURLOPT_SSL_VERIFYPEER_OFF")
- {
+ for (std::vector<std::string>::iterator i = args.begin(); i != args.end();
+ ++i) {
+ if (*i == "CURLOPT_SSL_VERIFYPEER_OFF") {
verifyPeerOff = true;
- }
- if(*i == "CURLOPT_SSL_VERIFYHOST_OFF")
- {
+ }
+ if (*i == "CURLOPT_SSL_VERIFYHOST_OFF") {
verifyHostOff = true;
- }
}
- cmStdString::size_type kk;
+ }
+ std::string::size_type kk;
cmCTest::SetOfStrings::const_iterator file;
- for ( file = files.begin(); file != files.end(); ++file )
- {
+ for (file = files.begin(); file != files.end(); ++file) {
/* get a curl handle */
curl = curl_easy_init();
- if(curl)
- {
- if(verifyPeerOff)
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " Set CURLOPT_SSL_VERIFYPEER to off\n");
+ if (curl) {
+ cmCurlSetCAInfo(curl);
+ if (verifyPeerOff) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Set CURLOPT_SSL_VERIFYPEER to off\n",
+ this->Quiet);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
- }
- if(verifyHostOff)
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " Set CURLOPT_SSL_VERIFYHOST to off\n");
+ }
+ if (verifyHostOff) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Set CURLOPT_SSL_VERIFYHOST to off\n",
+ this->Quiet);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
- }
+ }
// Using proxy
- if ( this->HTTPProxyType > 0 )
- {
+ if (this->HTTPProxyType > 0) {
curl_easy_setopt(curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
- switch (this->HTTPProxyType)
- {
- case 2:
- curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
- break;
- case 3:
- curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
- break;
- default:
- curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
- if (this->HTTPProxyAuth.size() > 0)
- {
- curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
- this->HTTPProxyAuth.c_str());
+ switch (this->HTTPProxyType) {
+ case 2:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
+ break;
+ case 3:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
+ break;
+ default:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ if (!this->HTTPProxyAuth.empty()) {
+ curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
+ this->HTTPProxyAuth.c_str());
}
- }
}
- if(this->CTest->ShouldUseHTTP10())
- {
+ }
+ if (this->CTest->ShouldUseHTTP10()) {
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
- }
+ }
// enable HTTP ERROR parsing
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
/* enable uploading */
@@ -408,165 +380,156 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix,
// if there is little to no activity for too long stop submitting
::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME,
- SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
+ SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
/* HTTP PUT please */
::curl_easy_setopt(curl, CURLOPT_PUT, 1);
::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
- cmStdString local_file = *file;
- if ( !cmSystemTools::FileExists(local_file.c_str()) )
- {
+ ::curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+
+ std::string local_file = *file;
+ if (!cmSystemTools::FileExists(local_file.c_str())) {
local_file = localprefix + "/" + *file;
- }
- cmStdString remote_file
- = remoteprefix + cmSystemTools::GetFilenameName(*file);
+ }
+ std::string remote_file =
+ remoteprefix + cmSystemTools::GetFilenameName(*file);
- *this->LogFile << "\tUpload file: " << local_file.c_str() << " to "
- << remote_file.c_str() << std::endl;
+ *this->LogFile << "\tUpload file: " << local_file << " to "
+ << remote_file << std::endl;
- cmStdString ofile = "";
- for ( kk = 0; kk < remote_file.size(); kk ++ )
- {
+ std::string ofile;
+ for (kk = 0; kk < remote_file.size(); kk++) {
char c = remote_file[kk];
char hexCh[4] = { 0, 0, 0, 0 };
hexCh[0] = c;
- switch ( c )
- {
- case '+':
- case '?':
- case '/':
- case '\\':
- case '&':
- case ' ':
- case '=':
- case '%':
- sprintf(hexCh, "%%%02X", (int)c);
- ofile.append(hexCh);
- break;
- default:
- ofile.append(hexCh);
- }
+ switch (c) {
+ case '+':
+ case '?':
+ case '/':
+ case '\\':
+ case '&':
+ case ' ':
+ case '=':
+ case '%':
+ sprintf(hexCh, "%%%02X", (int)c);
+ ofile.append(hexCh);
+ break;
+ default:
+ ofile.append(hexCh);
}
- cmStdString upload_as
- = url + ((url.find("?",0) == cmStdString::npos) ? "?" : "&")
- + "FileName=" + ofile;
+ }
+ std::string upload_as = url +
+ ((url.find('?') == std::string::npos) ? '?' : '&') + "FileName=" +
+ ofile;
upload_as += "&MD5=";
- if(cmSystemTools::IsOn(this->GetOption("InternalTest")))
- {
+ if (cmSystemTools::IsOn(this->GetOption("InternalTest"))) {
upload_as += "bad_md5sum";
- }
- else
- {
+ } else {
char md5[33];
- cmSystemTools::ComputeFileMD5(local_file.c_str(), md5);
+ cmSystemTools::ComputeFileMD5(local_file, md5);
md5[32] = 0;
upload_as += md5;
- }
+ }
- struct stat st;
- if ( ::stat(local_file.c_str(), &st) )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot find file: "
- << local_file.c_str() << std::endl);
+ if (!cmSystemTools::FileExists(local_file.c_str())) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Cannot find file: " << local_file << std::endl);
::curl_easy_cleanup(curl);
+ ::curl_slist_free_all(headers);
::curl_global_cleanup();
return false;
- }
+ }
+ unsigned long filelen = cmSystemTools::FileLength(local_file);
- ftpfile = ::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);
+ ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Upload file: " << local_file << " to "
+ << upload_as << " Size: "
+ << filelen << std::endl,
+ this->Quiet);
// specify target
- ::curl_easy_setopt(curl,CURLOPT_URL, upload_as.c_str());
+ ::curl_easy_setopt(curl, CURLOPT_URL, upload_as.c_str());
// now specify which file to upload
::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
// and give the size of the upload (optional)
- ::curl_easy_setopt(curl, CURLOPT_INFILESIZE,
- static_cast<long>(st.st_size));
+ ::curl_easy_setopt(curl, CURLOPT_INFILESIZE, static_cast<long>(filelen));
// and give curl the buffer for errors
::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
// specify handler for output
::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
- cmCTestSubmitHandlerWriteMemoryCallback);
+ cmCTestSubmitHandlerWriteMemoryCallback);
::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
- cmCTestSubmitHandlerCurlDebugCallback);
+ cmCTestSubmitHandlerCurlDebugCallback);
/* we pass our 'chunk' struct to the callback function */
cmCTestSubmitHandlerVectorOfChar chunk;
cmCTestSubmitHandlerVectorOfChar chunkDebug;
- ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
- ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
+ ::curl_easy_setopt(curl, CURLOPT_FILE, (void*)&chunk);
+ ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void*)&chunkDebug);
// Now run off and do what you've been told!
res = ::curl_easy_perform(curl);
- if(cmSystemTools::IsOn(this->GetOption("InternalTest")) &&
- cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
- this->CTest->GetCDashVersion().c_str(), "1.7"))
- {
- // mock failure output for internal test case
- std::string mock_output = "<cdash version=\"1.7.0\">\n"
- " <status>ERROR</status>\n"
- " <message>Checksum failed for file.</message>\n"
- "</cdash>\n";
- chunk.clear();
- chunk.assign(mock_output.begin(), mock_output.end());
- }
-
- if ( chunk.size() > 0 )
- {
- cmCTestLog(this->CTest, DEBUG, "CURL output: ["
- << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
- << std::endl);
+ if (!chunk.empty()) {
+ cmCTestOptionalLog(this->CTest, DEBUG, "CURL output: ["
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+ << "]" << std::endl,
+ this->Quiet);
this->ParseResponse(chunk);
- }
- if ( chunkDebug.size() > 0 )
- {
- cmCTestLog(this->CTest, DEBUG, "CURL debug output: ["
- << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
- << std::endl);
- }
+ }
+ if (!chunkDebug.empty()) {
+ cmCTestOptionalLog(
+ this->CTest, DEBUG, "CURL debug output: ["
+ << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
+ << std::endl,
+ this->Quiet);
+ }
// If curl failed for any reason, or checksum fails, wait and retry
//
- if(res != CURLE_OK || this->HasErrors)
- {
- std::string retryDelay = this->GetOption("RetryDelay") == NULL ?
- "" : this->GetOption("RetryDelay");
- std::string retryCount = this->GetOption("RetryCount") == NULL ?
- "" : this->GetOption("RetryCount");
-
- int delay = retryDelay == "" ? atoi(this->CTest->GetCTestConfiguration(
- "CTestSubmitRetryDelay").c_str()) : atoi(retryDelay.c_str());
- int count = retryCount == "" ? atoi(this->CTest->GetCTestConfiguration(
- "CTestSubmitRetryCount").c_str()) : atoi(retryCount.c_str());
-
- for(int i = 0; i < count; i++)
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- " Submit failed, waiting " << delay << " seconds...\n");
+ if (res != CURLE_OK || this->HasErrors) {
+ std::string retryDelay = this->GetOption("RetryDelay") == CM_NULLPTR
+ ? ""
+ : this->GetOption("RetryDelay");
+ std::string retryCount = this->GetOption("RetryCount") == CM_NULLPTR
+ ? ""
+ : this->GetOption("RetryCount");
+
+ int delay = retryDelay == ""
+ ? atoi(this->CTest->GetCTestConfiguration("CTestSubmitRetryDelay")
+ .c_str())
+ : atoi(retryDelay.c_str());
+ int count = retryCount == ""
+ ? atoi(this->CTest->GetCTestConfiguration("CTestSubmitRetryCount")
+ .c_str())
+ : atoi(retryCount.c_str());
+
+ for (int i = 0; i < count; i++) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Submit failed, waiting " << delay
+ << " seconds...\n",
+ this->Quiet);
double stop = cmSystemTools::GetTime() + delay;
- while(cmSystemTools::GetTime() < stop)
- {
+ while (cmSystemTools::GetTime() < stop) {
cmSystemTools::Delay(100);
- }
+ }
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- " Retry submission: Attempt " << (i + 1) << " of "
- << count << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Retry submission: Attempt "
+ << (i + 1) << " of " << count << std::endl,
+ this->Quiet);
::fclose(ftpfile);
- ftpfile = ::fopen(local_file.c_str(), "rb");
+ ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
chunk.clear();
@@ -575,134 +538,121 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix,
res = ::curl_easy_perform(curl);
- if ( chunk.size() > 0 )
- {
- cmCTestLog(this->CTest, DEBUG, "CURL output: ["
- << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
- << std::endl);
+ if (!chunk.empty()) {
+ cmCTestOptionalLog(
+ this->CTest, DEBUG, "CURL output: ["
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
+ << std::endl,
+ this->Quiet);
this->ParseResponse(chunk);
- }
+ }
- if(res == CURLE_OK && !this->HasErrors)
- {
+ if (res == CURLE_OK && !this->HasErrors) {
break;
- }
}
}
+ }
fclose(ftpfile);
- if ( res )
- {
+ if (res) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, " Error when uploading file: "
+ << local_file << std::endl);
cmCTestLog(this->CTest, ERROR_MESSAGE,
- " Error when uploading file: "
- << local_file.c_str() << std::endl);
- cmCTestLog(this->CTest, ERROR_MESSAGE, " Error message was: "
- << error_buffer << std::endl);
- *this->LogFile << " Error when uploading file: "
- << local_file.c_str()
+ " Error message was: " << error_buffer << std::endl);
+ *this->LogFile << " Error when uploading file: " << local_file
<< std::endl
<< " Error message was: " << error_buffer
<< std::endl;
// avoid deref of begin for zero size array
- if(chunk.size())
- {
+ if (!chunk.empty()) {
*this->LogFile << " Curl output was: "
<< cmCTestLogWrite(&*chunk.begin(), chunk.size())
<< std::endl;
cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
- << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
- << std::endl);
- }
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
+ << std::endl);
+ }
::curl_easy_cleanup(curl);
+ ::curl_slist_free_all(headers);
::curl_global_cleanup();
return false;
- }
+ }
// always cleanup
::curl_easy_cleanup(curl);
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Uploaded: " + local_file
- << std::endl);
- }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Uploaded: " + local_file << std::endl,
+ this->Quiet);
}
+ }
+ ::curl_slist_free_all(headers);
::curl_global_cleanup();
return true;
}
-//----------------------------------------------------------------------------
-void cmCTestSubmitHandler
-::ParseResponse(cmCTestSubmitHandlerVectorOfChar chunk)
+void cmCTestSubmitHandler::ParseResponse(
+ cmCTestSubmitHandlerVectorOfChar chunk)
{
- std::string output = "";
+ std::string output;
output.append(chunk.begin(), chunk.end());
- if(output.find("<cdash") != output.npos)
- {
+ if (output.find("<cdash") != std::string::npos) {
ResponseParser parser;
parser.Parse(output.c_str());
- if(parser.Status != ResponseParser::STATUS_OK)
- {
+ if (parser.Status != ResponseParser::STATUS_OK) {
this->HasErrors = true;
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission failed: " <<
- parser.Message << std::endl);
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Submission failed: " << parser.Message << std::endl);
return;
- }
}
+ }
output = cmSystemTools::UpperCase(output);
- if(output.find("WARNING") != std::string::npos)
- {
+ if (output.find("WARNING") != std::string::npos) {
this->HasWarnings = true;
- }
- if(output.find("ERROR") != std::string::npos)
- {
+ }
+ if (output.find("ERROR") != std::string::npos) {
this->HasErrors = true;
- }
+ }
- if(this->HasWarnings || this->HasErrors)
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Server Response:\n" <<
- cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "\n");
- }
+ if (this->HasWarnings || this->HasErrors) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " Server Response:\n"
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "\n");
+ }
}
-//----------------------------------------------------------------------------
-bool cmCTestSubmitHandler::TriggerUsingHTTP(
- const std::set<cmStdString>& files,
- const cmStdString& remoteprefix,
- const cmStdString& url)
+bool cmCTestSubmitHandler::TriggerUsingHTTP(const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url)
{
- CURL *curl;
+ CURL* curl;
char error_buffer[1024];
+
/* In windows, this will init the winsock stuff */
::curl_global_init(CURL_GLOBAL_ALL);
cmCTest::SetOfStrings::const_iterator file;
- for ( file = files.begin(); file != files.end(); ++file )
- {
+ for (file = files.begin(); file != files.end(); ++file) {
/* get a curl handle */
curl = curl_easy_init();
- if(curl)
- {
+ if (curl) {
// Using proxy
- if ( this->HTTPProxyType > 0 )
- {
+ if (this->HTTPProxyType > 0) {
curl_easy_setopt(curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
- switch (this->HTTPProxyType)
- {
- case 2:
- curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
- break;
- case 3:
- curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
- break;
- default:
- curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
- if (this->HTTPProxyAuth.size() > 0)
- {
- curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
- this->HTTPProxyAuth.c_str());
+ switch (this->HTTPProxyType) {
+ case 2:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
+ break;
+ case 3:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
+ break;
+ default:
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ if (!this->HTTPProxyAuth.empty()) {
+ curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
+ this->HTTPProxyAuth.c_str());
}
- }
}
+ }
::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
@@ -711,126 +661,120 @@ bool cmCTestSubmitHandler::TriggerUsingHTTP(
// specify handler for output
::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
- cmCTestSubmitHandlerWriteMemoryCallback);
+ cmCTestSubmitHandlerWriteMemoryCallback);
::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
- cmCTestSubmitHandlerCurlDebugCallback);
+ cmCTestSubmitHandlerCurlDebugCallback);
/* we pass our 'chunk' struct to the callback function */
cmCTestSubmitHandlerVectorOfChar chunk;
cmCTestSubmitHandlerVectorOfChar chunkDebug;
- ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
- ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
-
- cmStdString rfile
- = remoteprefix + cmSystemTools::GetFilenameName(*file);
- cmStdString ofile = "";
- cmStdString::iterator kk;
- for ( kk = rfile.begin(); kk < rfile.end(); ++ kk)
- {
+ ::curl_easy_setopt(curl, CURLOPT_FILE, (void*)&chunk);
+ ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void*)&chunkDebug);
+
+ std::string rfile = remoteprefix + cmSystemTools::GetFilenameName(*file);
+ std::string ofile;
+ std::string::iterator kk;
+ for (kk = rfile.begin(); kk < rfile.end(); ++kk) {
char c = *kk;
char hexCh[4] = { 0, 0, 0, 0 };
hexCh[0] = c;
- switch ( c )
- {
- case '+':
- case '?':
- case '/':
- case '\\':
- case '&':
- case ' ':
- case '=':
- case '%':
- sprintf(hexCh, "%%%02X", (int)c);
- ofile.append(hexCh);
- break;
- default:
- ofile.append(hexCh);
- }
+ switch (c) {
+ case '+':
+ case '?':
+ case '/':
+ case '\\':
+ case '&':
+ case ' ':
+ case '=':
+ case '%':
+ sprintf(hexCh, "%%%02X", (int)c);
+ ofile.append(hexCh);
+ break;
+ default:
+ ofile.append(hexCh);
}
- cmStdString turl
- = url + ((url.find("?",0) == cmStdString::npos) ? "?" : "&")
- + "xmlfile=" + ofile;
- *this->LogFile << "Trigger url: " << turl.c_str() << std::endl;
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Trigger url: "
- << turl.c_str() << std::endl);
+ }
+ std::string turl = url +
+ ((url.find('?') == std::string::npos) ? '?' : '&') + "xmlfile=" +
+ ofile;
+ *this->LogFile << "Trigger url: " << turl << std::endl;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Trigger url: " << turl << std::endl, this->Quiet);
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_easy_setopt(curl, CURLOPT_URL, turl.c_str());
- if ( curl_easy_perform(curl) )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, " Error when triggering: "
- << turl.c_str() << std::endl);
- cmCTestLog(this->CTest, ERROR_MESSAGE, " Error message was: "
- << error_buffer << std::endl);
+ if (curl_easy_perform(curl)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Error when triggering: " << turl << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Error message was: " << error_buffer << std::endl);
*this->LogFile << "\tTriggering failed with error: " << error_buffer
<< std::endl
<< " Error message was: " << error_buffer
<< std::endl;
- if(chunk.size())
- {
- *this->LogFile
- << " Curl output was: "
- << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << std::endl;
+ if (!chunk.empty()) {
+ *this->LogFile << " Curl output was: "
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+ << std::endl;
cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
- << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
- << std::endl);
- }
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
+ << std::endl);
+ }
::curl_easy_cleanup(curl);
::curl_global_cleanup();
return false;
- }
+ }
- if ( chunk.size() > 0 )
- {
- cmCTestLog(this->CTest, DEBUG, "CURL output: ["
- << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
- << std::endl);
- }
- if ( chunkDebug.size() > 0 )
- {
- cmCTestLog(this->CTest, DEBUG, "CURL debug output: ["
- << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size())
- << "]" << std::endl);
- }
+ if (!chunk.empty()) {
+ cmCTestOptionalLog(this->CTest, DEBUG, "CURL output: ["
+ << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+ << "]" << std::endl,
+ this->Quiet);
+ }
+ if (!chunkDebug.empty()) {
+ cmCTestOptionalLog(
+ this->CTest, DEBUG, "CURL debug output: ["
+ << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
+ << std::endl,
+ this->Quiet);
+ }
// always cleanup
::curl_easy_cleanup(curl);
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl);
- }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl,
+ this->Quiet);
}
+ }
::curl_global_cleanup();
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Dart server triggered..."
- << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Dart server triggered..." << std::endl, this->Quiet);
return true;
}
-//----------------------------------------------------------------------------
-bool cmCTestSubmitHandler::SubmitUsingSCP(
- const cmStdString& scp_command,
- const cmStdString& localprefix,
- const std::set<cmStdString>& files,
- const cmStdString& remoteprefix,
- const cmStdString& url)
+bool cmCTestSubmitHandler::SubmitUsingSCP(const std::string& scp_command,
+ const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url)
{
- if ( !scp_command.size() || !localprefix.size() ||
- !files.size() || !remoteprefix.size() || !url.size() )
- {
- return 0;
- }
+ if (scp_command.empty() || localprefix.empty() || files.empty() ||
+ remoteprefix.empty() || url.empty()) {
+ return false;
+ }
+
std::vector<const char*> argv;
argv.push_back(scp_command.c_str()); // Scp command
argv.push_back(scp_command.c_str()); // Dummy string for file
argv.push_back(scp_command.c_str()); // Dummy string for remote url
- argv.push_back(0);
+ argv.push_back(CM_NULLPTR);
cmsysProcess* cp = cmsysProcess_New();
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
- //cmsysProcess_SetTimeout(cp, timeout);
+ // cmsysProcess_SetTimeout(cp, timeout);
int problems = 0;
cmCTest::SetOfStrings::const_iterator file;
- for ( file = files.begin(); file != files.end(); ++file )
- {
+ for (file = files.begin(); file != files.end(); ++file) {
int retVal;
std::string lfname = localprefix;
@@ -840,124 +784,114 @@ bool cmCTestSubmitHandler::SubmitUsingSCP(
argv[1] = lfname.c_str();
std::string rfname = url + "/" + remoteprefix + *file;
argv[2] = rfname.c_str();
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Execute \"" << argv[0]
- << "\" \"" << argv[1] << "\" \""
- << argv[2] << "\"" << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Execute \""
+ << argv[0] << "\" \"" << argv[1] << "\" \"" << argv[2]
+ << "\"" << std::endl,
+ this->Quiet);
*this->LogFile << "Execute \"" << argv[0] << "\" \"" << argv[1] << "\" \""
- << argv[2] << "\"" << std::endl;
+ << argv[2] << "\"" << std::endl;
cmsysProcess_SetCommand(cp, &*argv.begin());
cmsysProcess_Execute(cp);
char* data;
int length;
+ cmProcessOutput processOutput;
+ std::string strdata;
+
+ while (cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR)) {
+ processOutput.DecodeText(data, length, strdata);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ cmCTestLogWrite(strdata.c_str(), strdata.size()),
+ this->Quiet);
+ }
+ processOutput.DecodeText(std::string(), strdata);
+ if (!strdata.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ cmCTestLogWrite(strdata.c_str(), strdata.size()),
+ this->Quiet);
+ }
- while(cmsysProcess_WaitForData(cp, &data, &length, 0))
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- cmCTestLogWrite(data, length));
- }
-
- cmsysProcess_WaitForExit(cp, 0);
+ cmsysProcess_WaitForExit(cp, CM_NULLPTR);
int result = cmsysProcess_GetState(cp);
- if(result == cmsysProcess_State_Exited)
- {
+ if (result == cmsysProcess_State_Exited) {
retVal = cmsysProcess_GetExitValue(cp);
- if ( retVal != 0 )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "\tSCP returned: "
- << retVal << std::endl);
+ if (retVal != 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "\tSCP returned: " << retVal << std::endl,
+ this->Quiet);
*this->LogFile << "\tSCP returned: " << retVal << std::endl;
- problems ++;
- }
+ problems++;
}
- else if(result == cmsysProcess_State_Exception)
- {
+ } else if (result == cmsysProcess_State_Exception) {
retVal = cmsysProcess_GetExitException(cp);
- cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was an exception: "
- << retVal << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "\tThere was an exception: " << retVal << std::endl);
*this->LogFile << "\tThere was an exception: " << retVal << std::endl;
- problems ++;
- }
- else if(result == cmsysProcess_State_Expired)
- {
+ problems++;
+ } else if (result == cmsysProcess_State_Expired) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was a timeout"
- << std::endl);
+ << std::endl);
*this->LogFile << "\tThere was a timeout" << std::endl;
- problems ++;
- }
- else if(result == cmsysProcess_State_Error)
- {
+ problems++;
+ } else if (result == cmsysProcess_State_Error) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "\tError executing SCP: "
- << cmsysProcess_GetErrorString(cp) << std::endl);
+ << cmsysProcess_GetErrorString(cp) << std::endl);
*this->LogFile << "\tError executing SCP: "
- << cmsysProcess_GetErrorString(cp) << std::endl;
- problems ++;
- }
+ << cmsysProcess_GetErrorString(cp) << std::endl;
+ problems++;
}
+ }
cmsysProcess_Delete(cp);
- if ( problems )
- {
- return false;
- }
- return true;
+ return problems == 0;
}
-//----------------------------------------------------------------------------
-bool cmCTestSubmitHandler::SubmitUsingCP(
- const cmStdString& localprefix,
- const std::set<cmStdString>& files,
- const cmStdString& remoteprefix,
- const cmStdString& destination)
+bool cmCTestSubmitHandler::SubmitUsingCP(const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& destination)
{
- if ( !localprefix.size() ||
- !files.size() || !remoteprefix.size() || !destination.size() )
- {
+ if (localprefix.empty() || files.empty() || remoteprefix.empty() ||
+ destination.empty()) {
+ /* clang-format off */
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Missing arguments for submit via cp:\n"
<< "\tlocalprefix: " << localprefix << "\n"
<< "\tNumber of files: " << files.size() << "\n"
<< "\tremoteprefix: " << remoteprefix << "\n"
<< "\tdestination: " << destination << std::endl);
- return 0;
- }
+ /* clang-format on */
+ return false;
+ }
+
cmCTest::SetOfStrings::const_iterator file;
- bool problems = false;
- for ( file = files.begin(); file != files.end(); ++file )
- {
+ for (file = files.begin(); file != files.end(); ++file) {
std::string lfname = localprefix;
cmSystemTools::ConvertToUnixSlashes(lfname);
lfname += "/" + *file;
std::string rfname = destination + "/" + remoteprefix + *file;
- cmSystemTools::CopyFileAlways(lfname.c_str(), rfname.c_str());
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Copy file: "
- << lfname.c_str() << " to "
- << rfname.c_str() << std::endl);
- }
+ cmSystemTools::CopyFileAlways(lfname, rfname);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Copy file: "
+ << lfname << " to " << rfname << std::endl,
+ this->Quiet);
+ }
std::string tagDoneFile = destination + "/" + remoteprefix + "DONE";
- cmSystemTools::Touch(tagDoneFile.c_str(), true);
- if ( problems )
- {
- return false;
- }
+ cmSystemTools::Touch(tagDoneFile, true);
return true;
}
-
-//----------------------------------------------------------------------------
#if defined(CTEST_USE_XMLRPC)
-bool cmCTestSubmitHandler::SubmitUsingXMLRPC(const cmStdString& localprefix,
- const std::set<cmStdString>& files,
- const cmStdString& remoteprefix,
- const cmStdString& url)
+bool cmCTestSubmitHandler::SubmitUsingXMLRPC(
+ const std::string& localprefix, const std::set<std::string>& files,
+ const std::string& remoteprefix, const std::string& url)
{
xmlrpc_env env;
char ctestString[] = "CTest";
std::string ctestVersionString = cmVersion::GetCMakeVersion();
char* ctestVersion = const_cast<char*>(ctestVersionString.c_str());
- cmStdString realURL = url + "/" + remoteprefix + "/Command/";
+ std::string realURL = url + "/" + remoteprefix + "/Command/";
/* Start up our XML-RPC client library. */
xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, ctestString, ctestVersion);
@@ -966,76 +900,72 @@ bool cmCTestSubmitHandler::SubmitUsingXMLRPC(const cmStdString& localprefix,
xmlrpc_env_init(&env);
/* Call the famous server at UserLand. */
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submitting to: "
- << realURL.c_str() << " (" << remoteprefix.c_str() << ")" << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Submitting to: "
+ << realURL << " (" << remoteprefix << ")" << std::endl,
+ this->Quiet);
cmCTest::SetOfStrings::const_iterator file;
- for ( file = files.begin(); file != files.end(); ++file )
- {
- xmlrpc_value *result;
+ for (file = files.begin(); file != files.end(); ++file) {
+ xmlrpc_value* result;
- cmStdString local_file = *file;
- if ( !cmSystemTools::FileExists(local_file.c_str()) )
- {
+ std::string local_file = *file;
+ if (!cmSystemTools::FileExists(local_file.c_str())) {
local_file = localprefix + "/" + *file;
- }
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submit file: "
- << local_file.c_str() << std::endl);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Submit file: " << local_file << std::endl,
+ this->Quiet);
struct stat st;
- if ( ::stat(local_file.c_str(), &st) )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot find file: "
- << local_file.c_str() << std::endl);
+ if (::stat(local_file.c_str(), &st)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Cannot find file: " << local_file << std::endl);
return false;
- }
+ }
// off_t can be bigger than size_t. fread takes size_t.
// make sure the file is not too big.
- if(static_cast<off_t>(static_cast<size_t>(st.st_size)) !=
- static_cast<off_t>(st.st_size))
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, " File too big: "
- << local_file.c_str() << std::endl);
+ if (static_cast<off_t>(static_cast<size_t>(st.st_size)) !=
+ static_cast<off_t>(st.st_size)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, " File too big: " << local_file
+ << std::endl);
return false;
- }
+ }
size_t fileSize = static_cast<size_t>(st.st_size);
- FILE* fp = fopen(local_file.c_str(), "rb");
- if ( !fp )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot open file: "
- << local_file.c_str() << std::endl);
+ FILE* fp = cmsys::SystemTools::Fopen(local_file, "rb");
+ if (!fp) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Cannot open file: " << local_file << std::endl);
return false;
- }
+ }
- unsigned char *fileBuffer = new unsigned char[fileSize];
- if ( fread(fileBuffer, 1, fileSize, fp) != fileSize )
- {
- delete [] fileBuffer;
+ unsigned char* fileBuffer = new unsigned char[fileSize];
+ if (fread(fileBuffer, 1, fileSize, fp) != fileSize) {
+ delete[] fileBuffer;
fclose(fp);
- cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot read file: "
- << local_file.c_str() << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " Cannot read file: " << local_file << std::endl);
return false;
- }
+ }
fclose(fp);
char remoteCommand[] = "Submit.put";
char* pRealURL = const_cast<char*>(realURL.c_str());
- result = xmlrpc_client_call(&env, pRealURL, remoteCommand,
- "(6)", fileBuffer, (xmlrpc_int32)fileSize );
+ result = xmlrpc_client_call(&env, pRealURL, remoteCommand, "(6)",
+ fileBuffer, (xmlrpc_int32)fileSize);
- delete [] fileBuffer;
+ delete[] fileBuffer;
- if ( env.fault_occurred )
- {
+ if (env.fault_occurred) {
cmCTestLog(this->CTest, ERROR_MESSAGE, " Submission problem: "
- << env.fault_string << " (" << env.fault_code << ")" << std::endl);
+ << env.fault_string << " (" << env.fault_code << ")"
+ << std::endl);
xmlrpc_env_clean(&env);
xmlrpc_client_cleanup();
return false;
- }
+ }
/* Dispose of our result value. */
xmlrpc_DECREF(result);
- }
+ }
/* Clean up our error-handling environment. */
xmlrpc_env_clean(&env);
@@ -1045,126 +975,335 @@ bool cmCTestSubmitHandler::SubmitUsingXMLRPC(const cmStdString& localprefix,
return true;
}
#else
-bool cmCTestSubmitHandler::SubmitUsingXMLRPC(cmStdString const&,
- std::set<cmStdString> const&,
- cmStdString const&,
- cmStdString const&)
+bool cmCTestSubmitHandler::SubmitUsingXMLRPC(
+ std::string const& /*unused*/, std::set<std::string> const& /*unused*/,
+ std::string const& /*unused*/, std::string const& /*unused*/)
{
return false;
}
#endif
-//----------------------------------------------------------------------------
+void cmCTestSubmitHandler::ConstructCDashURL(std::string& dropMethod,
+ std::string& url)
+{
+ dropMethod = this->CTest->GetCTestConfiguration("DropMethod");
+ url = dropMethod;
+ url += "://";
+ if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) {
+ url += this->CTest->GetCTestConfiguration("DropSiteUser");
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ this->CTest->GetCTestConfiguration("DropSiteUser").c_str(), this->Quiet);
+ if (!this->CTest->GetCTestConfiguration("DropSitePassword").empty()) {
+ url += ":" + this->CTest->GetCTestConfiguration("DropSitePassword");
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, ":******", this->Quiet);
+ }
+ url += "@";
+ }
+ url += this->CTest->GetCTestConfiguration("DropSite") +
+ this->CTest->GetCTestConfiguration("DropLocation");
+}
+
+int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file,
+ std::string const& typeString)
+{
+ if (file.empty()) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Upload file not specified\n");
+ return -1;
+ }
+ if (!cmSystemTools::FileExists(file)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Upload file not found: '"
+ << file << "'\n");
+ return -1;
+ }
+ cmCTestCurl curl(this->CTest);
+ curl.SetQuiet(this->Quiet);
+ std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions"));
+ std::vector<std::string> args;
+ cmSystemTools::ExpandListArgument(curlopt, args);
+ curl.SetCurlOptions(args);
+ curl.SetTimeOutSeconds(SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
+ curl.SetHttpHeaders(this->HttpHeaders);
+ std::string dropMethod;
+ std::string url;
+ this->ConstructCDashURL(dropMethod, url);
+ std::string::size_type pos = url.find("submit.php?");
+ url = url.substr(0, pos + 10);
+ if (!(dropMethod == "http" || dropMethod == "https")) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Only http and https are supported for CDASH_UPLOAD\n");
+ return -1;
+ }
+ bool internalTest = cmSystemTools::IsOn(this->GetOption("InternalTest"));
+
+ // Get RETRY_COUNT and RETRY_DELAY values if they were set.
+ std::string retryDelayString = this->GetOption("RetryDelay") == CM_NULLPTR
+ ? ""
+ : this->GetOption("RetryDelay");
+ std::string retryCountString = this->GetOption("RetryCount") == CM_NULLPTR
+ ? ""
+ : this->GetOption("RetryCount");
+ unsigned long retryDelay = 0;
+ if (retryDelayString != "") {
+ if (!cmSystemTools::StringToULong(retryDelayString.c_str(), &retryDelay)) {
+ cmCTestLog(this->CTest, WARNING, "Invalid value for 'RETRY_DELAY' : "
+ << retryDelayString << std::endl);
+ }
+ }
+ unsigned long retryCount = 0;
+ if (retryCountString != "") {
+ if (!cmSystemTools::StringToULong(retryCountString.c_str(), &retryCount)) {
+ cmCTestLog(this->CTest, WARNING, "Invalid value for 'RETRY_DELAY' : "
+ << retryCountString << std::endl);
+ }
+ }
+
+ char md5sum[33];
+ md5sum[32] = 0;
+ cmSystemTools::ComputeFileMD5(file, md5sum);
+ // 1. request the buildid and check to see if the file
+ // has already been uploaded
+ // TODO I added support for subproject. You would need to add
+ // a "&subproject=subprojectname" to the first POST.
+ cmCTestScriptHandler* ch =
+ static_cast<cmCTestScriptHandler*>(this->CTest->GetHandler("script"));
+ cmake* cm = ch->GetCMake();
+ const char* subproject = cm->GetState()->GetGlobalProperty("SubProject");
+ // TODO: Encode values for a URL instead of trusting caller.
+ std::ostringstream str;
+ str << "project="
+ << curl.Escape(this->CTest->GetCTestConfiguration("ProjectName")) << "&";
+ if (subproject) {
+ str << "subproject=" << curl.Escape(subproject) << "&";
+ }
+ str << "stamp=" << curl.Escape(this->CTest->GetCurrentTag()) << "-"
+ << curl.Escape(this->CTest->GetTestModelString()) << "&"
+ << "model=" << curl.Escape(this->CTest->GetTestModelString()) << "&"
+ << "build="
+ << curl.Escape(this->CTest->GetCTestConfiguration("BuildName")) << "&"
+ << "site=" << curl.Escape(this->CTest->GetCTestConfiguration("Site"))
+ << "&"
+ << "track=" << curl.Escape(this->CTest->GetTestModelString()) << "&"
+ << "starttime=" << (int)cmSystemTools::GetTime() << "&"
+ << "endtime=" << (int)cmSystemTools::GetTime() << "&"
+ << "datafilesmd5[0]=" << md5sum << "&"
+ << "type=" << curl.Escape(typeString);
+ std::string fields = str.str();
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "fields: " << fields << "\nurl:" << url
+ << "\nfile: " << file << "\n",
+ this->Quiet);
+ std::string response;
+
+ bool requestSucceeded = curl.HttpRequest(url, fields, response);
+ if (!internalTest && !requestSucceeded) {
+ // If request failed, wait and retry.
+ for (unsigned long i = 0; i < retryCount; i++) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Request failed, waiting " << retryDelay
+ << " seconds...\n",
+ this->Quiet);
+
+ double stop = cmSystemTools::GetTime() + static_cast<double>(retryDelay);
+ while (cmSystemTools::GetTime() < stop) {
+ cmSystemTools::Delay(100);
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Retry request: Attempt "
+ << (i + 1) << " of " << retryCount << std::endl,
+ this->Quiet);
+
+ requestSucceeded = curl.HttpRequest(url, fields, response);
+ if (requestSucceeded) {
+ break;
+ }
+ }
+ }
+ if (!internalTest && !requestSucceeded) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Error in HttpRequest\n"
+ << response);
+ return -1;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Request upload response: [" << response << "]\n",
+ this->Quiet);
+ Json::Value json;
+ Json::Reader reader;
+ if (!internalTest && !reader.parse(response, json)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "error parsing json string ["
+ << response << "]\n"
+ << reader.getFormattedErrorMessages() << "\n");
+ return -1;
+ }
+ if (!internalTest && json["status"].asInt() != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Bad status returned from CDash: " << json["status"].asInt());
+ return -1;
+ }
+ if (!internalTest) {
+ if (json["datafilesmd5"].isArray()) {
+ int datares = json["datafilesmd5"][0].asInt();
+ if (datares == 1) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "File already exists on CDash, skip upload "
+ << file << "\n",
+ this->Quiet);
+ return 0;
+ }
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "bad datafilesmd5 value in response " << response << "\n");
+ return -1;
+ }
+ }
+
+ std::string upload_as = cmSystemTools::GetFilenameName(file);
+ std::ostringstream fstr;
+ fstr << "type=" << curl.Escape(typeString) << "&"
+ << "md5=" << md5sum << "&"
+ << "filename=" << curl.Escape(upload_as) << "&"
+ << "buildid=" << json["buildid"].asString();
+
+ bool uploadSucceeded = false;
+ if (!internalTest) {
+ uploadSucceeded = curl.UploadFile(file, url, fstr.str(), response);
+ }
+
+ if (!uploadSucceeded) {
+ // If upload failed, wait and retry.
+ for (unsigned long i = 0; i < retryCount; i++) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Upload failed, waiting " << retryDelay
+ << " seconds...\n",
+ this->Quiet);
+
+ double stop = cmSystemTools::GetTime() + static_cast<double>(retryDelay);
+ while (cmSystemTools::GetTime() < stop) {
+ cmSystemTools::Delay(100);
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Retry upload: Attempt "
+ << (i + 1) << " of " << retryCount << std::endl,
+ this->Quiet);
+
+ if (!internalTest) {
+ uploadSucceeded = curl.UploadFile(file, url, fstr.str(), response);
+ }
+ if (uploadSucceeded) {
+ break;
+ }
+ }
+ }
+
+ if (!uploadSucceeded) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "error uploading to CDash. "
+ << file << " " << url << " " << fstr.str());
+ return -1;
+ }
+ if (!reader.parse(response, json)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "error parsing json string ["
+ << response << "]\n"
+ << reader.getFormattedErrorMessages() << "\n");
+ return -1;
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Upload file response: [" << response << "]\n",
+ this->Quiet);
+ return 0;
+}
+
int cmCTestSubmitHandler::ProcessHandler()
{
+ const char* cdashUploadFile = this->GetOption("CDashUploadFile");
+ const char* cdashUploadType = this->GetOption("CDashUploadType");
+ if (cdashUploadFile && cdashUploadType) {
+ return this->HandleCDashUploadFile(cdashUploadFile, cdashUploadType);
+ }
std::string iscdash = this->CTest->GetCTestConfiguration("IsCDash");
// cdash does not need to trigger so just return true
- if(iscdash.size())
- {
+ if (!iscdash.empty()) {
this->CDash = true;
- }
+ }
- const std::string &buildDirectory
- = this->CTest->GetCTestConfiguration("BuildDirectory");
- if ( buildDirectory.size() == 0 )
- {
+ const std::string& buildDirectory =
+ this->CTest->GetCTestConfiguration("BuildDirectory");
+ if (buildDirectory.empty()) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot find BuildDirectory key in the DartConfiguration.tcl"
- << std::endl);
+ "Cannot find BuildDirectory key in the DartConfiguration.tcl"
+ << std::endl);
return -1;
- }
+ }
- if ( getenv("HTTP_PROXY") )
- {
+ if (getenv("HTTP_PROXY")) {
this->HTTPProxyType = 1;
this->HTTPProxy = getenv("HTTP_PROXY");
- if ( getenv("HTTP_PROXY_PORT") )
- {
+ if (getenv("HTTP_PROXY_PORT")) {
this->HTTPProxy += ":";
this->HTTPProxy += getenv("HTTP_PROXY_PORT");
- }
- if ( getenv("HTTP_PROXY_TYPE") )
- {
- cmStdString type = getenv("HTTP_PROXY_TYPE");
+ }
+ if (getenv("HTTP_PROXY_TYPE")) {
+ std::string type = getenv("HTTP_PROXY_TYPE");
// HTTP/SOCKS4/SOCKS5
- if ( type == "HTTP" )
- {
+ if (type == "HTTP") {
this->HTTPProxyType = 1;
- }
- else if ( type == "SOCKS4" )
- {
+ } else if (type == "SOCKS4") {
this->HTTPProxyType = 2;
- }
- else if ( type == "SOCKS5" )
- {
+ } else if (type == "SOCKS5") {
this->HTTPProxyType = 3;
- }
}
- if ( getenv("HTTP_PROXY_USER") )
- {
+ }
+ if (getenv("HTTP_PROXY_USER")) {
this->HTTPProxyAuth = getenv("HTTP_PROXY_USER");
- }
- if ( getenv("HTTP_PROXY_PASSWD") )
- {
+ }
+ if (getenv("HTTP_PROXY_PASSWD")) {
this->HTTPProxyAuth += ":";
this->HTTPProxyAuth += getenv("HTTP_PROXY_PASSWD");
- }
}
+ }
- if ( getenv("FTP_PROXY") )
- {
+ if (getenv("FTP_PROXY")) {
this->FTPProxyType = 1;
this->FTPProxy = getenv("FTP_PROXY");
- if ( getenv("FTP_PROXY_PORT") )
- {
+ if (getenv("FTP_PROXY_PORT")) {
this->FTPProxy += ":";
this->FTPProxy += getenv("FTP_PROXY_PORT");
- }
- if ( getenv("FTP_PROXY_TYPE") )
- {
- cmStdString type = getenv("FTP_PROXY_TYPE");
+ }
+ if (getenv("FTP_PROXY_TYPE")) {
+ std::string type = getenv("FTP_PROXY_TYPE");
// HTTP/SOCKS4/SOCKS5
- if ( type == "HTTP" )
- {
+ if (type == "HTTP") {
this->FTPProxyType = 1;
- }
- else if ( type == "SOCKS4" )
- {
+ } else if (type == "SOCKS4") {
this->FTPProxyType = 2;
- }
- else if ( type == "SOCKS5" )
- {
+ } else if (type == "SOCKS5") {
this->FTPProxyType = 3;
- }
}
}
-
- if ( this->HTTPProxy.size() > 0 )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Use HTTP Proxy: "
- << this->HTTPProxy << std::endl);
- }
- if ( this->FTPProxy.size() > 0 )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Use FTP Proxy: "
- << this->FTPProxy << std::endl);
- }
+ }
+
+ if (!this->HTTPProxy.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Use HTTP Proxy: " << this->HTTPProxy << std::endl,
+ this->Quiet);
+ }
+ if (!this->FTPProxy.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Use FTP Proxy: " << this->FTPProxy << std::endl,
+ this->Quiet);
+ }
cmGeneratedFileStream ofs;
this->StartLogFile("Submit", ofs);
cmCTest::SetOfStrings files;
std::string prefix = this->GetSubmitResultsPrefix();
- if (!this->Files.empty())
- {
+ if (!this->Files.empty()) {
// Submit the explicitly selected files:
//
- cmCTest::SetOfStrings::const_iterator it;
- for (it = this->Files.begin(); it != this->Files.end(); ++it)
- {
- files.insert(*it);
- }
- }
+ files.insert(this->Files.begin(), this->Files.end());
+ }
// Add to the list of files to submit from any selected, existing parts:
//
@@ -1176,333 +1315,292 @@ int cmCTestSubmitHandler::ProcessHandler()
this->CTest->AddIfExists(cmCTest::PartConfigure, "Configure.xml");
this->CTest->AddIfExists(cmCTest::PartBuild, "Build.xml");
this->CTest->AddIfExists(cmCTest::PartTest, "Test.xml");
- if(this->CTest->AddIfExists(cmCTest::PartCoverage, "Coverage.xml"))
- {
- cmCTest::VectorOfStrings gfiles;
- std::string gpath
- = buildDirectory + "/Testing/" + this->CTest->GetCurrentTag();
+ if (this->CTest->AddIfExists(cmCTest::PartCoverage, "Coverage.xml")) {
+ std::vector<std::string> gfiles;
+ std::string gpath =
+ buildDirectory + "/Testing/" + this->CTest->GetCurrentTag();
std::string::size_type glen = gpath.size() + 1;
gpath = gpath + "/CoverageLog*";
- cmCTestLog(this->CTest, DEBUG, "Globbing for: " << gpath.c_str()
- << std::endl);
- if ( cmSystemTools::SimpleGlob(gpath, gfiles, 1) )
- {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Globbing for: " << gpath << std::endl, this->Quiet);
+ if (cmSystemTools::SimpleGlob(gpath, gfiles, 1)) {
size_t cc;
- for ( cc = 0; cc < gfiles.size(); cc ++ )
- {
+ for (cc = 0; cc < gfiles.size(); cc++) {
gfiles[cc] = gfiles[cc].substr(glen);
- cmCTestLog(this->CTest, DEBUG, "Glob file: " << gfiles[cc].c_str()
- << std::endl);
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Glob file: " << gfiles[cc] << std::endl,
+ this->Quiet);
this->CTest->AddSubmitFile(cmCTest::PartCoverage, gfiles[cc].c_str());
- }
}
- else
- {
+ } else {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Problem globbing" << std::endl);
- }
}
+ }
this->CTest->AddIfExists(cmCTest::PartMemCheck, "DynamicAnalysis.xml");
this->CTest->AddIfExists(cmCTest::PartMemCheck, "Purify.xml");
this->CTest->AddIfExists(cmCTest::PartNotes, "Notes.xml");
this->CTest->AddIfExists(cmCTest::PartUpload, "Upload.xml");
// Query parts for files to submit.
- for(cmCTest::Part p = cmCTest::PartStart;
- p != cmCTest::PartCount; p = cmCTest::Part(p+1))
- {
+ for (cmCTest::Part p = cmCTest::PartStart; p != cmCTest::PartCount;
+ p = cmCTest::Part(p + 1)) {
// Skip parts we are not submitting.
- if(!this->SubmitPart[p])
- {
+ if (!this->SubmitPart[p]) {
continue;
- }
+ }
// Submit files from this part.
std::vector<std::string> const& pfiles = this->CTest->GetSubmitFiles(p);
- for(std::vector<std::string>::const_iterator pi = pfiles.begin();
- pi != pfiles.end(); ++pi)
- {
- files.insert(*pi);
- }
- }
+ files.insert(pfiles.begin(), pfiles.end());
+ }
- if ( ofs )
- {
+ if (ofs) {
ofs << "Upload files:" << std::endl;
int cnt = 0;
cmCTest::SetOfStrings::iterator it;
- for ( it = files.begin(); it != files.end(); ++ it )
- {
- ofs << cnt << "\t" << it->c_str() << std::endl;
- cnt ++;
- }
+ for (it = files.begin(); it != files.end(); ++it) {
+ ofs << cnt << "\t" << *it << std::endl;
+ cnt++;
}
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "Submit files (using "
- << this->CTest->GetCTestConfiguration("DropMethod") << ")"
- << std::endl);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "Submit files (using "
+ << this->CTest->GetCTestConfiguration("DropMethod")
+ << ")" << std::endl,
+ this->Quiet);
const char* specificTrack = this->CTest->GetSpecificTrack();
- if ( specificTrack )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Send to track: "
- << specificTrack << std::endl);
- }
+ if (specificTrack) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Send to track: " << specificTrack << std::endl,
+ this->Quiet);
+ }
this->SetLogFile(&ofs);
- cmStdString dropMethod(this->CTest->GetCTestConfiguration("DropMethod"));
+ std::string dropMethod(this->CTest->GetCTestConfiguration("DropMethod"));
- if ( dropMethod == "" || dropMethod == "ftp" )
- {
+ if (dropMethod == "" || dropMethod == "ftp") {
ofs << "Using drop method: FTP" << std::endl;
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using FTP submit method"
- << std::endl
- << " Drop site: ftp://");
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Using FTP submit method" << std::endl
+ << " Drop site: ftp://",
+ this->Quiet);
std::string url = "ftp://";
url += cmCTest::MakeURLSafe(
- this->CTest->GetCTestConfiguration("DropSiteUser")) + ":" +
- cmCTest::MakeURLSafe(this->CTest->GetCTestConfiguration(
- "DropSitePassword")) + "@" +
- this->CTest->GetCTestConfiguration("DropSite") +
- cmCTest::MakeURLSafe(
- this->CTest->GetCTestConfiguration("DropLocation"));
- if ( this->CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- this->CTest->GetCTestConfiguration(
- "DropSiteUser").c_str());
- if ( this->CTest->GetCTestConfiguration("DropSitePassword").size() > 0 )
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, ":******");
- }
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "@");
+ this->CTest->GetCTestConfiguration("DropSiteUser")) +
+ ":" + cmCTest::MakeURLSafe(
+ this->CTest->GetCTestConfiguration("DropSitePassword")) +
+ "@" + this->CTest->GetCTestConfiguration("DropSite") +
+ cmCTest::MakeURLSafe(this->CTest->GetCTestConfiguration("DropLocation"));
+ if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ this->CTest->GetCTestConfiguration("DropSiteUser").c_str(),
+ this->Quiet);
+ if (!this->CTest->GetCTestConfiguration("DropSitePassword").empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, ":******",
+ this->Quiet);
}
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- this->CTest->GetCTestConfiguration("DropSite")
- << this->CTest->GetCTestConfiguration("DropLocation") << std::endl);
- if ( !this->SubmitUsingFTP(buildDirectory + "/Testing/"
- + this->CTest->GetCurrentTag(),
- files, prefix, url) )
- {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "@", this->Quiet);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ this->CTest->GetCTestConfiguration("DropSite")
+ << this->CTest->GetCTestConfiguration("DropLocation")
+ << std::endl,
+ this->Quiet);
+ if (!this->SubmitUsingFTP(buildDirectory + "/Testing/" +
+ this->CTest->GetCurrentTag(),
+ files, prefix, url)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- " Problems when submitting via FTP"
- << std::endl);
+ " Problems when submitting via FTP" << std::endl);
ofs << " Problems when submitting via FTP" << std::endl;
return -1;
- }
- if(!this->CDash)
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using HTTP trigger method"
- << std::endl
- << " Trigger site: "
- << this->CTest->GetCTestConfiguration("TriggerSite")
- << std::endl);
- if ( !this->
- TriggerUsingHTTP(files, prefix,
- this->CTest->GetCTestConfiguration("TriggerSite")))
- {
+ }
+ if (!this->CDash) {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT, " Using HTTP trigger method"
+ << std::endl
+ << " Trigger site: "
+ << this->CTest->GetCTestConfiguration("TriggerSite") << std::endl,
+ this->Quiet);
+ if (!this->TriggerUsingHTTP(
+ files, prefix,
+ this->CTest->GetCTestConfiguration("TriggerSite"))) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Problems when triggering via HTTP" << std::endl);
ofs << " Problems when triggering via HTTP" << std::endl;
return -1;
- }
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful"
- << std::endl);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Submission successful" << std::endl, this->Quiet);
ofs << " Submission successful" << std::endl;
return 0;
- }
}
- else if ( dropMethod == "http" || dropMethod == "https" )
- {
+ } else if (dropMethod == "http" || dropMethod == "https") {
std::string url = dropMethod;
url += "://";
ofs << "Using drop method: " << dropMethod << std::endl;
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using HTTP submit method"
- << std::endl
- << " Drop site:" << url);
- if ( this->CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
- {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Using HTTP submit method" << std::endl
+ << " Drop site:" << url,
+ this->Quiet);
+ if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) {
url += this->CTest->GetCTestConfiguration("DropSiteUser");
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- this->CTest->GetCTestConfiguration("DropSiteUser").c_str());
- if ( this->CTest->GetCTestConfiguration("DropSitePassword").size() > 0 )
- {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT,
+ this->CTest->GetCTestConfiguration("DropSiteUser").c_str(),
+ this->Quiet);
+ if (!this->CTest->GetCTestConfiguration("DropSitePassword").empty()) {
url += ":" + this->CTest->GetCTestConfiguration("DropSitePassword");
- cmCTestLog(this->CTest, HANDLER_OUTPUT, ":******");
- }
- url += "@";
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "@");
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, ":******",
+ this->Quiet);
}
+ url += "@";
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "@", this->Quiet);
+ }
url += this->CTest->GetCTestConfiguration("DropSite") +
this->CTest->GetCTestConfiguration("DropLocation");
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- this->CTest->GetCTestConfiguration("DropSite")
- << this->CTest->GetCTestConfiguration("DropLocation") << std::endl);
- if ( !this->SubmitUsingHTTP(buildDirectory + "/Testing/" +
- this->CTest->GetCurrentTag(), files, prefix, url) )
- {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ this->CTest->GetCTestConfiguration("DropSite")
+ << this->CTest->GetCTestConfiguration("DropLocation")
+ << std::endl,
+ this->Quiet);
+ if (!this->SubmitUsingHTTP(buildDirectory + "/Testing/" +
+ this->CTest->GetCurrentTag(),
+ files, prefix, url)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- " Problems when submitting via HTTP" << std::endl);
+ " Problems when submitting via HTTP" << std::endl);
ofs << " Problems when submitting via HTTP" << std::endl;
return -1;
- }
- if(!this->CDash)
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using HTTP trigger method"
- << std::endl
- << " Trigger site: "
- << this->CTest->GetCTestConfiguration("TriggerSite")
- << std::endl);
- if ( !this->
- TriggerUsingHTTP(files, prefix,
- this->CTest->GetCTestConfiguration("TriggerSite")))
- {
+ }
+ if (!this->CDash) {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT, " Using HTTP trigger method"
+ << std::endl
+ << " Trigger site: "
+ << this->CTest->GetCTestConfiguration("TriggerSite") << std::endl,
+ this->Quiet);
+ if (!this->TriggerUsingHTTP(
+ files, prefix,
+ this->CTest->GetCTestConfiguration("TriggerSite"))) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Problems when triggering via HTTP" << std::endl);
ofs << " Problems when triggering via HTTP" << std::endl;
return -1;
- }
}
- if(this->HasErrors)
- {
+ }
+ if (this->HasErrors) {
cmCTestLog(this->CTest, HANDLER_OUTPUT, " Errors occurred during "
- "submission." << std::endl);
+ "submission."
+ << std::endl);
ofs << " Errors occurred during submission. " << std::endl;
- }
- else
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful" <<
- (this->HasWarnings ? ", with warnings." : "") << std::endl);
- ofs << " Submission successful" <<
- (this->HasWarnings ? ", with warnings." : "") << std::endl;
- }
+ } else {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT, " Submission successful"
+ << (this->HasWarnings ? ", with warnings." : "") << std::endl,
+ this->Quiet);
+ ofs << " Submission successful"
+ << (this->HasWarnings ? ", with warnings." : "") << std::endl;
+ }
return 0;
- }
- else if ( dropMethod == "xmlrpc" )
- {
+ } else if (dropMethod == "xmlrpc") {
#if defined(CTEST_USE_XMLRPC)
ofs << "Using drop method: XML-RPC" << std::endl;
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Using XML-RPC submit method"
- << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Using XML-RPC submit method" << std::endl,
+ this->Quiet);
std::string url = this->CTest->GetCTestConfiguration("DropSite");
prefix = this->CTest->GetCTestConfiguration("DropLocation");
- if ( !this->SubmitUsingXMLRPC(buildDirectory + "/Testing/" +
- this->CTest->GetCurrentTag(), files, prefix, url) )
- {
+ if (!this->SubmitUsingXMLRPC(buildDirectory + "/Testing/" +
+ this->CTest->GetCurrentTag(),
+ files, prefix, url)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- " Problems when submitting via XML-RPC" << std::endl);
+ " Problems when submitting via XML-RPC" << std::endl);
ofs << " Problems when submitting via XML-RPC" << std::endl;
return -1;
- }
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful"
- << std::endl);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Submission successful" << std::endl, this->Quiet);
ofs << " Submission successful" << std::endl;
return 0;
#else
cmCTestLog(this->CTest, ERROR_MESSAGE,
" Submission method \"xmlrpc\" not compiled into CTest!"
- << std::endl);
+ << std::endl);
return -1;
#endif
- }
- else if ( dropMethod == "scp" )
- {
+ } else if (dropMethod == "scp") {
std::string url;
- std::string oldWorkingDirectory;
- if ( this->CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
- {
+ if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) {
url += this->CTest->GetCTestConfiguration("DropSiteUser") + "@";
- }
+ }
url += this->CTest->GetCTestConfiguration("DropSite") + ":" +
this->CTest->GetCTestConfiguration("DropLocation");
// change to the build directory so that we can uses a relative path
// on windows since scp dosn't support "c:" a drive in the path
- oldWorkingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
- cmSystemTools::ChangeDirectory(buildDirectory.c_str());
-
- if ( !this->SubmitUsingSCP(
- this->CTest->GetCTestConfiguration("ScpCommand"),
- "Testing/"+this->CTest->GetCurrentTag(), files, prefix, url) )
- {
- cmSystemTools::ChangeDirectory(oldWorkingDirectory.c_str());
+ cmWorkingDirectory workdir(buildDirectory);
+
+ if (!this->SubmitUsingSCP(this->CTest->GetCTestConfiguration("ScpCommand"),
+ "Testing/" + this->CTest->GetCurrentTag(), files,
+ prefix, url)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- " Problems when submitting via SCP"
- << std::endl);
+ " Problems when submitting via SCP" << std::endl);
ofs << " Problems when submitting via SCP" << std::endl;
return -1;
- }
- cmSystemTools::ChangeDirectory(oldWorkingDirectory.c_str());
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful"
- << std::endl);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Submission successful" << std::endl, this->Quiet);
ofs << " Submission successful" << std::endl;
return 0;
- }
- else if ( dropMethod == "cp" )
- {
- std::string location
- = this->CTest->GetCTestConfiguration("DropLocation");
-
+ } else if (dropMethod == "cp") {
+ std::string location = this->CTest->GetCTestConfiguration("DropLocation");
// change to the build directory so that we can uses a relative path
// on windows since scp dosn't support "c:" a drive in the path
- std::string
- oldWorkingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
- cmSystemTools::ChangeDirectory(buildDirectory.c_str());
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Change directory: "
- << buildDirectory.c_str() << std::endl);
-
- if ( !this->SubmitUsingCP(
- "Testing/"+this->CTest->GetCurrentTag(),
- files,
- prefix,
- location) )
- {
- cmSystemTools::ChangeDirectory(oldWorkingDirectory.c_str());
+ cmWorkingDirectory workdir(buildDirectory);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Change directory: " << buildDirectory << std::endl,
+ this->Quiet);
+
+ if (!this->SubmitUsingCP("Testing/" + this->CTest->GetCurrentTag(), files,
+ prefix, location)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- " Problems when submitting via CP"
- << std::endl);
+ " Problems when submitting via CP" << std::endl);
ofs << " Problems when submitting via cp" << std::endl;
return -1;
- }
- cmSystemTools::ChangeDirectory(oldWorkingDirectory.c_str());
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Submission successful"
- << std::endl);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Submission successful" << std::endl, this->Quiet);
ofs << " Submission successful" << std::endl;
return 0;
- }
+ }
cmCTestLog(this->CTest, ERROR_MESSAGE, " Unknown submission method: \""
- << dropMethod << "\"" << std::endl);
+ << dropMethod << "\"" << std::endl);
return -1;
}
-//----------------------------------------------------------------------------
std::string cmCTestSubmitHandler::GetSubmitResultsPrefix()
{
- std::string name = this->CTest->GetCTestConfiguration("Site") +
- "___" + this->CTest->GetCTestConfiguration("BuildName") +
- "___" + this->CTest->GetCurrentTag() + "-" +
+ std::string buildname =
+ cmCTest::SafeBuildIdField(this->CTest->GetCTestConfiguration("BuildName"));
+ std::string name = this->CTest->GetCTestConfiguration("Site") + "___" +
+ buildname + "___" + this->CTest->GetCurrentTag() + "-" +
this->CTest->GetTestModelString() + "___XML___";
return name;
}
-//----------------------------------------------------------------------------
void cmCTestSubmitHandler::SelectParts(std::set<cmCTest::Part> const& parts)
{
// Check whether each part is selected.
- for(cmCTest::Part p = cmCTest::PartStart;
- p != cmCTest::PartCount; p = cmCTest::Part(p+1))
- {
+ for (cmCTest::Part p = cmCTest::PartStart; p != cmCTest::PartCount;
+ p = cmCTest::Part(p + 1)) {
this->SubmitPart[p] =
(std::set<cmCTest::Part>::const_iterator(parts.find(p)) != parts.end());
- }
+ }
}
-//----------------------------------------------------------------------------
void cmCTestSubmitHandler::SelectFiles(cmCTest::SetOfStrings const& files)
{
- cmCTest::SetOfStrings::const_iterator it;
- for (it = files.begin(); it != files.end(); ++it)
- {
- this->Files.insert(*it);
- }
+ this->Files.insert(files.begin(), files.end());
}
diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h
index 14eac80b5..2923f4f3d 100644
--- a/Source/CTest/cmCTestSubmitHandler.h
+++ b/Source/CTest/cmCTestSubmitHandler.h
@@ -1,19 +1,18 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestSubmitHandler_h
#define cmCTestSubmitHandler_h
+#include "cmConfigure.h"
+
+#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
+#include <iosfwd>
+#include <set>
+#include <string>
+#include <vector>
+
/** \class cmCTestSubmitHandler
* \brief Helper class for CTest
*
@@ -23,17 +22,17 @@
class cmCTestSubmitHandler : public cmCTestGenericHandler
{
public:
- cmTypeMacro(cmCTestSubmitHandler, cmCTestGenericHandler);
+ typedef cmCTestGenericHandler Superclass;
cmCTestSubmitHandler();
- ~cmCTestSubmitHandler() { this->LogFile = 0; }
+ ~cmCTestSubmitHandler() CM_OVERRIDE { this->LogFile = CM_NULLPTR; }
/*
* The main entry point for this class
*/
- int ProcessHandler();
+ int ProcessHandler() CM_OVERRIDE;
- void Initialize();
+ void Initialize() CM_OVERRIDE;
/** Specify a set of parts (by name) to submit. */
void SelectParts(std::set<cmCTest::Part> const& parts);
@@ -41,39 +40,46 @@ public:
/** Specify a set of files to submit. */
void SelectFiles(cmCTest::SetOfStrings const& files);
+ // handle the cdash file upload protocol
+ int HandleCDashUploadFile(std::string const& file, std::string const& type);
+
+ void SetHttpHeaders(std::vector<std::string> const& v)
+ {
+ this->HttpHeaders = v;
+ }
+
+ void ConstructCDashURL(std::string& dropMethod, std::string& url);
+
private:
void SetLogFile(std::ostream* ost) { this->LogFile = ost; }
/**
* Submit file using various ways
*/
- bool SubmitUsingFTP(const cmStdString& localprefix,
- const std::set<cmStdString>& files,
- const cmStdString& remoteprefix,
- const cmStdString& url);
- bool SubmitUsingHTTP(const cmStdString& localprefix,
- const std::set<cmStdString>& files,
- const cmStdString& remoteprefix,
- const cmStdString& url);
- bool SubmitUsingSCP(const cmStdString& scp_command,
- const cmStdString& localprefix,
- const std::set<cmStdString>& files,
- const cmStdString& remoteprefix,
- const cmStdString& url);
-
- bool SubmitUsingCP( const cmStdString& localprefix,
- const std::set<cmStdString>& files,
- const cmStdString& remoteprefix,
- const cmStdString& url);
-
- bool TriggerUsingHTTP(const std::set<cmStdString>& files,
- const cmStdString& remoteprefix,
- const cmStdString& url);
-
- bool SubmitUsingXMLRPC(const cmStdString& localprefix,
- const std::set<cmStdString>& files,
- const cmStdString& remoteprefix,
- const cmStdString& url);
+ bool SubmitUsingFTP(const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix, const std::string& url);
+ bool SubmitUsingHTTP(const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url);
+ bool SubmitUsingSCP(const std::string& scp_command,
+ const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix, const std::string& url);
+
+ bool SubmitUsingCP(const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix, const std::string& url);
+
+ bool TriggerUsingHTTP(const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url);
+
+ bool SubmitUsingXMLRPC(const std::string& localprefix,
+ const std::set<std::string>& files,
+ const std::string& remoteprefix,
+ const std::string& url);
typedef std::vector<char> cmCTestSubmitHandlerVectorOfChar;
@@ -81,18 +87,20 @@ private:
std::string GetSubmitResultsPrefix();
- class ResponseParser;
- cmStdString HTTPProxy;
- int HTTPProxyType;
- cmStdString HTTPProxyAuth;
- cmStdString FTPProxy;
- int FTPProxyType;
+ class ResponseParser;
+
+ std::string HTTPProxy;
+ int HTTPProxyType;
+ std::string HTTPProxyAuth;
+ std::string FTPProxy;
+ int FTPProxyType;
std::ostream* LogFile;
bool SubmitPart[cmCTest::PartCount];
bool CDash;
bool HasWarnings;
bool HasErrors;
cmCTest::SetOfStrings Files;
+ std::vector<std::string> HttpHeaders;
};
#endif
diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx
index 231f035fb..075b1403a 100644
--- a/Source/CTest/cmCTestTestCommand.cxx
+++ b/Source/CTest/cmCTestTestCommand.cxx
@@ -1,18 +1,15 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestTestCommand.h"
#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+#include <sstream>
+#include <stdlib.h>
+#include <vector>
cmCTestTestCommand::cmCTestTestCommand()
{
@@ -23,10 +20,14 @@ cmCTestTestCommand::cmCTestTestCommand()
this->Arguments[ctt_INCLUDE] = "INCLUDE";
this->Arguments[ctt_EXCLUDE_LABEL] = "EXCLUDE_LABEL";
this->Arguments[ctt_INCLUDE_LABEL] = "INCLUDE_LABEL";
+ this->Arguments[ctt_EXCLUDE_FIXTURE] = "EXCLUDE_FIXTURE";
+ this->Arguments[ctt_EXCLUDE_FIXTURE_SETUP] = "EXCLUDE_FIXTURE_SETUP";
+ this->Arguments[ctt_EXCLUDE_FIXTURE_CLEANUP] = "EXCLUDE_FIXTURE_CLEANUP";
this->Arguments[ctt_PARALLEL_LEVEL] = "PARALLEL_LEVEL";
this->Arguments[ctt_SCHEDULE_RANDOM] = "SCHEDULE_RANDOM";
this->Arguments[ctt_STOP_TIME] = "STOP_TIME";
- this->Arguments[ctt_LAST] = 0;
+ this->Arguments[ctt_TEST_LOAD] = "TEST_LOAD";
+ this->Arguments[ctt_LAST] = CM_NULLPTR;
this->Last = ctt_LAST;
}
@@ -35,74 +36,95 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
const char* ctestTimeout =
this->Makefile->GetDefinition("CTEST_TEST_TIMEOUT");
- double timeout = this->CTest->GetTimeOut();
- if ( ctestTimeout )
- {
+ double timeout;
+ if (ctestTimeout) {
timeout = atof(ctestTimeout);
- }
- else
- {
- if ( timeout <= 0 )
- {
+ } else {
+ timeout = this->CTest->GetTimeOut();
+ if (timeout <= 0) {
// By default use timeout of 10 minutes
timeout = 600;
- }
}
+ }
this->CTest->SetTimeOut(timeout);
cmCTestGenericHandler* handler = this->InitializeActualHandler();
- if ( this->Values[ctt_START] || this->Values[ctt_END] ||
- this->Values[ctt_STRIDE] )
- {
- cmOStringStream testsToRunString;
- if ( this->Values[ctt_START] )
- {
+ if (this->Values[ctt_START] || this->Values[ctt_END] ||
+ this->Values[ctt_STRIDE]) {
+ std::ostringstream testsToRunString;
+ if (this->Values[ctt_START]) {
testsToRunString << this->Values[ctt_START];
- }
+ }
testsToRunString << ",";
- if ( this->Values[ctt_END] )
- {
+ if (this->Values[ctt_END]) {
testsToRunString << this->Values[ctt_END];
- }
+ }
testsToRunString << ",";
- if ( this->Values[ctt_STRIDE] )
- {
+ if (this->Values[ctt_STRIDE]) {
testsToRunString << this->Values[ctt_STRIDE];
- }
- handler->SetOption("TestsToRunInformation",
- testsToRunString.str().c_str());
}
- if(this->Values[ctt_EXCLUDE])
- {
+ handler->SetOption("TestsToRunInformation",
+ testsToRunString.str().c_str());
+ }
+ if (this->Values[ctt_EXCLUDE]) {
handler->SetOption("ExcludeRegularExpression", this->Values[ctt_EXCLUDE]);
- }
- if(this->Values[ctt_INCLUDE])
- {
+ }
+ if (this->Values[ctt_INCLUDE]) {
handler->SetOption("IncludeRegularExpression", this->Values[ctt_INCLUDE]);
- }
- if(this->Values[ctt_EXCLUDE_LABEL])
- {
+ }
+ if (this->Values[ctt_EXCLUDE_LABEL]) {
handler->SetOption("ExcludeLabelRegularExpression",
this->Values[ctt_EXCLUDE_LABEL]);
- }
- if(this->Values[ctt_INCLUDE_LABEL])
- {
+ }
+ if (this->Values[ctt_INCLUDE_LABEL]) {
handler->SetOption("LabelRegularExpression",
this->Values[ctt_INCLUDE_LABEL]);
- }
- if(this->Values[ctt_PARALLEL_LEVEL])
- {
- handler->SetOption("ParallelLevel",
- this->Values[ctt_PARALLEL_LEVEL]);
- }
- if(this->Values[ctt_SCHEDULE_RANDOM])
- {
- handler->SetOption("ScheduleRandom",
- this->Values[ctt_SCHEDULE_RANDOM]);
- }
- if(this->Values[ctt_STOP_TIME])
- {
+ }
+ if (this->Values[ctt_EXCLUDE_FIXTURE]) {
+ handler->SetOption("ExcludeFixtureRegularExpression",
+ this->Values[ctt_EXCLUDE_FIXTURE]);
+ }
+ if (this->Values[ctt_EXCLUDE_FIXTURE_SETUP]) {
+ handler->SetOption("ExcludeFixtureSetupRegularExpression",
+ this->Values[ctt_EXCLUDE_FIXTURE_SETUP]);
+ }
+ if (this->Values[ctt_EXCLUDE_FIXTURE_CLEANUP]) {
+ handler->SetOption("ExcludeFixtureCleanupRegularExpression",
+ this->Values[ctt_EXCLUDE_FIXTURE_CLEANUP]);
+ }
+ if (this->Values[ctt_PARALLEL_LEVEL]) {
+ handler->SetOption("ParallelLevel", this->Values[ctt_PARALLEL_LEVEL]);
+ }
+ if (this->Values[ctt_SCHEDULE_RANDOM]) {
+ handler->SetOption("ScheduleRandom", this->Values[ctt_SCHEDULE_RANDOM]);
+ }
+ if (this->Values[ctt_STOP_TIME]) {
this->CTest->SetStopTime(this->Values[ctt_STOP_TIME]);
+ }
+
+ // Test load is determined by: TEST_LOAD argument,
+ // or CTEST_TEST_LOAD script variable, or ctest --test-load
+ // command line argument... in that order.
+ unsigned long testLoad;
+ const char* ctestTestLoad = this->Makefile->GetDefinition("CTEST_TEST_LOAD");
+ if (this->Values[ctt_TEST_LOAD] && *this->Values[ctt_TEST_LOAD]) {
+ if (!cmSystemTools::StringToULong(this->Values[ctt_TEST_LOAD],
+ &testLoad)) {
+ testLoad = 0;
+ cmCTestLog(this->CTest, WARNING, "Invalid value for 'TEST_LOAD' : "
+ << this->Values[ctt_TEST_LOAD] << std::endl);
}
+ } else if (ctestTestLoad && *ctestTestLoad) {
+ if (!cmSystemTools::StringToULong(ctestTestLoad, &testLoad)) {
+ testLoad = 0;
+ cmCTestLog(this->CTest, WARNING, "Invalid value for 'CTEST_TEST_LOAD' : "
+ << ctestTestLoad << std::endl);
+ }
+ } else {
+ testLoad = this->CTest->GetTestLoad();
+ }
+ handler->SetTestLoad(testLoad);
+
+ handler->SetQuiet(this->Quiet);
return handler;
}
diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h
index 130cb6973..be7e7831f 100644
--- a/Source/CTest/cmCTestTestCommand.h
+++ b/Source/CTest/cmCTestTestCommand.h
@@ -1,19 +1,17 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestTestCommand_h
#define cmCTestTestCommand_h
+#include "cmConfigure.h"
+
#include "cmCTestHandlerCommand.h"
+#include <string>
+
+class cmCTestGenericHandler;
+class cmCommand;
+
/** \class cmCTestTest
* \brief Run a ctest script
*
@@ -22,71 +20,30 @@
class cmCTestTestCommand : public cmCTestHandlerCommand
{
public:
-
cmCTestTestCommand();
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestTestCommand* ni = new cmCTestTestCommand;
ni->CTest = this->CTest;
ni->CTestScriptHandler = this->CTestScriptHandler;
return ni;
- }
+ }
/**
* The name of the command as specified in CMakeList.txt.
*/
- 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);
+ std::string GetName() const CM_OVERRIDE { return "ctest_test"; }
protected:
virtual cmCTestGenericHandler* InitializeActualHandler();
- cmCTestGenericHandler* InitializeHandler();
+ cmCTestGenericHandler* InitializeHandler() CM_OVERRIDE;
- enum {
+ enum
+ {
ctt_BUILD = ct_LAST,
ctt_RETURN_VALUE,
ctt_START,
@@ -96,12 +53,15 @@ protected:
ctt_INCLUDE,
ctt_EXCLUDE_LABEL,
ctt_INCLUDE_LABEL,
+ ctt_EXCLUDE_FIXTURE,
+ ctt_EXCLUDE_FIXTURE_SETUP,
+ ctt_EXCLUDE_FIXTURE_CLEANUP,
ctt_PARALLEL_LEVEL,
ctt_SCHEDULE_RANDOM,
ctt_STOP_TIME,
+ ctt_TEST_LOAD,
ctt_LAST
};
};
-
#endif
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index 497774d1b..674be6052 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -1,424 +1,319 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestTestHandler.h"
- 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 "cmsys/Base64.h"
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+#include "cmsys/RegularExpression.hxx"
+#include <algorithm>
+#include <functional>
+#include <iomanip>
+#include <iterator>
+#include <set>
+#include <sstream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
-#include "cmCTestTestHandler.h"
-#include "cmCTestMultiProcessHandler.h"
-#include "cmCTestBatchTestHandler.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
-#include "cmCTestRunTest.h"
-#include "cmake.h"
+#include "cmCTestBatchTestHandler.h"
+#include "cmCTestMultiProcessHandler.h"
+#include "cmCommand.h"
#include "cmGeneratedFileStream.h"
-#include <cmsys/Process.h>
-#include <cmsys/RegularExpression.hxx>
-#include <cmsys/Base64.h>
-#include "cmMakefile.h"
#include "cmGlobalGenerator.h"
-#include "cmLocalGenerator.h"
-#include "cmCommand.h"
+#include "cmMakefile.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
#include "cmSystemTools.h"
-#include "cmXMLSafe.h"
+#include "cmWorkingDirectory.h"
+#include "cmXMLWriter.h"
+#include "cm_auto_ptr.hxx"
#include "cm_utf8.h"
+#include "cmake.h"
-#include <stdlib.h>
-#include <math.h>
-#include <float.h>
-
-#include <set>
+class cmExecutionStatus;
-//----------------------------------------------------------------------
class cmCTestSubdirCommand : public cmCommand
{
public:
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestSubdirCommand* c = new cmCTestSubdirCommand;
c->TestHandler = this->TestHandler;
return c;
- }
+ }
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
- virtual bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus &);
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- virtual const char* GetName() const { return "subdirs";}
-
- // Unused methods
- virtual const char* GetTerseDocumentation() const { return ""; }
- virtual const char* GetFullDocumentation() const { return ""; }
-
- cmTypeMacro(cmCTestSubdirCommand, cmCommand);
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& /*unused*/) CM_OVERRIDE;
cmCTestTestHandler* TestHandler;
};
-//----------------------------------------------------------------------
-bool cmCTestSubdirCommand
-::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
+bool cmCTestSubdirCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& /*unused*/)
{
- if(args.size() < 1 )
- {
+ if (args.empty()) {
this->SetError("called with incorrect number of arguments");
return false;
- }
+ }
std::vector<std::string>::const_iterator it;
std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
- for ( it = args.begin(); it != args.end(); ++ it )
- {
+ for (it = args.begin(); it != args.end(); ++it) {
std::string fname;
- if(cmSystemTools::FileIsFullPath(it->c_str()))
- {
+ if (cmSystemTools::FileIsFullPath(it->c_str())) {
fname = *it;
- }
- else
- {
+ } else {
fname = cwd;
fname += "/";
fname += *it;
- }
+ }
- if ( !cmSystemTools::FileIsDirectory(fname.c_str()) )
- {
+ if (!cmSystemTools::FileIsDirectory(fname)) {
// No subdirectory? So what...
continue;
+ }
+ bool readit = false;
+ {
+ cmWorkingDirectory workdir(fname);
+ const char* testFilename;
+ if (cmSystemTools::FileExists("CTestTestfile.cmake")) {
+ // does the CTestTestfile.cmake exist ?
+ testFilename = "CTestTestfile.cmake";
+ } else if (cmSystemTools::FileExists("DartTestfile.txt")) {
+ // does the DartTestfile.txt exist ?
+ testFilename = "DartTestfile.txt";
+ } else {
+ // No CTestTestfile? Who cares...
+ continue;
}
- cmSystemTools::ChangeDirectory(fname.c_str());
- const char* testFilename;
- if( cmSystemTools::FileExists("CTestTestfile.cmake") )
- {
- // does the CTestTestfile.cmake exist ?
- testFilename = "CTestTestfile.cmake";
- }
- else if( cmSystemTools::FileExists("DartTestfile.txt") )
- {
- // does the DartTestfile.txt exist ?
- testFilename = "DartTestfile.txt";
- }
- else
- {
- // No CTestTestfile? Who cares...
- continue;
- }
- fname += "/";
- fname += testFilename;
- bool readit =
- this->Makefile->ReadListFile(this->Makefile->GetCurrentListFile(),
- fname.c_str());
- cmSystemTools::ChangeDirectory(cwd.c_str());
- if(!readit)
- {
+ fname += "/";
+ fname += testFilename;
+ readit = this->Makefile->ReadDependentFile(fname.c_str());
+ }
+ if (!readit) {
std::string m = "Could not find include file: ";
m += fname;
- this->SetError(m.c_str());
+ this->SetError(m);
return false;
- }
}
- cmSystemTools::ChangeDirectory(cwd.c_str());
+ }
return true;
}
-//----------------------------------------------------------------------
class cmCTestAddSubdirectoryCommand : public cmCommand
{
public:
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestAddSubdirectoryCommand* c = new cmCTestAddSubdirectoryCommand;
c->TestHandler = this->TestHandler;
return c;
- }
+ }
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
- virtual bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus &);
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- 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);
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& /*unused*/) CM_OVERRIDE;
cmCTestTestHandler* TestHandler;
};
-//----------------------------------------------------------------------
-bool cmCTestAddSubdirectoryCommand
-::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
+bool cmCTestAddSubdirectoryCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus& /*unused*/)
{
- if(args.size() < 1 )
- {
+ if (args.empty()) {
this->SetError("called with incorrect number of arguments");
return false;
- }
+ }
- std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
- cmSystemTools::ChangeDirectory(cwd.c_str());
- std::string fname = cwd;
+ std::string fname = cmSystemTools::GetCurrentWorkingDirectory();
fname += "/";
- fname += args[1];
+ fname += args[0];
- if ( !cmSystemTools::FileExists(fname.c_str()) )
- {
+ if (!cmSystemTools::FileExists(fname.c_str())) {
// No subdirectory? So what...
return true;
+ }
+ bool readit = false;
+ {
+ const char* testFilename;
+ if (cmSystemTools::FileExists("CTestTestfile.cmake")) {
+ // does the CTestTestfile.cmake exist ?
+ testFilename = "CTestTestfile.cmake";
+ } else if (cmSystemTools::FileExists("DartTestfile.txt")) {
+ // does the DartTestfile.txt exist ?
+ testFilename = "DartTestfile.txt";
+ } else {
+ // No CTestTestfile? Who cares...
+ return true;
}
- cmSystemTools::ChangeDirectory(fname.c_str());
- const char* testFilename;
- if( cmSystemTools::FileExists("CTestTestfile.cmake") )
- {
- // does the CTestTestfile.cmake exist ?
- testFilename = "CTestTestfile.cmake";
- }
- else if( cmSystemTools::FileExists("DartTestfile.txt") )
- {
- // does the DartTestfile.txt exist ?
- testFilename = "DartTestfile.txt";
- }
- else
- {
- // No CTestTestfile? Who cares...
- cmSystemTools::ChangeDirectory(cwd.c_str());
- return true;
- }
- fname += "/";
- fname += testFilename;
- bool readit =
- this->Makefile->ReadListFile(this->Makefile->GetCurrentListFile(),
- fname.c_str());
- cmSystemTools::ChangeDirectory(cwd.c_str());
- if(!readit)
- {
+ fname += "/";
+ fname += testFilename;
+ readit = this->Makefile->ReadDependentFile(fname.c_str());
+ }
+ if (!readit) {
std::string m = "Could not find include file: ";
m += fname;
- this->SetError(m.c_str());
+ this->SetError(m);
return false;
- }
+ }
return true;
}
-//----------------------------------------------------------------------
class cmCTestAddTestCommand : public cmCommand
{
public:
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestAddTestCommand* c = new cmCTestAddTestCommand;
c->TestHandler = this->TestHandler;
return c;
- }
+ }
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
- virtual bool InitialPass(std::vector<std::string> const&,
- cmExecutionStatus &);
-
- /**
- * 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 ""; }
-
- cmTypeMacro(cmCTestAddTestCommand, cmCommand);
+ bool InitialPass(std::vector<std::string> const& /*args*/,
+ cmExecutionStatus& /*unused*/) CM_OVERRIDE;
cmCTestTestHandler* TestHandler;
};
-//----------------------------------------------------------------------
-bool cmCTestAddTestCommand
-::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
+bool cmCTestAddTestCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& /*unused*/)
{
- if ( args.size() < 2 )
- {
+ if (args.size() < 2) {
this->SetError("called with incorrect number of arguments");
return false;
- }
+ }
return this->TestHandler->AddTest(args);
}
-//----------------------------------------------------------------------
class cmCTestSetTestsPropertiesCommand : public cmCommand
{
public:
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
- cmCTestSetTestsPropertiesCommand* c
- = new cmCTestSetTestsPropertiesCommand;
+ cmCommand* Clone() CM_OVERRIDE
+ {
+ cmCTestSetTestsPropertiesCommand* c = new cmCTestSetTestsPropertiesCommand;
c->TestHandler = this->TestHandler;
return c;
- }
+ }
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
- */
- virtual bool InitialPass(std::vector<std::string> const&,
- cmExecutionStatus &);
-
- /**
- * 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 ""; }
-
- cmTypeMacro(cmCTestSetTestsPropertiesCommand, cmCommand);
+ bool InitialPass(std::vector<std::string> const& /*args*/,
+ cmExecutionStatus& /*unused*/) CM_OVERRIDE;
cmCTestTestHandler* TestHandler;
};
-//----------------------------------------------------------------------
-bool cmCTestSetTestsPropertiesCommand
-::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
+bool cmCTestSetTestsPropertiesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus& /*unused*/)
{
return this->TestHandler->SetTestsProperties(args);
}
-//----------------------------------------------------------------------
// get the next number in a string with numbers separated by ,
// pos is the start of the search and pos2 is the end of the search
// pos becomes pos2 after a call to GetNextNumber.
// -1 is returned at the end of the list.
-inline int GetNextNumber(std::string const& in,
- int& val,
+inline int GetNextNumber(std::string const& in, int& val,
std::string::size_type& pos,
std::string::size_type& pos2)
{
pos2 = in.find(',', pos);
- if(pos2 != in.npos)
- {
- if(pos2-pos == 0)
- {
+ if (pos2 != std::string::npos) {
+ if (pos2 - pos == 0) {
val = -1;
- }
- else
- {
- val = atoi(in.substr(pos, pos2-pos).c_str());
- }
- pos = pos2+1;
- return 1;
- }
- else
- {
- if(in.size()-pos == 0)
- {
- val = -1;
- }
- else
- {
- val = atoi(in.substr(pos, in.size()-pos).c_str());
- }
- return 0;
+ } else {
+ val = atoi(in.substr(pos, pos2 - pos).c_str());
}
+ pos = pos2 + 1;
+ return 1;
+ }
+ if (in.size() - pos == 0) {
+ val = -1;
+ } else {
+ val = atoi(in.substr(pos, in.size() - pos).c_str());
+ }
+ return 0;
}
-//----------------------------------------------------------------------
// get the next number in a string with numbers separated by ,
// pos is the start of the search and pos2 is the end of the search
// pos becomes pos2 after a call to GetNextNumber.
// -1 is returned at the end of the list.
-inline int GetNextRealNumber(std::string const& in,
- double& val,
+inline int GetNextRealNumber(std::string const& in, double& val,
std::string::size_type& pos,
std::string::size_type& pos2)
{
pos2 = in.find(',', pos);
- if(pos2 != in.npos)
- {
- if(pos2-pos == 0)
- {
+ if (pos2 != std::string::npos) {
+ if (pos2 - pos == 0) {
val = -1;
- }
- else
- {
- val = atof(in.substr(pos, pos2-pos).c_str());
- }
- pos = pos2+1;
- return 1;
- }
- else
- {
- if(in.size()-pos == 0)
- {
- val = -1;
- }
- else
- {
- val = atof(in.substr(pos, in.size()-pos).c_str());
- }
- return 0;
+ } else {
+ val = atof(in.substr(pos, pos2 - pos).c_str());
}
+ pos = pos2 + 1;
+ return 1;
+ }
+ if (in.size() - pos == 0) {
+ val = -1;
+ } else {
+ val = atof(in.substr(pos, in.size() - pos).c_str());
+ }
+ return 0;
}
-
-//----------------------------------------------------------------------
cmCTestTestHandler::cmCTestTestHandler()
{
this->UseUnion = false;
- this->UseIncludeLabelRegExpFlag = false;
- this->UseExcludeLabelRegExpFlag = false;
- this->UseIncludeRegExpFlag = false;
- this->UseExcludeRegExpFlag = false;
- this->UseExcludeRegExpFirst = false;
+ this->UseIncludeLabelRegExpFlag = false;
+ this->UseExcludeLabelRegExpFlag = false;
+ this->UseIncludeRegExpFlag = false;
+ this->UseExcludeRegExpFlag = false;
+ this->UseExcludeRegExpFirst = false;
this->CustomMaximumPassedTestOutputSize = 1 * 1024;
this->CustomMaximumFailedTestOutputSize = 300 * 1024;
this->MemCheck = false;
- this->LogFile = 0;
+ this->LogFile = CM_NULLPTR;
// regex to detect <DartMeasurement>...</DartMeasurement>
- this->DartStuff.compile(
- "(<DartMeasurement.*/DartMeasurement[a-zA-Z]*>)");
+ this->DartStuff.compile("(<DartMeasurement.*/DartMeasurement[a-zA-Z]*>)");
// regex to detect each individual <DartMeasurement>...</DartMeasurement>
this->DartStuff1.compile(
"(<DartMeasurement[^<]*</DartMeasurement[a-zA-Z]*>)");
}
-//----------------------------------------------------------------------
void cmCTestTestHandler::Initialize()
{
this->Superclass::Initialize();
@@ -447,117 +342,120 @@ void cmCTestTestHandler::Initialize()
this->ExcludeLabelRegularExpression = "";
this->IncludeRegExp = "";
this->ExcludeRegExp = "";
+ this->ExcludeFixtureRegExp.clear();
+ this->ExcludeFixtureSetupRegExp.clear();
+ this->ExcludeFixtureCleanupRegExp.clear();
TestsToRunString = "";
this->UseUnion = false;
this->TestList.clear();
}
-//----------------------------------------------------------------------
-void cmCTestTestHandler::PopulateCustomVectors(cmMakefile *mf)
+void cmCTestTestHandler::PopulateCustomVectors(cmMakefile* mf)
{
this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_PRE_TEST",
- this->CustomPreTest);
+ this->CustomPreTest);
this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_POST_TEST",
- this->CustomPostTest);
- this->CTest->PopulateCustomVector(mf,
- "CTEST_CUSTOM_TESTS_IGNORE",
- this->CustomTestsIgnore);
- this->CTest->PopulateCustomInteger(mf,
- "CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE",
- this->CustomMaximumPassedTestOutputSize);
- this->CTest->PopulateCustomInteger(mf,
- "CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE",
- this->CustomMaximumFailedTestOutputSize);
+ this->CustomPostTest);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_TESTS_IGNORE",
+ this->CustomTestsIgnore);
+ this->CTest->PopulateCustomInteger(
+ mf, "CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE",
+ this->CustomMaximumPassedTestOutputSize);
+ this->CTest->PopulateCustomInteger(
+ mf, "CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE",
+ this->CustomMaximumFailedTestOutputSize);
}
-//----------------------------------------------------------------------
int cmCTestTestHandler::PreProcessHandler()
{
- if ( !this->ExecuteCommands(this->CustomPreTest) )
- {
+ if (!this->ExecuteCommands(this->CustomPreTest)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Problem executing pre-test command(s)." << std::endl);
+ "Problem executing pre-test command(s)." << std::endl);
return 0;
- }
+ }
return 1;
}
-//----------------------------------------------------------------------
int cmCTestTestHandler::PostProcessHandler()
{
- if ( !this->ExecuteCommands(this->CustomPostTest) )
- {
+ if (!this->ExecuteCommands(this->CustomPostTest)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Problem executing post-test command(s)." << std::endl);
+ "Problem executing post-test command(s)." << std::endl);
return 0;
- }
+ }
return 1;
}
-//----------------------------------------------------------------------
-//clearly it would be nice if this were broken up into a few smaller
-//functions and commented...
+// clearly it would be nice if this were broken up into a few smaller
+// functions and commented...
int cmCTestTestHandler::ProcessHandler()
{
// Update internal data structure from generic one
this->SetTestsToRunInformation(this->GetOption("TestsToRunInformation"));
this->SetUseUnion(cmSystemTools::IsOn(this->GetOption("UseUnion")));
- if(cmSystemTools::IsOn(this->GetOption("ScheduleRandom")))
- {
+ if (cmSystemTools::IsOn(this->GetOption("ScheduleRandom"))) {
this->CTest->SetScheduleType("Random");
- }
- if(this->GetOption("ParallelLevel"))
- {
+ }
+ if (this->GetOption("ParallelLevel")) {
this->CTest->SetParallelLevel(atoi(this->GetOption("ParallelLevel")));
- }
+ }
const char* val;
val = this->GetOption("LabelRegularExpression");
- if ( val )
- {
+ if (val) {
this->UseIncludeLabelRegExpFlag = true;
this->IncludeLabelRegExp = val;
- }
+ }
val = this->GetOption("ExcludeLabelRegularExpression");
- if ( val )
- {
+ if (val) {
this->UseExcludeLabelRegExpFlag = true;
- this->ExcludeLabelRegularExpression = val;
- }
+ this->ExcludeLabelRegExp = val;
+ }
val = this->GetOption("IncludeRegularExpression");
- if ( val )
- {
+ if (val) {
this->UseIncludeRegExp();
this->SetIncludeRegExp(val);
- }
+ }
val = this->GetOption("ExcludeRegularExpression");
- if ( val )
- {
+ if (val) {
this->UseExcludeRegExp();
this->SetExcludeRegExp(val);
- }
+ }
+ val = this->GetOption("ExcludeFixtureRegularExpression");
+ if (val) {
+ this->ExcludeFixtureRegExp = val;
+ }
+ val = this->GetOption("ExcludeFixtureSetupRegularExpression");
+ if (val) {
+ this->ExcludeFixtureSetupRegExp = val;
+ }
+ val = this->GetOption("ExcludeFixtureCleanupRegularExpression");
+ if (val) {
+ this->ExcludeFixtureCleanupRegExp = val;
+ }
+ this->SetRerunFailed(cmSystemTools::IsOn(this->GetOption("RerunFailed")));
this->TestResults.clear();
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- (this->MemCheck ? "Memory check" : "Test")
- << " project " << cmSystemTools::GetCurrentWorkingDirectory()
- << std::endl);
- if ( ! this->PreProcessHandler() )
- {
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_OUTPUT, (this->MemCheck ? "Memory check" : "Test")
+ << " project " << cmSystemTools::GetCurrentWorkingDirectory()
+ << std::endl,
+ this->Quiet);
+ if (!this->PreProcessHandler()) {
return -1;
- }
+ }
cmGeneratedFileStream mLogFile;
this->StartLogFile((this->MemCheck ? "DynamicAnalysis" : "Test"), mLogFile);
this->LogFile = &mLogFile;
- std::vector<cmStdString> passed;
- std::vector<cmStdString> failed;
+ std::vector<std::string> passed;
+ std::vector<std::string> failed;
int total;
- //start the real time clock
+ // start the real time clock
double clock_start, clock_finish;
clock_start = cmSystemTools::GetTime();
@@ -567,473 +465,748 @@ int cmCTestTestHandler::ProcessHandler()
total = int(passed.size()) + int(failed.size());
- if (total == 0)
- {
- if ( !this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels() )
- {
+ if (total == 0) {
+ if (!this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels()) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "No tests were found!!!"
- << std::endl);
+ << std::endl);
+ }
+ } else {
+ if (this->HandlerVerbose && !passed.empty() &&
+ (this->UseIncludeRegExpFlag || this->UseExcludeRegExpFlag)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
+ << "The following tests passed:" << std::endl,
+ this->Quiet);
+ for (std::vector<std::string>::iterator j = passed.begin();
+ j != passed.end(); ++j) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "\t" << *j << std::endl, this->Quiet);
}
}
- else
- {
- if (this->HandlerVerbose && passed.size() &&
- (this->UseIncludeRegExpFlag || this->UseExcludeRegExpFlag))
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
- << "The following tests passed:" << std::endl);
- for(std::vector<cmStdString>::iterator j = passed.begin();
- j != passed.end(); ++j)
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "\t" << *j
- << std::endl);
- }
+
+ typedef std::set<cmCTestTestHandler::cmCTestTestResult,
+ cmCTestTestResultLess>
+ SetOfTests;
+ SetOfTests resultsSet(this->TestResults.begin(), this->TestResults.end());
+ std::vector<cmCTestTestHandler::cmCTestTestResult> disabledTests;
+
+ for (SetOfTests::iterator ftit = resultsSet.begin();
+ ftit != resultsSet.end(); ++ftit) {
+ if (cmHasLiteralPrefix(ftit->CompletionStatus, "SKIP_RETURN_CODE=") ||
+ ftit->CompletionStatus == "Disabled") {
+ disabledTests.push_back(*ftit);
}
+ }
float percent = float(passed.size()) * 100.0f / float(total);
- if ( failed.size() > 0 && percent > 99)
- {
+ if (!failed.empty() && percent > 99) {
percent = 99;
- }
+ }
cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl
- << static_cast<int>(percent + .5) << "% tests passed, "
- << failed.size() << " tests failed out of "
- << total << std::endl);
- if(this->CTest->GetLabelSummary())
- {
+ << static_cast<int>(percent + .5f) << "% tests passed, "
+ << failed.size() << " tests failed out of " << total
+ << std::endl);
+ if (this->CTest->GetLabelSummary()) {
this->PrintLabelSummary();
- }
+ }
char realBuf[1024];
sprintf(realBuf, "%6.2f sec", (double)(clock_finish - clock_start));
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time (real) = "
- << realBuf << "\n" );
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ "\nTotal Test time (real) = " << realBuf << "\n",
+ this->Quiet);
- if (failed.size())
- {
+ if (!disabledTests.empty()) {
cmGeneratedFileStream ofs;
cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl
- << "The following tests FAILED:" << std::endl);
- this->StartLogFile("TestsFailed", ofs);
+ << "The following tests did not run:" << std::endl);
+ this->StartLogFile("TestsDisabled", ofs);
+
+ const char* disabled_reason;
+ for (std::vector<cmCTestTestHandler::cmCTestTestResult>::iterator dtit =
+ disabledTests.begin();
+ dtit != disabledTests.end(); ++dtit) {
+ ofs << dtit->TestCount << ":" << dtit->Name << std::endl;
+ if (dtit->CompletionStatus == "Disabled") {
+ disabled_reason = "Disabled";
+ } else {
+ disabled_reason = "Skipped";
+ }
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "\t"
+ << std::setw(3) << dtit->TestCount << " - " << dtit->Name
+ << " (" << disabled_reason << ")" << std::endl);
+ }
+ }
- typedef std::set<cmCTestTestHandler::cmCTestTestResult,
- cmCTestTestResultLess> SetOfTests;
- SetOfTests resultsSet(this->TestResults.begin(),
- this->TestResults.end());
+ if (!failed.empty()) {
+ cmGeneratedFileStream ofs;
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl
+ << "The following tests FAILED:" << std::endl);
+ this->StartLogFile("TestsFailed", ofs);
- for(SetOfTests::iterator ftit = resultsSet.begin();
- ftit != resultsSet.end(); ++ftit)
- {
- if ( ftit->Status != cmCTestTestHandler::COMPLETED )
- {
+ for (SetOfTests::iterator ftit = resultsSet.begin();
+ ftit != resultsSet.end(); ++ftit) {
+ if (ftit->Status != cmCTestTestHandler::COMPLETED &&
+ !cmHasLiteralPrefix(ftit->CompletionStatus, "SKIP_RETURN_CODE=") &&
+ ftit->CompletionStatus != "Disabled") {
ofs << ftit->TestCount << ":" << ftit->Name << std::endl;
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "\t" << std::setw(3)
- << ftit->TestCount << " - "
- << ftit->Name.c_str() << " ("
- << this->GetTestStatus(ftit->Status) << ")"
- << std::endl);
- }
+ cmCTestLog(
+ this->CTest, HANDLER_OUTPUT, "\t"
+ << std::setw(3) << ftit->TestCount << " - " << ftit->Name << " ("
+ << this->GetTestStatus(ftit->Status) << ")" << std::endl);
}
}
}
+ }
- if ( this->CTest->GetProduceXML() )
- {
+ if (this->CTest->GetProduceXML()) {
cmGeneratedFileStream xmlfile;
- if( !this->StartResultingXML(
+ if (!this->StartResultingXML(
(this->MemCheck ? cmCTest::PartMemCheck : cmCTest::PartTest),
- (this->MemCheck ? "DynamicAnalysis" : "Test"), xmlfile) )
- {
+ (this->MemCheck ? "DynamicAnalysis" : "Test"), xmlfile)) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create "
- << (this->MemCheck ? "memory check" : "testing")
- << " XML file" << std::endl);
- this->LogFile = 0;
+ << (this->MemCheck ? "memory check" : "testing")
+ << " XML file" << std::endl);
+ this->LogFile = CM_NULLPTR;
return 1;
- }
- this->GenerateDartOutput(xmlfile);
}
+ cmXMLWriter xml(xmlfile);
+ this->GenerateDartOutput(xml);
+ }
- if ( ! this->PostProcessHandler() )
- {
- this->LogFile = 0;
+ if (!this->PostProcessHandler()) {
+ this->LogFile = CM_NULLPTR;
return -1;
- }
+ }
- if ( !failed.empty() )
- {
- this->LogFile = 0;
+ if (!failed.empty()) {
+ this->LogFile = CM_NULLPTR;
return -1;
- }
- this->LogFile = 0;
+ }
+ this->LogFile = CM_NULLPTR;
return 0;
}
-//----------------------------------------------------------------------
void cmCTestTestHandler::PrintLabelSummary()
{
cmCTestTestHandler::ListOfTests::iterator it = this->TestList.begin();
- cmCTestTestHandler::TestResultsVector::iterator ri =
- this->TestResults.begin();
- std::map<cmStdString, double> labelTimes;
- std::set<cmStdString> labels;
+ std::map<std::string, double> labelTimes;
+ std::map<std::string, int> labelCounts;
+ std::set<std::string> labels;
// initialize maps
std::string::size_type maxlen = 0;
- for(; it != this->TestList.end(); ++it)
- {
+ for (; it != this->TestList.end(); ++it) {
cmCTestTestProperties& p = *it;
- if(p.Labels.size() != 0)
- {
- for(std::vector<std::string>::iterator l = p.Labels.begin();
- l != p.Labels.end(); ++l)
- {
- if((*l).size() > maxlen)
- {
+ if (!p.Labels.empty()) {
+ for (std::vector<std::string>::iterator l = p.Labels.begin();
+ l != p.Labels.end(); ++l) {
+ if ((*l).size() > maxlen) {
maxlen = (*l).size();
- }
+ }
labels.insert(*l);
labelTimes[*l] = 0;
- }
+ labelCounts[*l] = 0;
}
}
- ri = this->TestResults.begin();
+ }
+ cmCTestTestHandler::TestResultsVector::iterator ri =
+ this->TestResults.begin();
// fill maps
- for(; ri != this->TestResults.end(); ++ri)
- {
- cmCTestTestResult &result = *ri;
+ for (; ri != this->TestResults.end(); ++ri) {
+ cmCTestTestResult& result = *ri;
cmCTestTestProperties& p = *result.Properties;
- if(p.Labels.size() != 0)
- {
- for(std::vector<std::string>::iterator l = p.Labels.begin();
- l != p.Labels.end(); ++l)
- {
+ if (!p.Labels.empty()) {
+ for (std::vector<std::string>::iterator l = p.Labels.begin();
+ l != p.Labels.end(); ++l) {
labelTimes[*l] += result.ExecutionTime;
- }
+ ++labelCounts[*l];
}
}
+ }
// now print times
- if(labels.size())
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nLabel Time Summary:");
- }
- for(std::set<cmStdString>::const_iterator i = labels.begin();
- i != labels.end(); ++i)
- {
+ if (!labels.empty()) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "\nLabel Time Summary:",
+ this->Quiet);
+ }
+ for (std::set<std::string>::const_iterator i = labels.begin();
+ i != labels.end(); ++i) {
std::string label = *i;
- label.resize(maxlen +3, ' ');
+ label.resize(maxlen + 3, ' ');
+
char buf[1024];
sprintf(buf, "%6.2f sec", labelTimes[*i]);
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "\n"
- << label << " = " << buf );
- if ( this->LogFile )
- {
- *this->LogFile << "\n" << *i << " = "
- << buf << "\n";
- }
+
+ std::ostringstream labelCountStr;
+ labelCountStr << "(" << labelCounts[*i] << " test";
+ if (labelCounts[*i] > 1) {
+ labelCountStr << "s";
}
- if(labels.size())
- {
- if(this->LogFile)
- {
+ labelCountStr << ")";
+
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "\n"
+ << label << " = " << buf << " "
+ << labelCountStr.str(),
+ this->Quiet);
+ if (this->LogFile) {
+ *this->LogFile << "\n" << *i << " = " << buf << "\n";
+ }
+ }
+ if (!labels.empty()) {
+ if (this->LogFile) {
*this->LogFile << "\n";
- }
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "\n");
}
-
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "\n", this->Quiet);
+ }
}
-//----------------------------------------------------------------------
void cmCTestTestHandler::CheckLabelFilterInclude(cmCTestTestProperties& it)
{
// if not using Labels to filter then return
- if (!this->UseIncludeLabelRegExpFlag )
- {
+ if (!this->UseIncludeLabelRegExpFlag) {
return;
- }
+ }
// if there are no labels and we are filtering by labels
// then exclude the test as it does not have the label
- if(it.Labels.size() == 0 )
- {
+ if (it.Labels.empty()) {
it.IsInBasedOnREOptions = false;
return;
- }
+ }
// check to see if the label regular expression matches
- bool found = false; // assume it does not match
+ bool found = false; // assume it does not match
// loop over all labels and look for match
- for(std::vector<std::string>::iterator l = it.Labels.begin();
- l != it.Labels.end(); ++l)
- {
- if(this->IncludeLabelRegularExpression.find(*l))
- {
+ for (std::vector<std::string>::iterator l = it.Labels.begin();
+ l != it.Labels.end(); ++l) {
+ if (this->IncludeLabelRegularExpression.find(*l)) {
found = true;
- }
}
+ }
// if no match was found, exclude the test
- if(!found)
- {
+ if (!found) {
it.IsInBasedOnREOptions = false;
- }
+ }
}
-
-//----------------------------------------------------------------------
void cmCTestTestHandler::CheckLabelFilterExclude(cmCTestTestProperties& it)
{
// if not using Labels to filter then return
- if (!this->UseExcludeLabelRegExpFlag )
- {
+ if (!this->UseExcludeLabelRegExpFlag) {
return;
- }
+ }
// if there are no labels and we are excluding by labels
// then do nothing as a no label can not be a match
- if(it.Labels.size() == 0 )
- {
+ if (it.Labels.empty()) {
return;
- }
+ }
// check to see if the label regular expression matches
- bool found = false; // assume it does not match
+ bool found = false; // assume it does not match
// loop over all labels and look for match
- for(std::vector<std::string>::iterator l = it.Labels.begin();
- l != it.Labels.end(); ++l)
- {
- if(this->ExcludeLabelRegularExpression.find(*l))
- {
+ for (std::vector<std::string>::iterator l = it.Labels.begin();
+ l != it.Labels.end(); ++l) {
+ if (this->ExcludeLabelRegularExpression.find(*l)) {
found = true;
- }
}
+ }
// if match was found, exclude the test
- if(found)
- {
+ if (found) {
it.IsInBasedOnREOptions = false;
- }
+ }
}
-//----------------------------------------------------------------------
void cmCTestTestHandler::CheckLabelFilter(cmCTestTestProperties& it)
{
this->CheckLabelFilterInclude(it);
this->CheckLabelFilterExclude(it);
}
-//----------------------------------------------------------------------
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;
cmCTestTestHandler::ListOfTests::iterator it;
- for ( it = this->TestList.begin(); it != this->TestList.end(); it ++ )
- {
+ for (it = this->TestList.begin(); it != this->TestList.end(); it++) {
this->CheckLabelFilter(*it);
- if (it->IsInBasedOnREOptions)
- {
- inREcnt ++;
- }
+ if (it->IsInBasedOnREOptions) {
+ inREcnt++;
}
+ }
// expand the test list based on the union flag
- if (this->UseUnion)
- {
+ if (this->UseUnion) {
this->ExpandTestsToRunInformation((int)tmsize);
- }
- else
- {
+ } else {
this->ExpandTestsToRunInformation(inREcnt);
- }
+ }
// Now create a final list of tests to run
int cnt = 0;
inREcnt = 0;
- std::string last_directory = "";
+ std::string last_directory;
ListOfTests finalList;
- for ( it = this->TestList.begin(); it != this->TestList.end(); it ++ )
- {
- cnt ++;
- if (it->IsInBasedOnREOptions)
- {
+ for (it = this->TestList.begin(); it != this->TestList.end(); it++) {
+ cnt++;
+ if (it->IsInBasedOnREOptions) {
inREcnt++;
- }
+ }
- if (this->UseUnion)
- {
+ if (this->UseUnion) {
// if it is not in the list and not in the regexp then skip
- if ((this->TestsToRun.size() &&
- std::find(this->TestsToRun.begin(), this->TestsToRun.end(), cnt)
- == this->TestsToRun.end()) && !it->IsInBasedOnREOptions)
- {
+ if ((!this->TestsToRun.empty() &&
+ std::find(this->TestsToRun.begin(), this->TestsToRun.end(), cnt) ==
+ this->TestsToRun.end()) &&
+ !it->IsInBasedOnREOptions) {
continue;
- }
}
- else
- {
+ } else {
// is this test in the list of tests to run? If not then skip it
- if ((this->TestsToRun.size() &&
- std::find(this->TestsToRun.begin(),
- this->TestsToRun.end(), inREcnt)
- == this->TestsToRun.end()) || !it->IsInBasedOnREOptions)
- {
+ if ((!this->TestsToRun.empty() &&
+ std::find(this->TestsToRun.begin(), this->TestsToRun.end(),
+ inREcnt) == this->TestsToRun.end()) ||
+ !it->IsInBasedOnREOptions) {
continue;
- }
}
- it->Index = cnt; // save the index into the test list for this test
- finalList.push_back(*it);
}
+ it->Index = cnt; // save the index into the test list for this test
+ finalList.push_back(*it);
+ }
+
+ UpdateForFixtures(finalList);
+
// Save the total number of tests before exclusions
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.empty() &&
+ std::find(this->TestsToRun.begin(), this->TestsToRun.end(), cnt) ==
+ this->TestsToRun.end())) {
+ continue;
+ }
+
+ it->Index = cnt;
+ finalList.push_back(*it);
+ }
+
+ UpdateForFixtures(finalList);
+
+ // 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::UpdateForFixtures(ListOfTests& tests) const
+{
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Updating test list for fixtures" << std::endl,
+ this->Quiet);
+
+ // Prepare regular expression evaluators
+ std::string setupRegExp(this->ExcludeFixtureRegExp);
+ std::string cleanupRegExp(this->ExcludeFixtureRegExp);
+ if (!this->ExcludeFixtureSetupRegExp.empty()) {
+ if (setupRegExp.empty()) {
+ setupRegExp = this->ExcludeFixtureSetupRegExp;
+ } else {
+ setupRegExp.append("(" + setupRegExp + ")|(" +
+ this->ExcludeFixtureSetupRegExp + ")");
+ }
+ }
+ if (!this->ExcludeFixtureCleanupRegExp.empty()) {
+ if (cleanupRegExp.empty()) {
+ cleanupRegExp = this->ExcludeFixtureCleanupRegExp;
+ } else {
+ cleanupRegExp.append("(" + cleanupRegExp + ")|(" +
+ this->ExcludeFixtureCleanupRegExp + ")");
+ }
+ }
+ cmsys::RegularExpression excludeSetupRegex(setupRegExp);
+ cmsys::RegularExpression excludeCleanupRegex(cleanupRegExp);
+
+ // Prepare some maps to help us find setup and cleanup tests for
+ // any given fixture
+ typedef ListOfTests::const_iterator TestIterator;
+ typedef std::multimap<std::string, TestIterator> FixtureDependencies;
+ typedef FixtureDependencies::const_iterator FixtureDepsIterator;
+ FixtureDependencies fixtureSetups;
+ FixtureDependencies fixtureCleanups;
+
+ for (ListOfTests::const_iterator it = this->TestList.begin();
+ it != this->TestList.end(); ++it) {
+ const cmCTestTestProperties& p = *it;
+
+ const std::set<std::string>& setups = p.FixturesSetup;
+ for (std::set<std::string>::const_iterator depsIt = setups.begin();
+ depsIt != setups.end(); ++depsIt) {
+ fixtureSetups.insert(std::make_pair(*depsIt, it));
+ }
+
+ const std::set<std::string>& cleanups = p.FixturesCleanup;
+ for (std::set<std::string>::const_iterator depsIt = cleanups.begin();
+ depsIt != cleanups.end(); ++depsIt) {
+ fixtureCleanups.insert(std::make_pair(*depsIt, it));
+ }
+ }
+
+ // Prepare fast lookup of tests already included in our list of tests
+ std::set<std::string> addedTests;
+ for (ListOfTests::const_iterator it = tests.begin(); it != tests.end();
+ ++it) {
+ const cmCTestTestProperties& p = *it;
+ addedTests.insert(p.Name);
+ }
+
+ // These are lookups of fixture name to a list of indices into the final
+ // tests array for tests which require that fixture and tests which are
+ // setups for that fixture. They are needed at the end to populate
+ // dependencies of the cleanup tests in our final list of tests.
+ std::map<std::string, std::vector<size_t> > fixtureRequirements;
+ std::map<std::string, std::vector<size_t> > setupFixturesAdded;
+
+ // Use integer index for iteration because we append to
+ // the tests vector as we go
+ size_t fixtureTestsAdded = 0;
+ std::set<std::string> addedFixtures;
+ for (size_t i = 0; i < tests.size(); ++i) {
+ // Skip disabled tests
+ if (tests[i].Disabled) {
+ continue;
+ }
+
+ // There are two things to do for each test:
+ // 1. For every fixture required by this test, record that fixture as
+ // being required and create dependencies on that fixture's setup
+ // tests.
+ // 2. Record all setup tests in the final test list so we can later make
+ // cleanup tests in the test list depend on their associated setup
+ // tests to enforce correct ordering.
+
+ // 1. Handle fixture requirements
+ //
+ // Must copy the set of fixtures required because we may invalidate
+ // the tests array by appending to it
+ std::set<std::string> fixtures = tests[i].FixturesRequired;
+ for (std::set<std::string>::const_iterator fixturesIt = fixtures.begin();
+ fixturesIt != fixtures.end(); ++fixturesIt) {
+
+ const std::string& requiredFixtureName = *fixturesIt;
+ if (requiredFixtureName.empty()) {
+ continue;
+ }
+
+ fixtureRequirements[requiredFixtureName].push_back(i);
+
+ // Add dependencies to this test for all of the setup tests
+ // associated with the required fixture. If any of those setup
+ // tests fail, this test should not run. We make the fixture's
+ // cleanup tests depend on this test case later.
+ std::pair<FixtureDepsIterator, FixtureDepsIterator> setupRange =
+ fixtureSetups.equal_range(requiredFixtureName);
+ for (FixtureDepsIterator sIt = setupRange.first;
+ sIt != setupRange.second; ++sIt) {
+ const std::string& setupTestName = sIt->second->Name;
+ tests[i].RequireSuccessDepends.insert(setupTestName);
+ if (std::find(tests[i].Depends.begin(), tests[i].Depends.end(),
+ setupTestName) == tests[i].Depends.end()) {
+ tests[i].Depends.push_back(setupTestName);
+ }
+ }
+
+ // Append any fixture setup/cleanup tests to our test list if they
+ // are not already in it (they could have been in the original
+ // set of tests passed to us at the outset or have already been
+ // added from a previously checked test). A fixture isn't required
+ // to have setup/cleanup tests.
+ if (!addedFixtures.insert(requiredFixtureName).second) {
+ // Already seen this fixture, no need to check it again
+ continue;
+ }
+
+ // Only add setup tests if this fixture has not been excluded
+ if (setupRegExp.empty() ||
+ !excludeSetupRegex.find(requiredFixtureName)) {
+ std::pair<FixtureDepsIterator, FixtureDepsIterator> fixtureRange =
+ fixtureSetups.equal_range(requiredFixtureName);
+ for (FixtureDepsIterator it = fixtureRange.first;
+ it != fixtureRange.second; ++it) {
+ ListOfTests::const_iterator lotIt = it->second;
+ const cmCTestTestProperties& p = *lotIt;
+
+ if (!addedTests.insert(p.Name).second) {
+ // Already have p in our test list
+ continue;
+ }
+
+ // This is a test not yet in our list, so add it and
+ // update its index to reflect where it was in the original
+ // full list of all tests (needed to track individual tests
+ // across ctest runs for re-run failed, etc.)
+ tests.push_back(p);
+ tests.back().Index =
+ 1 + static_cast<int>(std::distance(this->TestList.begin(), lotIt));
+ ++fixtureTestsAdded;
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Added setup test "
+ << p.Name << " required by fixture "
+ << requiredFixtureName << std::endl,
+ this->Quiet);
+ }
+ }
+
+ // Only add cleanup tests if this fixture has not been excluded
+ if (cleanupRegExp.empty() ||
+ !excludeCleanupRegex.find(requiredFixtureName)) {
+ std::pair<FixtureDepsIterator, FixtureDepsIterator> fixtureRange =
+ fixtureCleanups.equal_range(requiredFixtureName);
+ for (FixtureDepsIterator it = fixtureRange.first;
+ it != fixtureRange.second; ++it) {
+ ListOfTests::const_iterator lotIt = it->second;
+ const cmCTestTestProperties& p = *lotIt;
+
+ if (!addedTests.insert(p.Name).second) {
+ // Already have p in our test list
+ continue;
+ }
+
+ // This is a test not yet in our list, so add it and
+ // update its index to reflect where it was in the original
+ // full list of all tests (needed to track individual tests
+ // across ctest runs for re-run failed, etc.)
+ tests.push_back(p);
+ tests.back().Index =
+ 1 + static_cast<int>(std::distance(this->TestList.begin(), lotIt));
+ ++fixtureTestsAdded;
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Added cleanup test "
+ << p.Name << " required by fixture "
+ << requiredFixtureName << std::endl,
+ this->Quiet);
+ }
+ }
+ }
+
+ // 2. Record all setup fixtures included in the final list of tests
+ for (std::set<std::string>::const_iterator fixturesIt =
+ tests[i].FixturesSetup.begin();
+ fixturesIt != tests[i].FixturesSetup.end(); ++fixturesIt) {
+
+ const std::string& setupFixtureName = *fixturesIt;
+ if (setupFixtureName.empty()) {
+ continue;
+ }
+
+ setupFixturesAdded[setupFixtureName].push_back(i);
+ }
+ }
+
+ // Now that we have the final list of tests, we can update all cleanup
+ // tests to depend on those tests which require that fixture and on any
+ // setup tests for that fixture. The latter is required to handle the
+ // pathological case where setup and cleanup tests are in the test set
+ // but no other test has that fixture as a requirement.
+ for (ListOfTests::iterator tIt = tests.begin(); tIt != tests.end(); ++tIt) {
+ cmCTestTestProperties& p = *tIt;
+ const std::set<std::string>& cleanups = p.FixturesCleanup;
+ for (std::set<std::string>::const_iterator fIt = cleanups.begin();
+ fIt != cleanups.end(); ++fIt) {
+ const std::string& fixture = *fIt;
+
+ // This cleanup test could be part of the original test list that was
+ // passed in. It is then possible that no other test requires the
+ // fIt fixture, so we have to check for this.
+ std::map<std::string, std::vector<size_t> >::const_iterator cIt =
+ fixtureRequirements.find(fixture);
+ if (cIt != fixtureRequirements.end()) {
+ const std::vector<size_t>& indices = cIt->second;
+ for (std::vector<size_t>::const_iterator indexIt = indices.begin();
+ indexIt != indices.end(); ++indexIt) {
+ const std::string& reqTestName = tests[*indexIt].Name;
+ if (std::find(p.Depends.begin(), p.Depends.end(), reqTestName) ==
+ p.Depends.end()) {
+ p.Depends.push_back(reqTestName);
+ }
+ }
+ }
+
+ // Ensure fixture cleanup tests always run after their setup tests, even
+ // if no other test cases require the fixture
+ cIt = setupFixturesAdded.find(fixture);
+ if (cIt != setupFixturesAdded.end()) {
+ const std::vector<size_t>& indices = cIt->second;
+ for (std::vector<size_t>::const_iterator indexIt = indices.begin();
+ indexIt != indices.end(); ++indexIt) {
+ const std::string& setupTestName = tests[*indexIt].Name;
+ if (std::find(p.Depends.begin(), p.Depends.end(), setupTestName) ==
+ p.Depends.end()) {
+ p.Depends.push_back(setupTestName);
+ }
+ }
+ }
+ }
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Added "
+ << fixtureTestsAdded
+ << " tests to meet fixture requirements" << std::endl,
+ this->Quiet);
+}
+
+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())
- {
+ if (max < p.Name.size()) {
max = p.Name.size();
- }
}
- if(static_cast<std::string::size_type>(this->CTest->GetMaxTestNameWidth())
- != max)
- {
+ }
+ if (static_cast<std::string::size_type>(
+ this->CTest->GetMaxTestNameWidth()) != max) {
this->CTest->SetMaxTestNameWidth(static_cast<int>(max));
- }
+ }
}
-bool cmCTestTestHandler::GetValue(const char* tag,
- int& value,
- std::ifstream& fin)
+bool cmCTestTestHandler::GetValue(const char* tag, int& value,
+ std::istream& fin)
{
std::string line;
bool ret = true;
cmSystemTools::GetLineFromStream(fin, line);
- if(line == tag)
- {
+ if (line == tag) {
fin >> value;
ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
- }
- else
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "parse error: missing tag: "
- << tag << " found [" << line << "]" << std::endl);
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "parse error: missing tag: "
+ << tag << " found [" << line << "]" << std::endl);
ret = false;
- }
+ }
return ret;
}
-bool cmCTestTestHandler::GetValue(const char* tag,
- double& value,
- std::ifstream& fin)
+bool cmCTestTestHandler::GetValue(const char* tag, double& value,
+ std::istream& fin)
{
std::string line;
cmSystemTools::GetLineFromStream(fin, line);
bool ret = true;
- if(line == tag)
- {
+ if (line == tag) {
fin >> value;
ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
- }
- else
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "parse error: missing tag: "
- << tag << " found [" << line << "]" << std::endl);
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "parse error: missing tag: "
+ << tag << " found [" << line << "]" << std::endl);
ret = false;
- }
+ }
return ret;
}
-bool cmCTestTestHandler::GetValue(const char* tag,
- bool& value,
- std::ifstream& fin)
+bool cmCTestTestHandler::GetValue(const char* tag, bool& value,
+ std::istream& fin)
{
std::string line;
cmSystemTools::GetLineFromStream(fin, line);
bool ret = true;
- if(line == tag)
- {
+ if (line == tag) {
#ifdef __HAIKU__
int tmp = 0;
fin >> tmp;
value = false;
- if(tmp)
- {
+ if (tmp) {
value = true;
- }
+ }
#else
fin >> value;
#endif
ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
- }
- else
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "parse error: missing tag: "
- << tag << " found [" << line << "]" << std::endl);
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "parse error: missing tag: "
+ << tag << " found [" << line << "]" << std::endl);
ret = false;
- }
+ }
return ret;
}
-bool cmCTestTestHandler::GetValue(const char* tag,
- size_t& value,
- std::ifstream& fin)
+bool cmCTestTestHandler::GetValue(const char* tag, size_t& value,
+ std::istream& fin)
{
std::string line;
cmSystemTools::GetLineFromStream(fin, line);
bool ret = true;
- if(line == tag)
- {
+ if (line == tag) {
fin >> value;
ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
- }
- else
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "parse error: missing tag: "
- << tag << " found [" << line.c_str() << "]" << std::endl);
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "parse error: missing tag: "
+ << tag << " found [" << line << "]" << std::endl);
ret = false;
- }
+ }
return ret;
}
-bool cmCTestTestHandler::GetValue(const char* tag,
- std::string& value,
- std::ifstream& fin)
+bool cmCTestTestHandler::GetValue(const char* tag, std::string& value,
+ std::istream& fin)
{
std::string line;
cmSystemTools::GetLineFromStream(fin, line);
bool ret = true;
- if(line == tag)
- {
- ret = cmSystemTools::GetLineFromStream(fin, value);
- }
- else
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "parse error: missing tag: "
- << tag << " found [" << line << "]" << std::endl);
+ if (line == tag) {
+ ret = cmSystemTools::GetLineFromStream(fin, value);
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "parse error: missing tag: "
+ << tag << " found [" << line << "]" << std::endl);
ret = false;
- }
+ }
return ret;
}
-//---------------------------------------------------------------------
-void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
- std::vector<cmStdString> &failed)
+void cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed,
+ std::vector<std::string>& failed)
{
this->ComputeTestList();
this->StartTest = this->CTest->CurrentTime();
this->StartTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
double elapsed_time_start = cmSystemTools::GetTime();
- cmCTestMultiProcessHandler* parallel = this->CTest->GetBatchJobs() ?
- new cmCTestBatchTestHandler : new cmCTestMultiProcessHandler;
+ cmCTestMultiProcessHandler* parallel = this->CTest->GetBatchJobs()
+ ? new cmCTestBatchTestHandler
+ : new cmCTestMultiProcessHandler;
parallel->SetCTest(this->CTest);
parallel->SetParallelLevel(this->CTest->GetParallelLevel());
parallel->SetTestHandler(this);
-
- *this->LogFile << "Start testing: "
- << this->CTest->CurrentTime() << std::endl
+ parallel->SetQuiet(this->Quiet);
+ if (this->TestLoad > 0) {
+ parallel->SetTestLoad(this->TestLoad);
+ } else {
+ parallel->SetTestLoad(this->CTest->GetTestLoad());
+ }
+
+ *this->LogFile
+ << "Start testing: " << this->CTest->CurrentTime() << std::endl
<< "----------------------------------------------------------"
<< std::endl;
@@ -1041,320 +1214,271 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
cmCTestMultiProcessHandler::PropertiesMap properties;
bool randomSchedule = this->CTest->GetScheduleType() == "Random";
- if(randomSchedule)
- {
- srand((unsigned)time(0));
- }
+ if (randomSchedule) {
+ srand((unsigned)time(CM_NULLPTR));
+ }
for (ListOfTests::iterator it = this->TestList.begin();
- it != this->TestList.end(); ++it)
- {
+ it != this->TestList.end(); ++it) {
cmCTestTestProperties& p = *it;
cmCTestMultiProcessHandler::TestSet depends;
- if(randomSchedule)
- {
+ if (randomSchedule) {
p.Cost = static_cast<float>(rand());
- }
+ }
- if(p.Timeout == 0 && this->CTest->GetGlobalTimeout() != 0)
- {
+ if (p.Timeout == 0 && this->CTest->GetGlobalTimeout() != 0) {
p.Timeout = this->CTest->GetGlobalTimeout();
- }
+ }
- if(p.Depends.size())
- {
- for(std::vector<std::string>::iterator i = p.Depends.begin();
- i != p.Depends.end(); ++i)
- {
- for(ListOfTests::iterator it2 = this->TestList.begin();
- it2 != this->TestList.end(); ++it2)
- {
- if(it2->Name == *i)
- {
+ if (!p.Depends.empty()) {
+ for (std::vector<std::string>::iterator i = p.Depends.begin();
+ i != p.Depends.end(); ++i) {
+ for (ListOfTests::iterator it2 = this->TestList.begin();
+ it2 != this->TestList.end(); ++it2) {
+ if (it2->Name == *i) {
depends.insert(it2->Index);
break; // break out of test loop as name can only match 1
- }
}
}
}
+ }
tests[it->Index] = depends;
properties[it->Index] = &*it;
- }
+ }
parallel->SetTests(tests, properties);
parallel->SetPassFailVectors(&passed, &failed);
this->TestResults.clear();
parallel->SetTestResults(&this->TestResults);
- if(this->CTest->ShouldPrintLabels())
- {
+ if (this->CTest->ShouldPrintLabels()) {
parallel->PrintLabels();
- }
- else if(this->CTest->GetShowOnly())
- {
+ } else if (this->CTest->GetShowOnly()) {
parallel->PrintTestList();
- }
- else
- {
+ } else {
parallel->RunTests();
- }
+ }
delete parallel;
this->EndTest = this->CTest->CurrentTime();
this->EndTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
this->ElapsedTestingTime = cmSystemTools::GetTime() - elapsed_time_start;
- *this->LogFile << "End testing: "
- << this->CTest->CurrentTime() << std::endl;
+ *this->LogFile << "End testing: " << this->CTest->CurrentTime() << std::endl;
}
-//----------------------------------------------------------------------
-void cmCTestTestHandler::GenerateTestCommand(std::vector<std::string>&, int)
+void cmCTestTestHandler::GenerateTestCommand(
+ std::vector<std::string>& /*unused*/, int /*unused*/)
{
}
-//----------------------------------------------------------------------
-void cmCTestTestHandler::GenerateDartOutput(std::ostream& os)
+void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml)
{
- if ( !this->CTest->GetProduceXML() )
- {
+ if (!this->CTest->GetProduceXML()) {
return;
- }
+ }
- this->CTest->StartXML(os, this->AppendXML);
- os << "<Testing>\n"
- << "\t<StartDateTime>" << this->StartTest << "</StartDateTime>\n"
- << "\t<StartTestTime>" << this->StartTestTime << "</StartTestTime>\n"
- << "\t<TestList>\n";
+ this->CTest->StartXML(xml, this->AppendXML);
+ xml.StartElement("Testing");
+ xml.Element("StartDateTime", this->StartTest);
+ xml.Element("StartTestTime", this->StartTestTime);
+ xml.StartElement("TestList");
cmCTestTestHandler::TestResultsVector::size_type cc;
- for ( cc = 0; cc < this->TestResults.size(); cc ++ )
- {
- cmCTestTestResult *result = &this->TestResults[cc];
+ for (cc = 0; cc < this->TestResults.size(); cc++) {
+ cmCTestTestResult* result = &this->TestResults[cc];
std::string testPath = result->Path + "/" + result->Name;
- os << "\t\t<Test>" << cmXMLSafe(
- this->CTest->GetShortPathToFile(testPath.c_str()))
- << "</Test>" << std::endl;
- }
- os << "\t</TestList>\n";
- for ( cc = 0; cc < this->TestResults.size(); cc ++ )
- {
- cmCTestTestResult *result = &this->TestResults[cc];
- this->WriteTestResultHeader(os, result);
- os << "\t\t<Results>" << std::endl;
- if ( result->Status != cmCTestTestHandler::NOT_RUN )
- {
- if ( result->Status != cmCTestTestHandler::COMPLETED ||
- result->ReturnValue )
- {
- os << "\t\t\t<NamedMeasurement type=\"text/string\" "
- "name=\"Exit Code\"><Value>"
- << cmXMLSafe(this->GetTestStatus(result->Status))
- << "</Value>"
- "</NamedMeasurement>\n"
- << "\t\t\t<NamedMeasurement type=\"text/string\" "
- "name=\"Exit Value\"><Value>"
- << result->ReturnValue
- << "</Value></NamedMeasurement>"
- << std::endl;
- }
- os << result->RegressionImages;
- os << "\t\t\t<NamedMeasurement type=\"numeric/double\" "
- << "name=\"Execution Time\"><Value>"
- << result->ExecutionTime
- << "</Value></NamedMeasurement>\n";
- if(result->Reason.size())
- {
+ xml.Element("Test", this->CTest->GetShortPathToFile(testPath.c_str()));
+ }
+ xml.EndElement(); // TestList
+ for (cc = 0; cc < this->TestResults.size(); cc++) {
+ cmCTestTestResult* result = &this->TestResults[cc];
+ this->WriteTestResultHeader(xml, result);
+ xml.StartElement("Results");
+
+ if (result->Status != cmCTestTestHandler::NOT_RUN) {
+ if (result->Status != cmCTestTestHandler::COMPLETED ||
+ result->ReturnValue) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", "Exit Code");
+ xml.Element("Value", this->GetTestStatus(result->Status));
+ xml.EndElement(); // NamedMeasurement
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", "Exit Value");
+ xml.Element("Value", result->ReturnValue);
+ xml.EndElement(); // NamedMeasurement
+ }
+ this->GenerateRegressionImages(xml, result->DartString);
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "numeric/double");
+ xml.Attribute("name", "Execution Time");
+ xml.Element("Value", result->ExecutionTime);
+ xml.EndElement(); // NamedMeasurement
+ if (!result->Reason.empty()) {
const char* reasonType = "Pass Reason";
- if(result->Status != cmCTestTestHandler::COMPLETED &&
- result->Status != cmCTestTestHandler::NOT_RUN)
- {
+ if (result->Status != cmCTestTestHandler::COMPLETED) {
reasonType = "Fail Reason";
- }
- os << "\t\t\t<NamedMeasurement type=\"text/string\" "
- << "name=\"" << reasonType << "\"><Value>"
- << cmXMLSafe(result->Reason)
- << "</Value></NamedMeasurement>\n";
}
- os
- << "\t\t\t<NamedMeasurement type=\"text/string\" "
- << "name=\"Completion Status\"><Value>"
- << cmXMLSafe(result->CompletionStatus)
- << "</Value></NamedMeasurement>\n";
- }
- os
- << "\t\t\t<NamedMeasurement type=\"text/string\" "
- << "name=\"Command Line\"><Value>"
- << cmXMLSafe(result->FullCommandLine)
- << "</Value></NamedMeasurement>\n";
- std::map<cmStdString,cmStdString>::iterator measureIt;
- for ( measureIt = result->Properties->Measurements.begin();
- measureIt != result->Properties->Measurements.end();
- ++ measureIt )
- {
- os
- << "\t\t\t<NamedMeasurement type=\"text/string\" "
- << "name=\"" << measureIt->first.c_str() << "\"><Value>"
- << cmXMLSafe(measureIt->second)
- << "</Value></NamedMeasurement>\n";
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", reasonType);
+ xml.Element("Value", result->Reason);
+ xml.EndElement(); // NamedMeasurement
}
- os
- << "\t\t\t<Measurement>\n"
- << "\t\t\t\t<Value"
- << (result->CompressOutput ?
- " encoding=\"base64\" compression=\"gzip\">"
- : ">");
- os << cmXMLSafe(result->Output);
- os
- << "</Value>\n"
- << "\t\t\t</Measurement>\n"
- << "\t\t</Results>\n";
-
- this->AttachFiles(os, result);
- this->WriteTestResultFooter(os, result);
- }
-
- os << "\t<EndDateTime>" << this->EndTest << "</EndDateTime>\n"
- << "\t<EndTestTime>" << this->EndTestTime << "</EndTestTime>\n"
- << "<ElapsedMinutes>"
- << static_cast<int>(this->ElapsedTestingTime/6)/10.0
- << "</ElapsedMinutes>"
- << "</Testing>" << std::endl;
- this->CTest->EndXML(os);
+ }
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", "Completion Status");
+ xml.Element("Value", result->CompletionStatus);
+ xml.EndElement(); // NamedMeasurement
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", "Command Line");
+ xml.Element("Value", result->FullCommandLine);
+ xml.EndElement(); // NamedMeasurement
+ std::map<std::string, std::string>::iterator measureIt;
+ for (measureIt = result->Properties->Measurements.begin();
+ measureIt != result->Properties->Measurements.end(); ++measureIt) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", measureIt->first);
+ xml.Element("Value", measureIt->second);
+ xml.EndElement(); // NamedMeasurement
+ }
+ xml.StartElement("Measurement");
+ xml.StartElement("Value");
+ if (result->CompressOutput) {
+ xml.Attribute("encoding", "base64");
+ xml.Attribute("compression", "gzip");
+ }
+ xml.Content(result->Output);
+ xml.EndElement(); // Value
+ xml.EndElement(); // Measurement
+ xml.EndElement(); // Results
+
+ this->AttachFiles(xml, result);
+ this->WriteTestResultFooter(xml, result);
+ }
+
+ xml.Element("EndDateTime", this->EndTest);
+ xml.Element("EndTestTime", this->EndTestTime);
+ xml.Element("ElapsedMinutes",
+ static_cast<int>(this->ElapsedTestingTime / 6) / 10.0);
+ xml.EndElement(); // Testing
+ this->CTest->EndXML(xml);
}
-//----------------------------------------------------------------------------
-void cmCTestTestHandler::WriteTestResultHeader(std::ostream& os,
+void cmCTestTestHandler::WriteTestResultHeader(cmXMLWriter& xml,
cmCTestTestResult* result)
{
- os << "\t<Test Status=\"";
- if ( result->Status == cmCTestTestHandler::COMPLETED )
- {
- os << "passed";
- }
- else if ( result->Status == cmCTestTestHandler::NOT_RUN )
- {
- os << "notrun";
- }
- else
- {
- os << "failed";
- }
+ xml.StartElement("Test");
+ if (result->Status == cmCTestTestHandler::COMPLETED) {
+ xml.Attribute("Status", "passed");
+ } else if (result->Status == cmCTestTestHandler::NOT_RUN) {
+ xml.Attribute("Status", "notrun");
+ } else {
+ xml.Attribute("Status", "failed");
+ }
std::string testPath = result->Path + "/" + result->Name;
- os << "\">\n"
- << "\t\t<Name>" << cmXMLSafe(result->Name) << "</Name>\n"
- << "\t\t<Path>" << cmXMLSafe(
- this->CTest->GetShortPathToFile(result->Path.c_str())) << "</Path>\n"
- << "\t\t<FullName>" << cmXMLSafe(
- this->CTest->GetShortPathToFile(testPath.c_str())) << "</FullName>\n"
- << "\t\t<FullCommandLine>"
- << cmXMLSafe(result->FullCommandLine)
- << "</FullCommandLine>\n";
+ xml.Element("Name", result->Name);
+ xml.Element("Path", this->CTest->GetShortPathToFile(result->Path.c_str()));
+ xml.Element("FullName", this->CTest->GetShortPathToFile(testPath.c_str()));
+ xml.Element("FullCommandLine", result->FullCommandLine);
}
-//----------------------------------------------------------------------------
-void cmCTestTestHandler::WriteTestResultFooter(std::ostream& os,
+void cmCTestTestHandler::WriteTestResultFooter(cmXMLWriter& xml,
cmCTestTestResult* result)
{
- if(!result->Properties->Labels.empty())
- {
- os << "\t\t<Labels>\n";
+ if (!result->Properties->Labels.empty()) {
+ xml.StartElement("Labels");
std::vector<std::string> const& labels = result->Properties->Labels;
- for(std::vector<std::string>::const_iterator li = labels.begin();
- li != labels.end(); ++li)
- {
- os << "\t\t\t<Label>" << cmXMLSafe(*li) << "</Label>\n";
- }
- os << "\t\t</Labels>\n";
+ for (std::vector<std::string>::const_iterator li = labels.begin();
+ li != labels.end(); ++li) {
+ xml.Element("Label", *li);
}
+ xml.EndElement(); // Labels
+ }
- os
- << "\t</Test>" << std::endl;
+ xml.EndElement(); // Test
}
-//----------------------------------------------------------------------
-void cmCTestTestHandler::AttachFiles(std::ostream& os,
+void cmCTestTestHandler::AttachFiles(cmXMLWriter& xml,
cmCTestTestResult* result)
{
- if(result->Status != cmCTestTestHandler::COMPLETED
- && result->Properties->AttachOnFail.size())
- {
+ if (result->Status != cmCTestTestHandler::COMPLETED &&
+ !result->Properties->AttachOnFail.empty()) {
result->Properties->AttachedFiles.insert(
result->Properties->AttachedFiles.end(),
result->Properties->AttachOnFail.begin(),
result->Properties->AttachOnFail.end());
- }
- for(std::vector<std::string>::const_iterator file =
- result->Properties->AttachedFiles.begin();
- file != result->Properties->AttachedFiles.end(); ++file)
- {
- std::string base64 = this->CTest->Base64GzipEncodeFile(*file);
+ }
+ for (std::vector<std::string>::const_iterator file =
+ result->Properties->AttachedFiles.begin();
+ file != result->Properties->AttachedFiles.end(); ++file) {
+ const std::string& base64 = this->CTest->Base64GzipEncodeFile(*file);
std::string fname = cmSystemTools::GetFilenameName(*file);
- os << "\t\t<NamedMeasurement name=\"Attached File\" encoding=\"base64\" "
- "compression=\"tar/gzip\" filename=\"" << fname << "\" type=\"file\">"
- "\n\t\t\t<Value>\n\t\t\t"
- << base64
- << "\n\t\t\t</Value>\n\t\t</NamedMeasurement>\n";
- }
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("name", "Attached File");
+ xml.Attribute("encoding", "base64");
+ xml.Attribute("compression", "tar/gzip");
+ xml.Attribute("filename", fname);
+ xml.Attribute("type", "file");
+ xml.Element("Value", base64);
+ xml.EndElement(); // NamedMeasurement
+ }
}
-//----------------------------------------------------------------------
-int cmCTestTestHandler::ExecuteCommands(std::vector<cmStdString>& vec)
+int cmCTestTestHandler::ExecuteCommands(std::vector<std::string>& vec)
{
- std::vector<cmStdString>::iterator it;
- for ( it = vec.begin(); it != vec.end(); ++it )
- {
+ std::vector<std::string>::iterator it;
+ for (it = vec.begin(); it != vec.end(); ++it) {
int retVal = 0;
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run command: " << *it
- << std::endl);
- if ( !cmSystemTools::RunSingleCommand(it->c_str(), 0, &retVal, 0,
- cmSystemTools::OUTPUT_MERGE
- /*this->Verbose*/) || retVal != 0 )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Problem running command: "
- << *it << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Run command: " << *it << std::endl, this->Quiet);
+ if (!cmSystemTools::RunSingleCommand(it->c_str(), CM_NULLPTR, CM_NULLPTR,
+ &retVal, CM_NULLPTR,
+ cmSystemTools::OUTPUT_MERGE
+ /*this->Verbose*/) ||
+ retVal != 0) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Problem running command: " << *it << std::endl);
return 0;
- }
}
+ }
return 1;
}
-
-//----------------------------------------------------------------------
// Find the appropriate executable to run for a test
-std::string cmCTestTestHandler::FindTheExecutable(const char *exe)
+std::string cmCTestTestHandler::FindTheExecutable(const char* exe)
{
std::string resConfig;
std::vector<std::string> extraPaths;
std::vector<std::string> failedPaths;
- if(strcmp(exe, "NOT_AVAILABLE") == 0)
- {
+ if (strcmp(exe, "NOT_AVAILABLE") == 0) {
return exe;
- }
- return cmCTestTestHandler::FindExecutable(this->CTest,
- exe, resConfig,
- extraPaths,
- failedPaths);
+ }
+ return cmCTestTestHandler::FindExecutable(this->CTest, exe, resConfig,
+ extraPaths, failedPaths);
}
// add additional configurations to the search path
-void cmCTestTestHandler
-::AddConfigurations(cmCTest *ctest,
- std::vector<std::string> &attempted,
- std::vector<std::string> &attemptedConfigs,
- std::string filepath,
- std::string &filename)
+void cmCTestTestHandler::AddConfigurations(
+ cmCTest* ctest, std::vector<std::string>& attempted,
+ std::vector<std::string>& attemptedConfigs, std::string filepath,
+ std::string& filename)
{
std::string tempPath;
- if (filepath.size() &&
- filepath[filepath.size()-1] != '/')
- {
+ if (!filepath.empty() && filepath[filepath.size() - 1] != '/') {
filepath += "/";
- }
+ }
tempPath = filepath + filename;
attempted.push_back(tempPath);
attemptedConfigs.push_back("");
- if(ctest->GetConfigType().size())
- {
+ if (!ctest->GetConfigType().empty()) {
tempPath = filepath;
tempPath += ctest->GetConfigType();
tempPath += "/";
@@ -1369,9 +1493,7 @@ void cmCTestTestHandler
tempPath += filename;
attempted.push_back(tempPath);
attemptedConfigs.push_back(ctest->GetConfigType());
- }
- else
- {
+ } else {
// no config specified - try some options...
tempPath = filepath;
tempPath += "Release/";
@@ -1403,247 +1525,193 @@ void cmCTestTestHandler
tempPath += filename;
attempted.push_back(tempPath);
attemptedConfigs.push_back("Deployment");
- }
+ }
}
-
-//----------------------------------------------------------------------
// Find the appropriate executable to run for a test
-std::string cmCTestTestHandler
-::FindExecutable(cmCTest *ctest,
- const char *testCommand,
- std::string &resultingConfig,
- std::vector<std::string> &extraPaths,
- std::vector<std::string> &failed)
+std::string cmCTestTestHandler::FindExecutable(
+ cmCTest* ctest, const char* testCommand, std::string& resultingConfig,
+ std::vector<std::string>& extraPaths, std::vector<std::string>& failed)
{
// now run the compiled test if we can find it
std::vector<std::string> attempted;
std::vector<std::string> attemptedConfigs;
std::string tempPath;
- std::string filepath =
- cmSystemTools::GetFilenamePath(testCommand);
- std::string filename =
- cmSystemTools::GetFilenameName(testCommand);
+ std::string filepath = cmSystemTools::GetFilenamePath(testCommand);
+ std::string filename = cmSystemTools::GetFilenameName(testCommand);
- cmCTestTestHandler::AddConfigurations(ctest, attempted,
- attemptedConfigs,
- filepath,filename);
+ cmCTestTestHandler::AddConfigurations(ctest, attempted, attemptedConfigs,
+ filepath, filename);
// even if a fullpath was specified also try it relative to the current
// directory
- if (filepath.size() && filepath[0] == '/')
- {
- std::string localfilepath = filepath.substr(1,filepath.size()-1);
- cmCTestTestHandler::AddConfigurations(ctest, attempted,
- attemptedConfigs,
- localfilepath,filename);
- }
-
+ if (!filepath.empty() && filepath[0] == '/') {
+ std::string localfilepath = filepath.substr(1, filepath.size() - 1);
+ cmCTestTestHandler::AddConfigurations(ctest, attempted, attemptedConfigs,
+ localfilepath, filename);
+ }
// if extraPaths are provided and we were not passed a full path, try them,
// try any extra paths
- if (filepath.size() == 0)
- {
- for (unsigned int i = 0; i < extraPaths.size(); ++i)
- {
+ if (filepath.empty()) {
+ for (unsigned int i = 0; i < extraPaths.size(); ++i) {
std::string filepathExtra =
cmSystemTools::GetFilenamePath(extraPaths[i]);
std::string filenameExtra =
cmSystemTools::GetFilenameName(extraPaths[i]);
- cmCTestTestHandler::AddConfigurations(ctest,attempted,
- attemptedConfigs,
- filepathExtra,
- filenameExtra);
- }
+ cmCTestTestHandler::AddConfigurations(ctest, attempted, attemptedConfigs,
+ filepathExtra, filenameExtra);
}
+ }
// store the final location in fullPath
std::string fullPath;
// now look in the paths we specified above
- for(unsigned int ai=0;
- ai < attempted.size() && fullPath.size() == 0; ++ai)
- {
+ for (unsigned int ai = 0; ai < attempted.size() && fullPath.empty(); ++ai) {
// first check without exe extension
- if(cmSystemTools::FileExists(attempted[ai].c_str())
- && !cmSystemTools::FileIsDirectory(attempted[ai].c_str()))
- {
- fullPath = cmSystemTools::CollapseFullPath(attempted[ai].c_str());
+ if (cmSystemTools::FileExists(attempted[ai].c_str()) &&
+ !cmSystemTools::FileIsDirectory(attempted[ai])) {
+ fullPath = cmSystemTools::CollapseFullPath(attempted[ai]);
resultingConfig = attemptedConfigs[ai];
- }
+ }
// then try with the exe extension
- else
- {
- failed.push_back(attempted[ai].c_str());
+ else {
+ failed.push_back(attempted[ai]);
tempPath = attempted[ai];
tempPath += cmSystemTools::GetExecutableExtension();
- if(cmSystemTools::FileExists(tempPath.c_str())
- && !cmSystemTools::FileIsDirectory(tempPath.c_str()))
- {
- fullPath = cmSystemTools::CollapseFullPath(tempPath.c_str());
+ if (cmSystemTools::FileExists(tempPath.c_str()) &&
+ !cmSystemTools::FileIsDirectory(tempPath)) {
+ fullPath = cmSystemTools::CollapseFullPath(tempPath);
resultingConfig = attemptedConfigs[ai];
- }
- else
- {
- failed.push_back(tempPath.c_str());
- }
+ } else {
+ failed.push_back(tempPath);
}
}
+ }
// if everything else failed, check the users path, but only if a full path
// wasn't specified
- if (fullPath.size() == 0 && filepath.size() == 0)
- {
+ if (fullPath.empty() && filepath.empty()) {
std::string path = cmSystemTools::FindProgram(filename.c_str());
- if (path != "")
- {
+ if (path != "") {
resultingConfig = "";
return path;
- }
}
- if(fullPath.size() == 0)
- {
- cmCTestLog(ctest, HANDLER_OUTPUT,
- "Could not find executable " << testCommand << "\n"
- << "Looked in the following places:\n");
- for(std::vector<std::string>::iterator i = failed.begin();
- i != failed.end(); ++i)
- {
- cmCTestLog(ctest, HANDLER_OUTPUT,
- i->c_str() << "\n");
- }
+ }
+ if (fullPath.empty()) {
+ cmCTestLog(ctest, HANDLER_OUTPUT, "Could not find executable "
+ << testCommand << "\n"
+ << "Looked in the following places:\n");
+ for (std::vector<std::string>::iterator i = failed.begin();
+ i != failed.end(); ++i) {
+ cmCTestLog(ctest, HANDLER_OUTPUT, *i << "\n");
}
+ }
return fullPath;
}
-
-//----------------------------------------------------------------------
void cmCTestTestHandler::GetListOfTests()
{
- if ( !this->IncludeLabelRegExp.empty() )
- {
- this->IncludeLabelRegularExpression.
- compile(this->IncludeLabelRegExp.c_str());
- }
- if ( !this->IncludeLabelRegExp.empty() )
- {
- this->ExcludeLabelRegularExpression.
- compile(this->ExcludeLabelRegExp.c_str());
- }
- if ( !this->IncludeRegExp.empty() )
- {
+ if (!this->IncludeLabelRegExp.empty()) {
+ this->IncludeLabelRegularExpression.compile(
+ this->IncludeLabelRegExp.c_str());
+ }
+ if (!this->ExcludeLabelRegExp.empty()) {
+ this->ExcludeLabelRegularExpression.compile(
+ this->ExcludeLabelRegExp.c_str());
+ }
+ if (!this->IncludeRegExp.empty()) {
this->IncludeTestsRegularExpression.compile(this->IncludeRegExp.c_str());
- }
- if ( !this->ExcludeRegExp.empty() )
- {
+ }
+ if (!this->ExcludeRegExp.empty()) {
this->ExcludeTestsRegularExpression.compile(this->ExcludeRegExp.c_str());
- }
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Constructing a list of tests" << std::endl);
- cmake cm;
- cmGlobalGenerator gg;
- gg.SetCMakeInstance(&cm);
- cmsys::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator());
- cmMakefile *mf = lg->GetMakefile();
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Constructing a list of tests" << std::endl, this->Quiet);
+ cmake cm(cmake::RoleScript);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator gg(&cm);
+ CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(&gg, cm.GetCurrentSnapshot()));
mf->AddDefinition("CTEST_CONFIGURATION_TYPE",
- this->CTest->GetConfigType().c_str());
+ this->CTest->GetConfigType().c_str());
// Add handler for ADD_TEST
cmCTestAddTestCommand* newCom1 = new cmCTestAddTestCommand;
newCom1->TestHandler = this;
- cm.AddCommand(newCom1);
+ cm.GetState()->AddBuiltinCommand("add_test", newCom1);
// Add handler for SUBDIRS
- cmCTestSubdirCommand* newCom2 =
- new cmCTestSubdirCommand;
+ cmCTestSubdirCommand* newCom2 = new cmCTestSubdirCommand;
newCom2->TestHandler = this;
- cm.AddCommand(newCom2);
+ cm.GetState()->AddBuiltinCommand("subdirs", newCom2);
// Add handler for ADD_SUBDIRECTORY
- cmCTestAddSubdirectoryCommand* newCom3 =
- new cmCTestAddSubdirectoryCommand;
+ cmCTestAddSubdirectoryCommand* newCom3 = new cmCTestAddSubdirectoryCommand;
newCom3->TestHandler = this;
- cm.AddCommand(newCom3);
+ cm.GetState()->AddBuiltinCommand("add_subdirectory", newCom3);
- // Add handler for SET_SOURCE_FILES_PROPERTIES
- cmCTestSetTestsPropertiesCommand* newCom4
- = new cmCTestSetTestsPropertiesCommand;
+ // Add handler for SET_TESTS_PROPERTIES
+ cmCTestSetTestsPropertiesCommand* newCom4 =
+ new cmCTestSetTestsPropertiesCommand;
newCom4->TestHandler = this;
- cm.AddCommand(newCom4);
+ cm.GetState()->AddBuiltinCommand("set_tests_properties", newCom4);
const char* testFilename;
- if( cmSystemTools::FileExists("CTestTestfile.cmake") )
- {
+ if (cmSystemTools::FileExists("CTestTestfile.cmake")) {
// does the CTestTestfile.cmake exist ?
testFilename = "CTestTestfile.cmake";
- }
- else if( cmSystemTools::FileExists("DartTestfile.txt") )
- {
+ } else if (cmSystemTools::FileExists("DartTestfile.txt")) {
// does the DartTestfile.txt exist ?
testFilename = "DartTestfile.txt";
- }
- else
- {
+ } else {
return;
- }
+ }
- if ( !mf->ReadListFile(0, testFilename) )
- {
+ if (!mf->ReadListFile(testFilename)) {
return;
- }
- if ( cmSystemTools::GetErrorOccuredFlag() )
- {
+ }
+ if (cmSystemTools::GetErrorOccuredFlag()) {
return;
- }
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Done constructing a list of tests" << std::endl);
+ }
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Done constructing a list of tests" << std::endl,
+ this->Quiet);
}
-//----------------------------------------------------------------------
void cmCTestTestHandler::UseIncludeRegExp()
{
this->UseIncludeRegExpFlag = true;
}
-//----------------------------------------------------------------------
void cmCTestTestHandler::UseExcludeRegExp()
{
this->UseExcludeRegExpFlag = true;
- this->UseExcludeRegExpFirst = this->UseIncludeRegExpFlag ? false : true;
+ this->UseExcludeRegExpFirst = !this->UseIncludeRegExpFlag;
}
-//----------------------------------------------------------------------
const char* cmCTestTestHandler::GetTestStatus(int status)
{
- static const char statuses[][100] = {
- "Not Run",
- "Timeout",
- "SEGFAULT",
- "ILLEGAL",
- "INTERRUPT",
- "NUMERICAL",
- "OTHER_FAULT",
- "Failed",
- "BAD_COMMAND",
- "Completed"
- };
-
- if ( status < cmCTestTestHandler::NOT_RUN ||
- status > cmCTestTestHandler::COMPLETED )
- {
+ static const char* statuses[] = { "Not Run", "Timeout", "SEGFAULT",
+ "ILLEGAL", "INTERRUPT", "NUMERICAL",
+ "OTHER_FAULT", "Failed", "BAD_COMMAND",
+ "Completed" };
+
+ if (status < cmCTestTestHandler::NOT_RUN ||
+ status > cmCTestTestHandler::COMPLETED) {
return "No Status";
- }
+ }
return statuses[status];
}
-//----------------------------------------------------------------------
void cmCTestTestHandler::ExpandTestsToRunInformation(size_t numTests)
{
- if (this->TestsToRunString.empty())
- {
+ if (this->TestsToRunString.empty()) {
return;
- }
+ }
int start;
int end = -1;
@@ -1651,311 +1719,317 @@ void cmCTestTestHandler::ExpandTestsToRunInformation(size_t numTests)
std::string::size_type pos = 0;
std::string::size_type pos2;
// read start
- if(GetNextNumber(this->TestsToRunString, start, pos, pos2))
- {
+ if (GetNextNumber(this->TestsToRunString, start, pos, pos2)) {
// read end
- if(GetNextNumber(this->TestsToRunString, end, pos, pos2))
- {
+ if (GetNextNumber(this->TestsToRunString, end, pos, pos2)) {
// read stride
- if(GetNextRealNumber(this->TestsToRunString, stride, pos, pos2))
- {
- int val =0;
+ if (GetNextRealNumber(this->TestsToRunString, stride, pos, pos2)) {
+ int val = 0;
// now read specific numbers
- while(GetNextNumber(this->TestsToRunString, val, pos, pos2))
- {
+ while (GetNextNumber(this->TestsToRunString, val, pos, pos2)) {
this->TestsToRun.push_back(val);
- }
- this->TestsToRun.push_back(val);
}
+ this->TestsToRun.push_back(val);
}
}
+ }
// if start is not specified then we assume we start at 1
- if(start == -1)
- {
+ if (start == -1) {
start = 1;
- }
+ }
// if end isnot specified then we assume we end with the last test
- if(end == -1)
- {
+ if (end == -1) {
end = static_cast<int>(numTests);
- }
+ }
// if the stride wasn't specified then it defaults to 1
- if(stride == -1)
- {
+ if (stride == -1) {
stride = 1;
- }
+ }
// if we have a range then add it
- if(end != -1 && start != -1 && stride > 0)
- {
+ if (end != -1 && start != -1 && stride > 0) {
int i = 0;
- while (i*stride + start <= end)
- {
- this->TestsToRun.push_back(static_cast<int>(i*stride+start));
+ while (i * stride + start <= end) {
+ this->TestsToRun.push_back(static_cast<int>(i * stride + start));
++i;
- }
}
+ }
// sort the array
std::sort(this->TestsToRun.begin(), this->TestsToRun.end(),
- std::less<int>());
+ std::less<int>());
// remove duplicates
std::vector<int>::iterator new_end =
std::unique(this->TestsToRun.begin(), this->TestsToRun.end());
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) == 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));
+ 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 != pattern) {
+ continue;
+ }
+ if (logName == "") {
+ logName = fileName;
+ } else {
+ // if multiple matching logs were found we use the most recently
+ // modified one.
+ int res;
+ cmSystemTools::FileTimeCompare(logName, fileName, &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 == std::string::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
+ << " while generating list of previously failed tests."
+ << std::endl);
+ }
+}
+
// Just for convenience
#define SPACE_REGEX "[ \t\r\n]"
-//----------------------------------------------------------------------
-std::string cmCTestTestHandler::GenerateRegressionImages(
- const std::string& xml)
+void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml,
+ const std::string& dart)
{
cmsys::RegularExpression twoattributes(
- "<DartMeasurement"
- SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
- SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
- SPACE_REGEX "*>([^<]*)</DartMeasurement>");
+ "<DartMeasurement" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>([^<]*)</DartMeasurement>");
cmsys::RegularExpression threeattributes(
- "<DartMeasurement"
- SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
- SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
- SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
- SPACE_REGEX "*>([^<]*)</DartMeasurement>");
+ "<DartMeasurement" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>([^<]*)</DartMeasurement>");
cmsys::RegularExpression fourattributes(
- "<DartMeasurement"
- SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
- SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
- SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
- SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
- SPACE_REGEX "*>([^<]*)</DartMeasurement>");
+ "<DartMeasurement" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>([^<]*)</DartMeasurement>");
cmsys::RegularExpression cdatastart(
- "<DartMeasurement"
- SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
- SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
- SPACE_REGEX "*>"
- SPACE_REGEX "*<!\\[CDATA\\[");
- cmsys::RegularExpression cdataend(
- "]]>"
- SPACE_REGEX "*</DartMeasurement>");
+ "<DartMeasurement" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>" SPACE_REGEX "*<!\\[CDATA\\[");
+ cmsys::RegularExpression cdataend("]]>" SPACE_REGEX "*</DartMeasurement>");
cmsys::RegularExpression measurementfile(
- "<DartMeasurementFile"
- SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
- SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
- SPACE_REGEX "*>([^<]*)</DartMeasurementFile>");
+ "<DartMeasurementFile" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX
+ "*>([^<]*)</DartMeasurementFile>");
- cmOStringStream ostr;
bool done = false;
- std::string cxml = xml;
- while ( ! done )
- {
- if ( twoattributes.find(cxml) )
- {
- ostr
- << "\t\t\t<NamedMeasurement"
- << " " << twoattributes.match(1) << "=\""
- << twoattributes.match(2) << "\""
- << " " << twoattributes.match(3) << "=\""
- << twoattributes.match(4) << "\""
- << "><Value>" << twoattributes.match(5)
- << "</Value></NamedMeasurement>"
- << std::endl;
+ std::string cxml = dart;
+ while (!done) {
+ if (twoattributes.find(cxml)) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(twoattributes.match(1).c_str(), twoattributes.match(2));
+ xml.Attribute(twoattributes.match(3).c_str(), twoattributes.match(4));
+ xml.Element("Value", twoattributes.match(5));
+ xml.EndElement();
cxml.erase(twoattributes.start(),
- twoattributes.end() - twoattributes.start());
- }
- else if ( threeattributes.find(cxml) )
- {
- ostr
- << "\t\t\t<NamedMeasurement"
- << " " << threeattributes.match(1) << "=\""
- << threeattributes.match(2) << "\""
- << " " << threeattributes.match(3) << "=\""
- << threeattributes.match(4) << "\""
- << " " << threeattributes.match(5) << "=\""
- << threeattributes.match(6) << "\""
- << "><Value>" << threeattributes.match(7)
- << "</Value></NamedMeasurement>"
- << std::endl;
+ twoattributes.end() - twoattributes.start());
+ } else if (threeattributes.find(cxml)) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(threeattributes.match(1).c_str(),
+ threeattributes.match(2));
+ xml.Attribute(threeattributes.match(3).c_str(),
+ threeattributes.match(4));
+ xml.Attribute(threeattributes.match(5).c_str(),
+ threeattributes.match(6));
+ xml.Element("Value", twoattributes.match(7));
+ xml.EndElement();
cxml.erase(threeattributes.start(),
- threeattributes.end() - threeattributes.start());
- }
- else if ( fourattributes.find(cxml) )
- {
- ostr
- << "\t\t\t<NamedMeasurement"
- << " " << fourattributes.match(1) << "=\""
- << fourattributes.match(2) << "\""
- << " " << fourattributes.match(3) << "=\""
- << fourattributes.match(4) << "\""
- << " " << fourattributes.match(5) << "=\""
- << fourattributes.match(6) << "\""
- << " " << fourattributes.match(7) << "=\""
- << fourattributes.match(8) << "\""
- << "><Value>" << fourattributes.match(9)
- << "</Value></NamedMeasurement>"
- << std::endl;
+ threeattributes.end() - threeattributes.start());
+ } else if (fourattributes.find(cxml)) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(fourattributes.match(1).c_str(), fourattributes.match(2));
+ xml.Attribute(fourattributes.match(3).c_str(), fourattributes.match(4));
+ xml.Attribute(fourattributes.match(5).c_str(), fourattributes.match(6));
+ xml.Attribute(fourattributes.match(7).c_str(), fourattributes.match(8));
+ xml.Element("Value", twoattributes.match(9));
+ xml.EndElement();
cxml.erase(fourattributes.start(),
- fourattributes.end() - fourattributes.start());
- }
- else if ( cdatastart.find(cxml) && cdataend.find(cxml) )
- {
- ostr
- << "\t\t\t<NamedMeasurement"
- << " " << cdatastart.match(1) << "=\""
- << cdatastart.match(2) << "\""
- << " " << cdatastart.match(3) << "=\""
- << cdatastart.match(4) << "\""
- << "><Value><![CDATA["
- << cxml.substr(cdatastart.end(), cdataend.start() - cdatastart.end())
- << "]]></Value></NamedMeasurement>"
- << std::endl;
- cxml.erase(cdatastart.start(),
- cdataend.end() - cdatastart.start());
- }
- else if ( measurementfile.find(cxml) )
- {
+ fourattributes.end() - fourattributes.start());
+ } else if (cdatastart.find(cxml) && cdataend.find(cxml)) {
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(cdatastart.match(1).c_str(), cdatastart.match(2));
+ xml.Attribute(cdatastart.match(3).c_str(), cdatastart.match(4));
+ xml.StartElement("Value");
+ xml.CData(
+ cxml.substr(cdatastart.end(), cdataend.start() - cdatastart.end()));
+ xml.EndElement(); // Value
+ xml.EndElement(); // NamedMeasurement
+ cxml.erase(cdatastart.start(), cdataend.end() - cdatastart.start());
+ } else if (measurementfile.find(cxml)) {
const std::string& filename =
cmCTest::CleanString(measurementfile.match(5));
- if ( cmSystemTools::FileExists(filename.c_str()) )
- {
- long len = cmSystemTools::FileLength(filename.c_str());
- if ( len == 0 )
- {
+ if (cmSystemTools::FileExists(filename.c_str())) {
+ long len = cmSystemTools::FileLength(filename);
+ if (len == 0) {
std::string k1 = measurementfile.match(1);
std::string v1 = measurementfile.match(2);
std::string k2 = measurementfile.match(3);
std::string v2 = measurementfile.match(4);
- if ( cmSystemTools::LowerCase(k1) == "type" )
- {
+ if (cmSystemTools::LowerCase(k1) == "type") {
v1 = "text/string";
- }
- if ( cmSystemTools::LowerCase(k2) == "type" )
- {
+ }
+ if (cmSystemTools::LowerCase(k2) == "type") {
v2 = "text/string";
- }
-
- ostr
- << "\t\t\t<NamedMeasurement"
- << " " << k1 << "=\"" << v1 << "\""
- << " " << k2 << "=\"" << v2 << "\""
- << " encoding=\"none\""
- << "><Value>Image " << filename.c_str()
- << " is empty</Value></NamedMeasurement>";
}
- else
- {
- std::ifstream ifs(filename.c_str(), std::ios::in
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(k1.c_str(), v1);
+ xml.Attribute(k2.c_str(), v2);
+ xml.Attribute("encoding", "none");
+ xml.Element("Value", "Image " + filename + " is empty");
+ xml.EndElement();
+ } else {
+ cmsys::ifstream ifs(filename.c_str(), std::ios::in
#ifdef _WIN32
- | std::ios::binary
+ | std::ios::binary
#endif
- );
- unsigned char *file_buffer = new unsigned char [ len + 1 ];
+ );
+ unsigned char* file_buffer = new unsigned char[len + 1];
ifs.read(reinterpret_cast<char*>(file_buffer), len);
- unsigned char *encoded_buffer
- = new unsigned char [ static_cast<int>(
- static_cast<double>(len) * 1.5 + 5.0) ];
-
- unsigned long rlen
- = cmsysBase64_Encode(file_buffer, len, encoded_buffer, 1);
- unsigned long cc;
-
- ostr
- << "\t\t\t<NamedMeasurement"
- << " " << measurementfile.match(1) << "=\""
- << measurementfile.match(2) << "\""
- << " " << measurementfile.match(3) << "=\""
- << measurementfile.match(4) << "\""
- << " encoding=\"base64\""
- << ">" << std::endl << "\t\t\t\t<Value>";
- for ( cc = 0; cc < rlen; cc ++ )
- {
+ unsigned char* encoded_buffer = new unsigned char[static_cast<int>(
+ static_cast<double>(len) * 1.5 + 5.0)];
+
+ size_t rlen =
+ cmsysBase64_Encode(file_buffer, len, encoded_buffer, 1);
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute(measurementfile.match(1).c_str(),
+ measurementfile.match(2));
+ xml.Attribute(measurementfile.match(3).c_str(),
+ measurementfile.match(4));
+ xml.Attribute("encoding", "base64");
+ std::ostringstream ostr;
+ for (size_t cc = 0; cc < rlen; cc++) {
ostr << encoded_buffer[cc];
- if ( cc % 60 == 0 && cc )
- {
+ if (cc % 60 == 0 && cc) {
ostr << std::endl;
- }
}
- ostr
- << "</Value>" << std::endl << "\t\t\t</NamedMeasurement>"
- << std::endl;
- delete [] file_buffer;
- delete [] encoded_buffer;
}
+ xml.Element("Value", ostr.str());
+ xml.EndElement(); // NamedMeasurement
+ delete[] file_buffer;
+ delete[] encoded_buffer;
}
- else
- {
+ } else {
int idx = 4;
- if ( measurementfile.match(1) == "name" )
- {
+ if (measurementfile.match(1) == "name") {
idx = 2;
- }
- ostr
- << "\t\t\t<NamedMeasurement"
- << " name=\"" << measurementfile.match(idx) << "\""
- << " text=\"text/string\""
- << "><Value>File " << filename.c_str()
- << " not found</Value></NamedMeasurement>"
- << std::endl;
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "File \"" << filename.c_str()
- << "\" not found." << std::endl);
}
- cxml.erase(measurementfile.start(),
- measurementfile.end() - measurementfile.start());
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("name", measurementfile.match(idx));
+ xml.Attribute("text", "text/string");
+ xml.Element("Value", "File " + filename + " not found");
+ xml.EndElement();
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "File \""
+ << filename << "\" not found." << std::endl,
+ this->Quiet);
}
- else
- {
+ cxml.erase(measurementfile.start(),
+ measurementfile.end() - measurementfile.start());
+ } else {
done = true;
- }
}
- return ostr.str();
+ }
}
-//----------------------------------------------------------------------
-void cmCTestTestHandler::SetIncludeRegExp(const char *arg)
+void cmCTestTestHandler::SetIncludeRegExp(const char* arg)
{
this->IncludeRegExp = arg;
}
-//----------------------------------------------------------------------
-void cmCTestTestHandler::SetExcludeRegExp(const char *arg)
+void cmCTestTestHandler::SetExcludeRegExp(const char* arg)
{
this->ExcludeRegExp = arg;
}
-//----------------------------------------------------------------------
void cmCTestTestHandler::SetTestsToRunInformation(const char* in)
{
- if ( !in )
- {
+ if (!in) {
return;
- }
+ }
this->TestsToRunString = in;
// if the argument is a file, then read it and use the contents as the
// string
- if(cmSystemTools::FileExists(in))
- {
- std::ifstream fin(in);
+ if (cmSystemTools::FileExists(in)) {
+ cmsys::ifstream fin(in);
unsigned long filelen = cmSystemTools::FileLength(in);
- char* buff = new char[filelen+1];
+ char* buff = new char[filelen + 1];
fin.getline(buff, filelen);
buff[fin.gcount()] = 0;
this->TestsToRunString = buff;
- delete [] buff;
- }
+ delete[] buff;
+ }
}
-//----------------------------------------------------------------------------
bool cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length)
{
- if(!length || length >= output.size() ||
- output.find("CTEST_FULL_OUTPUT") != output.npos)
- {
+ if (!length || length >= output.size() ||
+ output.find("CTEST_FULL_OUTPUT") != std::string::npos) {
return true;
- }
+ }
// Truncate at given length but do not break in the middle of a multi-byte
// UTF-8 encoding.
@@ -1963,303 +2037,260 @@ bool cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length)
char const* const end = begin + output.size();
char const* const truncate = begin + length;
char const* current = begin;
- while(current < truncate)
- {
+ while (current < truncate) {
unsigned int ch;
- if(const char* next = cm_utf8_decode_character(current, end, &ch))
- {
- if(next > truncate)
- {
+ if (const char* next = cm_utf8_decode_character(current, end, &ch)) {
+ if (next > truncate) {
break;
- }
- current = next;
}
- else // Bad byte will be handled by cmXMLSafe.
- {
+ current = next;
+ } else // Bad byte will be handled by cmXMLWriter.
+ {
++current;
- }
}
+ }
output = output.substr(0, current - begin);
// Append truncation message.
- cmOStringStream msg;
+ std::ostringstream msg;
msg << "...\n"
- "The rest of the test output was removed since it exceeds the threshold "
- "of " << length << " bytes.\n";
+ "The rest of the test output was removed since it exceeds the "
+ "threshold "
+ "of "
+ << length << " bytes.\n";
output += msg.str();
return true;
}
-//----------------------------------------------------------------------
bool cmCTestTestHandler::SetTestsProperties(
const std::vector<std::string>& args)
{
std::vector<std::string>::const_iterator it;
- std::vector<cmStdString> tests;
+ std::vector<std::string> tests;
bool found = false;
- for ( it = args.begin(); it != args.end(); ++ it )
- {
- if ( *it == "PROPERTIES" )
- {
+ for (it = args.begin(); it != args.end(); ++it) {
+ if (*it == "PROPERTIES") {
found = true;
break;
- }
- tests.push_back(*it);
}
- if ( !found )
- {
+ tests.push_back(*it);
+ }
+ if (!found) {
return false;
- }
- ++ it; // skip PROPERTIES
- for ( ; it != args.end(); ++ it )
- {
+ }
+ ++it; // skip PROPERTIES
+ for (; it != args.end(); ++it) {
std::string key = *it;
- ++ it;
- if ( it == args.end() )
- {
+ ++it;
+ if (it == args.end()) {
break;
- }
+ }
std::string val = *it;
- std::vector<cmStdString>::const_iterator tit;
- for ( tit = tests.begin(); tit != tests.end(); ++ tit )
- {
+ std::vector<std::string>::const_iterator tit;
+ for (tit = tests.begin(); tit != tests.end(); ++tit) {
cmCTestTestHandler::ListOfTests::iterator rtit;
- for ( rtit = this->TestList.begin();
- rtit != this->TestList.end();
- ++ rtit )
- {
- if ( *tit == rtit->Name )
- {
- if ( key == "WILL_FAIL" )
- {
+ for (rtit = this->TestList.begin(); rtit != this->TestList.end();
+ ++rtit) {
+ if (*tit == rtit->Name) {
+ if (key == "WILL_FAIL") {
rtit->WillFail = cmSystemTools::IsOn(val.c_str());
- }
- if ( key == "ATTACHED_FILES" )
- {
+ }
+ if (key == "DISABLED") {
+ rtit->Disabled = cmSystemTools::IsOn(val.c_str());
+ }
+ if (key == "ATTACHED_FILES") {
+ cmSystemTools::ExpandListArgument(val, rtit->AttachedFiles);
+ }
+ if (key == "ATTACHED_FILES_ON_FAIL") {
+ cmSystemTools::ExpandListArgument(val, rtit->AttachOnFail);
+ }
+ if (key == "RESOURCE_LOCK") {
std::vector<std::string> lval;
- cmSystemTools::ExpandListArgument(val.c_str(), lval);
+ cmSystemTools::ExpandListArgument(val, lval);
- for(std::vector<std::string>::iterator f = lval.begin();
- f != lval.end(); ++f)
- {
- rtit->AttachedFiles.push_back(*f);
- }
- }
- if ( key == "ATTACHED_FILES_ON_FAIL" )
- {
+ rtit->LockedResources.insert(lval.begin(), lval.end());
+ }
+ if (key == "FIXTURES_SETUP") {
std::vector<std::string> lval;
- cmSystemTools::ExpandListArgument(val.c_str(), lval);
+ cmSystemTools::ExpandListArgument(val, lval);
- for(std::vector<std::string>::iterator f = lval.begin();
- f != lval.end(); ++f)
- {
- rtit->AttachOnFail.push_back(*f);
- }
- }
- if ( key == "RESOURCE_LOCK" )
- {
+ rtit->FixturesSetup.insert(lval.begin(), lval.end());
+ }
+ if (key == "FIXTURES_CLEANUP") {
std::vector<std::string> lval;
- cmSystemTools::ExpandListArgument(val.c_str(), lval);
+ cmSystemTools::ExpandListArgument(val, lval);
- for(std::vector<std::string>::iterator f = lval.begin();
- f != lval.end(); ++f)
- {
- rtit->LockedResources.insert(*f);
- }
- }
- if ( key == "TIMEOUT" )
- {
+ rtit->FixturesCleanup.insert(lval.begin(), lval.end());
+ }
+ if (key == "FIXTURES_REQUIRED") {
+ std::vector<std::string> lval;
+ cmSystemTools::ExpandListArgument(val, lval);
+
+ rtit->FixturesRequired.insert(lval.begin(), lval.end());
+ }
+ if (key == "TIMEOUT") {
rtit->Timeout = atof(val.c_str());
rtit->ExplicitTimeout = true;
- }
- if ( key == "COST" )
- {
+ }
+ if (key == "COST") {
rtit->Cost = static_cast<float>(atof(val.c_str()));
- }
- if ( key == "REQUIRED_FILES" )
- {
- std::vector<std::string> lval;
- cmSystemTools::ExpandListArgument(val.c_str(), lval);
-
- for(std::vector<std::string>::iterator f = lval.begin();
- f != lval.end(); ++f)
- {
- rtit->RequiredFiles.push_back(*f);
- }
- }
- if ( key == "RUN_SERIAL" )
- {
+ }
+ if (key == "REQUIRED_FILES") {
+ cmSystemTools::ExpandListArgument(val, rtit->RequiredFiles);
+ }
+ if (key == "RUN_SERIAL") {
rtit->RunSerial = cmSystemTools::IsOn(val.c_str());
- }
- if ( key == "FAIL_REGULAR_EXPRESSION" )
- {
+ }
+ if (key == "FAIL_REGULAR_EXPRESSION") {
std::vector<std::string> lval;
- cmSystemTools::ExpandListArgument(val.c_str(), lval);
+ cmSystemTools::ExpandListArgument(val, lval);
std::vector<std::string>::iterator crit;
- for ( crit = lval.begin(); crit != lval.end(); ++ crit )
- {
+ for (crit = lval.begin(); crit != lval.end(); ++crit) {
rtit->ErrorRegularExpressions.push_back(
std::pair<cmsys::RegularExpression, std::string>(
cmsys::RegularExpression(crit->c_str()),
- std::string(crit->c_str())));
- }
+ std::string(*crit)));
}
- if ( key == "PROCESSORS" )
- {
+ }
+ if (key == "PROCESSORS") {
rtit->Processors = atoi(val.c_str());
- if(rtit->Processors < 1)
- {
+ if (rtit->Processors < 1) {
rtit->Processors = 1;
- }
- }
- if ( key == "DEPENDS" )
- {
- std::vector<std::string> lval;
- cmSystemTools::ExpandListArgument(val.c_str(), lval);
- std::vector<std::string>::iterator crit;
- for ( crit = lval.begin(); crit != lval.end(); ++ crit )
- {
- rtit->Depends.push_back(*crit);
- }
}
- if ( key == "ENVIRONMENT" )
- {
- std::vector<std::string> lval;
- cmSystemTools::ExpandListArgument(val.c_str(), lval);
- std::vector<std::string>::iterator crit;
- for ( crit = lval.begin(); crit != lval.end(); ++ crit )
- {
- rtit->Environment.push_back(*crit);
- }
- }
- if ( key == "LABELS" )
- {
- std::vector<std::string> lval;
- cmSystemTools::ExpandListArgument(val.c_str(), lval);
- std::vector<std::string>::iterator crit;
- for ( crit = lval.begin(); crit != lval.end(); ++ crit )
- {
- rtit->Labels.push_back(*crit);
- }
+ }
+ if (key == "SKIP_RETURN_CODE") {
+ rtit->SkipReturnCode = atoi(val.c_str());
+ if (rtit->SkipReturnCode < 0 || rtit->SkipReturnCode > 255) {
+ rtit->SkipReturnCode = -1;
}
- if ( key == "MEASUREMENT" )
- {
- size_t pos = val.find_first_of("=");
- if ( pos != val.npos )
- {
+ }
+ if (key == "DEPENDS") {
+ cmSystemTools::ExpandListArgument(val, rtit->Depends);
+ }
+ if (key == "ENVIRONMENT") {
+ cmSystemTools::ExpandListArgument(val, rtit->Environment);
+ }
+ if (key == "LABELS") {
+ cmSystemTools::ExpandListArgument(val, rtit->Labels);
+ }
+ if (key == "MEASUREMENT") {
+ size_t pos = val.find_first_of('=');
+ if (pos != std::string::npos) {
std::string mKey = val.substr(0, pos);
const char* mVal = val.c_str() + pos + 1;
rtit->Measurements[mKey] = mVal;
- }
- else
- {
+ } else {
rtit->Measurements[val] = "1";
- }
}
- if ( key == "PASS_REGULAR_EXPRESSION" )
- {
+ }
+ if (key == "PASS_REGULAR_EXPRESSION") {
std::vector<std::string> lval;
- cmSystemTools::ExpandListArgument(val.c_str(), lval);
+ cmSystemTools::ExpandListArgument(val, lval);
std::vector<std::string>::iterator crit;
- for ( crit = lval.begin(); crit != lval.end(); ++ crit )
- {
+ for (crit = lval.begin(); crit != lval.end(); ++crit) {
rtit->RequiredRegularExpressions.push_back(
std::pair<cmsys::RegularExpression, std::string>(
cmsys::RegularExpression(crit->c_str()),
- std::string(crit->c_str())));
- }
+ std::string(*crit)));
}
- if ( key == "WORKING_DIRECTORY" )
- {
+ }
+ if (key == "WORKING_DIRECTORY") {
rtit->Directory = val;
+ }
+ if (key == "TIMEOUT_AFTER_MATCH") {
+ std::vector<std::string> propArgs;
+ cmSystemTools::ExpandListArgument(val, propArgs);
+ if (propArgs.size() != 2) {
+ cmCTestLog(this->CTest, WARNING,
+ "TIMEOUT_AFTER_MATCH expects two arguments, found "
+ << propArgs.size() << std::endl);
+ } else {
+ rtit->AlternateTimeout = atof(propArgs[0].c_str());
+ std::vector<std::string> lval;
+ cmSystemTools::ExpandListArgument(propArgs[1], lval);
+ std::vector<std::string>::iterator crit;
+ for (crit = lval.begin(); crit != lval.end(); ++crit) {
+ rtit->TimeoutRegularExpressions.push_back(
+ std::pair<cmsys::RegularExpression, std::string>(
+ cmsys::RegularExpression(crit->c_str()),
+ std::string(*crit)));
+ }
}
}
}
}
}
+ }
return true;
}
-//----------------------------------------------------------------------
bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args)
{
const std::string& testname = args[0];
- cmCTestLog(this->CTest, DEBUG, "Add test: " << args[0] << std::endl);
+ cmCTestOptionalLog(this->CTest, DEBUG, "Add test: " << args[0] << std::endl,
+ this->Quiet);
- if (this->UseExcludeRegExpFlag &&
- this->UseExcludeRegExpFirst &&
- this->ExcludeTestsRegularExpression.find(testname.c_str()))
- {
+ if (this->UseExcludeRegExpFlag && this->UseExcludeRegExpFirst &&
+ this->ExcludeTestsRegularExpression.find(testname.c_str())) {
return true;
- }
- if ( this->MemCheck )
- {
- std::vector<cmStdString>::iterator it;
+ }
+ if (this->MemCheck) {
+ std::vector<std::string>::iterator it;
bool found = false;
- for ( it = this->CustomTestsIgnore.begin();
- it != this->CustomTestsIgnore.end(); ++ it )
- {
- if ( *it == testname )
- {
+ for (it = this->CustomTestsIgnore.begin();
+ it != this->CustomTestsIgnore.end(); ++it) {
+ if (*it == testname) {
found = true;
break;
- }
}
- if ( found )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Ignore memcheck: "
- << *it << std::endl);
+ }
+ if (found) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Ignore memcheck: " << *it << std::endl, this->Quiet);
return true;
- }
}
- else
- {
- std::vector<cmStdString>::iterator it;
+ } else {
+ std::vector<std::string>::iterator it;
bool found = false;
- for ( it = this->CustomTestsIgnore.begin();
- it != this->CustomTestsIgnore.end(); ++ it )
- {
- if ( *it == testname )
- {
+ for (it = this->CustomTestsIgnore.begin();
+ it != this->CustomTestsIgnore.end(); ++it) {
+ if (*it == testname) {
found = true;
break;
- }
}
- if ( found )
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Ignore test: "
- << *it << std::endl);
+ }
+ if (found) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Ignore test: " << *it << std::endl, this->Quiet);
return true;
- }
}
+ }
cmCTestTestProperties test;
test.Name = testname;
test.Args = args;
test.Directory = cmSystemTools::GetCurrentWorkingDirectory();
- cmCTestLog(this->CTest, DEBUG, "Set test directory: "
- << test.Directory << std::endl);
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Set test directory: " << test.Directory << std::endl,
+ this->Quiet);
test.IsInBasedOnREOptions = true;
test.WillFail = false;
+ test.Disabled = false;
test.RunSerial = false;
test.Timeout = 0;
test.ExplicitTimeout = false;
test.Cost = 0;
test.Processors = 1;
+ test.SkipReturnCode = -1;
test.PreviousRuns = 0;
if (this->UseIncludeRegExpFlag &&
- !this->IncludeTestsRegularExpression.find(testname.c_str()))
- {
+ !this->IncludeTestsRegularExpression.find(testname.c_str())) {
test.IsInBasedOnREOptions = false;
- }
- else if (this->UseExcludeRegExpFlag &&
- !this->UseExcludeRegExpFirst &&
- this->ExcludeTestsRegularExpression.find(testname.c_str()))
- {
+ } else if (this->UseExcludeRegExpFlag && !this->UseExcludeRegExpFirst &&
+ this->ExcludeTestsRegularExpression.find(testname.c_str())) {
test.IsInBasedOnREOptions = false;
- }
+ }
this->TestList.push_back(test);
return true;
}
-
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index 93b793b20..0edcb143a 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -1,23 +1,24 @@
-/*============================================================================
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestTestHandler_h
#define cmCTestTestHandler_h
+#include "cmConfigure.h"
#include "cmCTestGenericHandler.h"
-#include <cmsys/RegularExpression.hxx>
+#include "cmsys/RegularExpression.hxx"
+#include <iosfwd>
+#include <map>
+#include <set>
+#include <stddef.h>
+#include <string>
+#include <utility>
+#include <vector>
+
+class cmCTest;
class cmMakefile;
+class cmXMLWriter;
/** \class cmCTestTestHandler
* \brief A class that handles ctest -S invocations
@@ -28,13 +29,14 @@ class cmCTestTestHandler : public cmCTestGenericHandler
friend class cmCTestRunTest;
friend class cmCTestMultiProcessHandler;
friend class cmCTestBatchTestHandler;
+
public:
- cmTypeMacro(cmCTestTestHandler, cmCTestGenericHandler);
+ typedef cmCTestGenericHandler Superclass;
/**
* The main entry point for this class
*/
- int ProcessHandler();
+ int ProcessHandler() CM_OVERRIDE;
/**
* When both -R and -I are used should te resulting test list be the
@@ -44,19 +46,34 @@ 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);
+ void PopulateCustomVectors(cmMakefile* mf) CM_OVERRIDE;
///! Control the use of the regular expresisons, call these methods to turn
- ///them on
+ /// them on
void UseIncludeRegExp();
void UseExcludeRegExp();
- void SetIncludeRegExp(const char *);
- void SetExcludeRegExp(const char *);
+ void SetIncludeRegExp(const char*);
+ void SetExcludeRegExp(const char*);
- void SetMaxIndex(int n) {this->MaxIndex = n;}
- int GetMaxIndex() {return this->MaxIndex;}
+ void SetMaxIndex(int n) { this->MaxIndex = n; }
+ int GetMaxIndex() { return this->MaxIndex; }
+
+ void SetTestOutputSizePassed(int n)
+ {
+ this->CustomMaximumPassedTestOutputSize = n;
+ }
+ void SetTestOutputSizeFailed(int n)
+ {
+ this->CustomMaximumFailedTestOutputSize = n;
+ }
///! pass the -I argument down
void SetTestsToRunInformation(const char*);
@@ -73,7 +90,7 @@ public:
*/
bool SetTestsProperties(const std::vector<std::string>& args);
- void Initialize();
+ void Initialize() CM_OVERRIDE;
// NOTE: This struct is Saved/Restored
// in cmCTestTestHandler, if you add to this class
@@ -81,31 +98,41 @@ public:
// ctest -j N will break for that feature
struct cmCTestTestProperties
{
- cmStdString Name;
- cmStdString Directory;
+ std::string Name;
+ std::string Directory;
std::vector<std::string> Args;
std::vector<std::string> RequiredFiles;
std::vector<std::string> Depends;
std::vector<std::string> AttachedFiles;
std::vector<std::string> AttachOnFail;
- std::vector<std::pair<cmsys::RegularExpression,
- std::string> > ErrorRegularExpressions;
- std::vector<std::pair<cmsys::RegularExpression,
- std::string> > RequiredRegularExpressions;
- std::map<cmStdString, cmStdString> Measurements;
+ std::vector<std::pair<cmsys::RegularExpression, std::string> >
+ ErrorRegularExpressions;
+ std::vector<std::pair<cmsys::RegularExpression, std::string> >
+ RequiredRegularExpressions;
+ std::vector<std::pair<cmsys::RegularExpression, std::string> >
+ TimeoutRegularExpressions;
+ std::map<std::string, std::string> Measurements;
bool IsInBasedOnREOptions;
bool WillFail;
+ bool Disabled;
float Cost;
int PreviousRuns;
bool RunSerial;
double Timeout;
bool ExplicitTimeout;
+ double AlternateTimeout;
int Index;
- //Requested number of process slots
+ // 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;
+ std::set<std::string> FixturesSetup;
+ std::set<std::string> FixturesCleanup;
+ std::set<std::string> FixturesRequired;
+ std::set<std::string> RequireSuccessDepends;
};
struct cmCTestTestResult
@@ -114,72 +141,73 @@ public:
std::string Path;
std::string Reason;
std::string FullCommandLine;
- double ExecutionTime;
- int ReturnValue;
- int Status;
- bool CompressOutput;
+ double ExecutionTime;
+ int ReturnValue;
+ int Status;
+ bool CompressOutput;
std::string CompletionStatus;
std::string Output;
- std::string RegressionImages;
- int TestCount;
+ std::string DartString;
+ int TestCount;
cmCTestTestProperties* Properties;
};
struct cmCTestTestResultLess
{
- bool operator() (const cmCTestTestResult &lhs,
- const cmCTestTestResult &rhs) const
+ bool operator()(const cmCTestTestResult& lhs,
+ const cmCTestTestResult& rhs) const
{
- return lhs.TestCount < rhs.TestCount;
+ return lhs.TestCount < rhs.TestCount;
}
};
// add configurations to a search path for an executable
- static void AddConfigurations(cmCTest *ctest,
- std::vector<std::string> &attempted,
- std::vector<std::string> &attemptedConfigs,
- std::string filepath,
- std::string &filename);
+ static void AddConfigurations(cmCTest* ctest,
+ std::vector<std::string>& attempted,
+ std::vector<std::string>& attemptedConfigs,
+ std::string filepath, std::string& filename);
// full signature static method to find an executable
- static std::string FindExecutable(cmCTest *ctest,
- const char *testCommand,
- std::string &resultingConfig,
- std::vector<std::string> &extraPaths,
- std::vector<std::string> &failed);
+ static std::string FindExecutable(cmCTest* ctest, const char* testCommand,
+ std::string& resultingConfig,
+ std::vector<std::string>& extraPaths,
+ std::vector<std::string>& failed);
typedef std::vector<cmCTestTestProperties> ListOfTests;
+
protected:
// compute a final test list
virtual int PreProcessHandler();
virtual int PostProcessHandler();
virtual void GenerateTestCommand(std::vector<std::string>& args, int test);
- int ExecuteCommands(std::vector<cmStdString>& vec);
+ int ExecuteCommands(std::vector<std::string>& vec);
- void WriteTestResultHeader(std::ostream& os, cmCTestTestResult* result);
- void WriteTestResultFooter(std::ostream& os, cmCTestTestResult* result);
+ void WriteTestResultHeader(cmXMLWriter& xml, cmCTestTestResult* result);
+ void WriteTestResultFooter(cmXMLWriter& xml, cmCTestTestResult* result);
// Write attached test files into the xml
- void AttachFiles(std::ostream& os, cmCTestTestResult* result);
+ void AttachFiles(cmXMLWriter& xml, cmCTestTestResult* result);
//! Clean test output to specified length
bool CleanTestOutput(std::string& output, size_t length);
- double ElapsedTestingTime;
+ double ElapsedTestingTime;
typedef std::vector<cmCTestTestResult> TestResultsVector;
- TestResultsVector TestResults;
+ TestResultsVector TestResults;
- std::vector<cmStdString> CustomTestsIgnore;
- std::string StartTest;
- std::string EndTest;
- unsigned int StartTestTime;
- unsigned int EndTestTime;
+ std::vector<std::string> CustomTestsIgnore;
+ std::string StartTest;
+ std::string EndTest;
+ unsigned int StartTestTime;
+ unsigned int EndTestTime;
bool MemCheck;
int CustomMaximumPassedTestOutputSize;
int CustomMaximumFailedTestOutputSize;
int MaxIndex;
+
public:
- enum { // Program statuses
+ enum
+ { // Program statuses
NOT_RUN = 0,
TIMEOUT,
SEGFAULT,
@@ -196,14 +224,14 @@ private:
/**
* Generate the Dart compatible output
*/
- virtual void GenerateDartOutput(std::ostream& os);
+ virtual void GenerateDartOutput(cmXMLWriter& xml);
void PrintLabelSummary();
/**
* Run the tests for a directory and any subdirectories
*/
- void ProcessDirectory(std::vector<cmStdString> &passed,
- std::vector<cmStdString> &failed);
+ void ProcessDirectory(std::vector<std::string>& passed,
+ std::vector<std::string>& failed);
/**
* Get the list of tests in directory and subdirectories.
@@ -213,33 +241,35 @@ private:
// based on union regex and -I stuff
void ComputeTestList();
- bool GetValue(const char* tag,
- std::string& value,
- std::ifstream& fin);
- bool GetValue(const char* tag,
- int& value,
- std::ifstream& fin);
- bool GetValue(const char* tag,
- size_t& value,
- std::ifstream& fin);
- bool GetValue(const char* tag,
- bool& value,
- std::ifstream& fin);
- bool GetValue(const char* tag,
- double& value,
- std::ifstream& fin);
+ // compute the lists of tests that will actually run
+ // based on LastTestFailed.log
+ void ComputeTestListForRerunFailed();
+
+ // add required setup/cleanup tests not already in the
+ // list of tests to be run and update dependencies between
+ // tests to account for fixture setup/cleanup
+ void UpdateForFixtures(ListOfTests& tests) const;
+
+ void UpdateMaxTestNameWidth();
+
+ bool GetValue(const char* tag, std::string& value, std::istream& fin);
+ bool GetValue(const char* tag, int& value, std::istream& fin);
+ bool GetValue(const char* tag, size_t& value, std::istream& fin);
+ bool GetValue(const char* tag, bool& value, std::istream& fin);
+ bool GetValue(const char* tag, double& value, std::istream& fin);
/**
* Find the executable for a test
*/
- std::string FindTheExecutable(const char *exe);
+ std::string FindTheExecutable(const char* exe);
const char* GetTestStatus(int status);
void ExpandTestsToRunInformation(size_t numPossibleTests);
+ void ExpandTestsToRunInformationForRerunFailed();
- std::vector<cmStdString> CustomPreTest;
- std::vector<cmStdString> CustomPostTest;
+ std::vector<std::string> CustomPreTest;
+ std::vector<std::string> CustomPostTest;
- std::vector<int> TestsToRun;
+ std::vector<int> TestsToRun;
bool UseIncludeLabelRegExpFlag;
bool UseExcludeLabelRegExpFlag;
@@ -250,12 +280,15 @@ private:
std::string ExcludeLabelRegExp;
std::string IncludeRegExp;
std::string ExcludeRegExp;
+ std::string ExcludeFixtureRegExp;
+ std::string ExcludeFixtureSetupRegExp;
+ std::string ExcludeFixtureCleanupRegExp;
cmsys::RegularExpression IncludeLabelRegularExpression;
cmsys::RegularExpression ExcludeLabelRegularExpression;
cmsys::RegularExpression IncludeTestsRegularExpression;
cmsys::RegularExpression ExcludeTestsRegularExpression;
- std::string GenerateRegressionImages(const std::string& xml);
+ void GenerateRegressionImages(cmXMLWriter& xml, const std::string& dart);
cmsys::RegularExpression DartStuff1;
void CheckLabelFilter(cmCTestTestProperties& it);
void CheckLabelFilterExclude(cmCTestTestProperties& it);
@@ -268,6 +301,8 @@ private:
cmsys::RegularExpression DartStuff;
std::ostream* LogFile;
+
+ bool RerunFailed;
};
#endif
diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx
index 2ca9f6c86..8c037545f 100644
--- a/Source/CTest/cmCTestUpdateCommand.cxx
+++ b/Source/CTest/cmCTestUpdateCommand.cxx
@@ -1,80 +1,91 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestUpdateCommand.h"
#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+#include <vector>
cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler()
{
- if ( this->Values[ct_SOURCE] )
- {
- this->CTest->SetCTestConfiguration("SourceDirectory",
+ if (this->Values[ct_SOURCE]) {
+ this->CTest->SetCTestConfiguration(
+ "SourceDirectory",
+ cmSystemTools::CollapseFullPath(this->Values[ct_SOURCE]).c_str(),
+ this->Quiet);
+ } else {
+ this->CTest->SetCTestConfiguration(
+ "SourceDirectory",
cmSystemTools::CollapseFullPath(
- this->Values[ct_SOURCE]).c_str());
- }
- else
- {
- this->CTest->SetCTestConfiguration("SourceDirectory",
- cmSystemTools::CollapseFullPath(
- this->Makefile->GetDefinition("CTEST_SOURCE_DIRECTORY")).c_str());
- }
- std::string source_dir
- = this->CTest->GetCTestConfiguration("SourceDirectory");
+ this->Makefile->GetDefinition("CTEST_SOURCE_DIRECTORY"))
+ .c_str(),
+ this->Quiet);
+ }
+ std::string source_dir =
+ this->CTest->GetCTestConfiguration("SourceDirectory");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "UpdateCommand", "CTEST_UPDATE_COMMAND");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "UpdateOptions", "CTEST_UPDATE_OPTIONS");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "CVSCommand", "CTEST_CVS_COMMAND");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "CVSUpdateOptions", "CTEST_CVS_UPDATE_OPTIONS");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "SVNCommand", "CTEST_SVN_COMMAND");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "SVNUpdateOptions", "CTEST_SVN_UPDATE_OPTIONS");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "SVNOptions", "CTEST_SVN_OPTIONS");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "BZRCommand", "CTEST_BZR_COMMAND");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "BZRUpdateOptions", "CTEST_BZR_UPDATE_OPTIONS");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "GITCommand", "CTEST_GIT_COMMAND");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "GITUpdateOptions", "CTEST_GIT_UPDATE_OPTIONS");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "GITUpdateCustom", "CTEST_GIT_UPDATE_CUSTOM");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "HGCommand", "CTEST_HG_COMMAND");
- this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
- "HGUpdateOptions", "CTEST_HG_UPDATE_OPTIONS");
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "UpdateCommand", "CTEST_UPDATE_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "UpdateOptions", "CTEST_UPDATE_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "CVSCommand", "CTEST_CVS_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "CVSUpdateOptions", "CTEST_CVS_UPDATE_OPTIONS",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "SVNCommand", "CTEST_SVN_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "SVNUpdateOptions", "CTEST_SVN_UPDATE_OPTIONS",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "SVNOptions", "CTEST_SVN_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "BZRCommand", "CTEST_BZR_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "BZRUpdateOptions", "CTEST_BZR_UPDATE_OPTIONS",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "GITCommand", "CTEST_GIT_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "GITUpdateOptions", "CTEST_GIT_UPDATE_OPTIONS",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "GITInitSubmodules", "CTEST_GIT_INIT_SUBMODULES",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "GITUpdateCustom", "CTEST_GIT_UPDATE_CUSTOM", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "UpdateVersionOnly", "CTEST_UPDATE_VERSION_ONLY",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "HGCommand", "CTEST_HG_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "HGUpdateOptions", "CTEST_HG_UPDATE_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "P4Command", "CTEST_P4_COMMAND", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "P4UpdateOptions", "CTEST_P4_UPDATE_OPTIONS", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "P4Client", "CTEST_P4_CLIENT", this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "P4Options", "CTEST_P4_OPTIONS", this->Quiet);
- cmCTestGenericHandler* handler
- = this->CTest->GetInitializedHandler("update");
- if ( !handler )
- {
+ cmCTestGenericHandler* handler =
+ this->CTest->GetInitializedHandler("update");
+ if (!handler) {
this->SetError("internal CTest error. Cannot instantiate update handler");
- return 0;
- }
+ return CM_NULLPTR;
+ }
handler->SetCommand(this);
- if ( source_dir.empty() )
- {
+ if (source_dir.empty()) {
this->SetError("source directory not specified. Please use SOURCE tag");
- return 0;
- }
+ return CM_NULLPTR;
+ }
handler->SetOption("SourceDirectory", source_dir.c_str());
+ handler->SetQuiet(this->Quiet);
return handler;
}
-
-
diff --git a/Source/CTest/cmCTestUpdateCommand.h b/Source/CTest/cmCTestUpdateCommand.h
index c578fff6f..3b8f0a641 100644
--- a/Source/CTest/cmCTestUpdateCommand.h
+++ b/Source/CTest/cmCTestUpdateCommand.h
@@ -1,19 +1,17 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestUpdateCommand_h
#define cmCTestUpdateCommand_h
+#include "cmConfigure.h"
+
#include "cmCTestHandlerCommand.h"
+#include <string>
+
+class cmCTestGenericHandler;
+class cmCommand;
+
/** \class cmCTestUpdate
* \brief Run a ctest script
*
@@ -22,52 +20,26 @@
class cmCTestUpdateCommand : public cmCTestHandlerCommand
{
public:
-
cmCTestUpdateCommand() {}
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestUpdateCommand* ni = new cmCTestUpdateCommand;
ni->CTest = this->CTest;
ni->CTestScriptHandler = this->CTestScriptHandler;
return ni;
- }
+ }
/**
* The name of the command as specified in CMakeList.txt.
*/
- 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);
+ std::string GetName() const CM_OVERRIDE { return "ctest_update"; }
protected:
- cmCTestGenericHandler* InitializeHandler();
+ cmCTestGenericHandler* InitializeHandler() CM_OVERRIDE;
};
-
#endif
diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx
index 9eae3f3ac..e08a9b7bd 100644
--- a/Source/CTest/cmCTestUpdateHandler.cxx
+++ b/Source/CTest/cmCTestUpdateHandler.cxx
@@ -1,115 +1,41 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestUpdateHandler.h"
+#include "cmCLocaleEnvironmentScope.h"
#include "cmCTest.h"
-#include "cmake.h"
-#include "cmMakefile.h"
-#include "cmLocalGenerator.h"
-#include "cmGlobalGenerator.h"
-#include "cmVersion.h"
-#include "cmGeneratedFileStream.h"
-#include "cmXMLParser.h"
-#include "cmXMLSafe.h"
-
-#include "cmCTestVC.h"
-#include "cmCTestCVS.h"
-#include "cmCTestSVN.h"
#include "cmCTestBZR.h"
+#include "cmCTestCVS.h"
#include "cmCTestGIT.h"
#include "cmCTestHG.h"
+#include "cmCTestP4.h"
+#include "cmCTestSVN.h"
+#include "cmCTestVC.h"
+#include "cmGeneratedFileStream.h"
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+#include "cmXMLWriter.h"
-#include <cmsys/auto_ptr.hxx>
-
-//#include <cmsys/RegularExpression.hxx>
-#include <cmsys/Process.h>
-
-// used for sleep
-#ifdef _WIN32
-#include "windows.h"
-#endif
-
-#include <stdlib.h>
-#include <math.h>
-#include <float.h>
+#include "cm_auto_ptr.hxx"
+#include <sstream>
-//----------------------------------------------------------------------
-static const char* cmCTestUpdateHandlerUpdateStrings[] =
-{
- "Unknown",
- "CVS",
- "SVN",
- "BZR",
- "GIT",
- "HG"
+static const char* cmCTestUpdateHandlerUpdateStrings[] = {
+ "Unknown", "CVS", "SVN", "BZR", "GIT", "HG", "P4"
};
static const char* cmCTestUpdateHandlerUpdateToString(int type)
{
- if ( type < cmCTestUpdateHandler::e_UNKNOWN ||
- type >= cmCTestUpdateHandler::e_LAST )
- {
+ if (type < cmCTestUpdateHandler::e_UNKNOWN ||
+ type >= cmCTestUpdateHandler::e_LAST) {
return cmCTestUpdateHandlerUpdateStrings[cmCTestUpdateHandler::e_UNKNOWN];
- }
+ }
return cmCTestUpdateHandlerUpdateStrings[type];
}
-class cmCTestUpdateHandlerLocale
-{
-public:
- cmCTestUpdateHandlerLocale();
- ~cmCTestUpdateHandlerLocale();
-private:
- std::string saveLCMessages;
-};
-
-cmCTestUpdateHandlerLocale::cmCTestUpdateHandlerLocale()
-{
- const char* lcmess = cmSystemTools::GetEnv("LC_MESSAGES");
- if(lcmess)
- {
- saveLCMessages = lcmess;
- }
- // if LC_MESSAGES is not set to C, then
- // set it, so that svn/cvs info will be in english ascii
- if(! (lcmess && strcmp(lcmess, "C") == 0))
- {
- cmSystemTools::PutEnv("LC_MESSAGES=C");
- }
-}
-
-cmCTestUpdateHandlerLocale::~cmCTestUpdateHandlerLocale()
-{
- // restore the value of LC_MESSAGES after running the version control
- // commands
- if(saveLCMessages.size())
- {
- std::string put = "LC_MESSAGES=";
- put += saveLCMessages;
- cmSystemTools::PutEnv(put.c_str());
- }
- else
- {
- cmSystemTools::UnsetEnv("LC_MESSAGES");
- }
-}
-
-//----------------------------------------------------------------------
cmCTestUpdateHandler::cmCTestUpdateHandler()
{
}
-//----------------------------------------------------------------------
void cmCTestUpdateHandler::Initialize()
{
this->Superclass::Initialize();
@@ -117,114 +43,121 @@ void cmCTestUpdateHandler::Initialize()
this->UpdateType = e_CVS;
}
-//----------------------------------------------------------------------
int cmCTestUpdateHandler::DetermineType(const char* cmd, const char* type)
{
- cmCTestLog(this->CTest, DEBUG, "Determine update type from command: " << cmd
- << " and type: " << type << std::endl);
- if ( type && *type )
- {
- cmCTestLog(this->CTest, DEBUG, "Type specified: " << type << std::endl);
+ cmCTestOptionalLog(this->CTest, DEBUG, "Determine update type from command: "
+ << cmd << " and type: " << type << std::endl,
+ this->Quiet);
+ if (type && *type) {
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Type specified: " << type << std::endl, this->Quiet);
std::string stype = cmSystemTools::LowerCase(type);
- if ( stype.find("cvs") != std::string::npos )
- {
+ if (stype.find("cvs") != std::string::npos) {
return cmCTestUpdateHandler::e_CVS;
- }
- if ( stype.find("svn") != std::string::npos )
- {
+ }
+ if (stype.find("svn") != std::string::npos) {
return cmCTestUpdateHandler::e_SVN;
- }
- if ( stype.find("bzr") != std::string::npos )
- {
+ }
+ if (stype.find("bzr") != std::string::npos) {
return cmCTestUpdateHandler::e_BZR;
- }
- if ( stype.find("git") != std::string::npos )
- {
+ }
+ if (stype.find("git") != std::string::npos) {
return cmCTestUpdateHandler::e_GIT;
- }
- if ( stype.find("hg") != std::string::npos )
- {
+ }
+ if (stype.find("hg") != std::string::npos) {
return cmCTestUpdateHandler::e_HG;
- }
}
- else
- {
- cmCTestLog(this->CTest, DEBUG, "Type not specified, check command: "
- << cmd << std::endl);
+ if (stype.find("p4") != std::string::npos) {
+ return cmCTestUpdateHandler::e_P4;
+ }
+ } else {
+ cmCTestOptionalLog(
+ this->CTest, DEBUG,
+ "Type not specified, check command: " << cmd << std::endl, this->Quiet);
std::string stype = cmSystemTools::LowerCase(cmd);
- if ( stype.find("cvs") != std::string::npos )
- {
+ if (stype.find("cvs") != std::string::npos) {
return cmCTestUpdateHandler::e_CVS;
- }
- if ( stype.find("svn") != std::string::npos )
- {
+ }
+ if (stype.find("svn") != std::string::npos) {
return cmCTestUpdateHandler::e_SVN;
- }
- if ( stype.find("bzr") != std::string::npos )
- {
+ }
+ if (stype.find("bzr") != std::string::npos) {
return cmCTestUpdateHandler::e_BZR;
- }
- if ( stype.find("git") != std::string::npos )
- {
+ }
+ if (stype.find("git") != std::string::npos) {
return cmCTestUpdateHandler::e_GIT;
- }
- if ( stype.find("hg") != std::string::npos )
- {
+ }
+ if (stype.find("hg") != std::string::npos) {
return cmCTestUpdateHandler::e_HG;
- }
}
+ if (stype.find("p4") != std::string::npos) {
+ return cmCTestUpdateHandler::e_P4;
+ }
+ }
return cmCTestUpdateHandler::e_UNKNOWN;
}
-//----------------------------------------------------------------------
-//clearly it would be nice if this were broken up into a few smaller
-//functions and commented...
+// clearly it would be nice if this were broken up into a few smaller
+// functions and commented...
int cmCTestUpdateHandler::ProcessHandler()
{
// Make sure VCS tool messages are in English so we can parse them.
- cmCTestUpdateHandlerLocale fixLocale;
+ cmCLocaleEnvironmentScope fixLocale;
static_cast<void>(fixLocale);
// Get source dir
const char* sourceDirectory = this->GetOption("SourceDirectory");
- if ( !sourceDirectory )
- {
+ if (!sourceDirectory) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot find SourceDirectory key in the DartConfiguration.tcl"
- << std::endl);
+ "Cannot find SourceDirectory key in the DartConfiguration.tcl"
+ << std::endl);
return -1;
- }
+ }
cmGeneratedFileStream ofs;
- if ( !this->CTest->GetShowOnly() )
- {
+ if (!this->CTest->GetShowOnly()) {
this->StartLogFile("Update", ofs);
- }
+ }
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Updating the repository: "
- << sourceDirectory << std::endl);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Updating the repository: " << sourceDirectory
+ << std::endl,
+ this->Quiet);
- if(!this->SelectVCS())
- {
+ if (!this->SelectVCS()) {
return -1;
- }
+ }
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " Use "
- << cmCTestUpdateHandlerUpdateToString(this->UpdateType)
- << " repository type"
- << std::endl;);
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Use "
+ << cmCTestUpdateHandlerUpdateToString(this->UpdateType)
+ << " repository type" << std::endl;
+ , this->Quiet);
// Create an object to interact with the VCS tool.
- cmsys::auto_ptr<cmCTestVC> vc;
- switch (this->UpdateType)
- {
- case e_CVS: vc.reset(new cmCTestCVS(this->CTest, ofs)); break;
- case e_SVN: vc.reset(new cmCTestSVN(this->CTest, ofs)); break;
- case e_BZR: vc.reset(new cmCTestBZR(this->CTest, ofs)); break;
- case e_GIT: vc.reset(new cmCTestGIT(this->CTest, ofs)); break;
- case e_HG: vc.reset(new cmCTestHG(this->CTest, ofs)); break;
- default: vc.reset(new cmCTestVC(this->CTest, ofs)); break;
- }
+ CM_AUTO_PTR<cmCTestVC> vc;
+ switch (this->UpdateType) {
+ case e_CVS:
+ vc.reset(new cmCTestCVS(this->CTest, ofs));
+ break;
+ case e_SVN:
+ vc.reset(new cmCTestSVN(this->CTest, ofs));
+ break;
+ case e_BZR:
+ vc.reset(new cmCTestBZR(this->CTest, ofs));
+ break;
+ case e_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);
vc->SetSourceDirectory(sourceDirectory);
@@ -235,125 +168,130 @@ int cmCTestUpdateHandler::ProcessHandler()
// Now update repository and remember what files were updated
//
cmGeneratedFileStream os;
- if(!this->StartResultingXML(cmCTest::PartUpdate, "Update", os))
- {
+ if (!this->StartResultingXML(cmCTest::PartUpdate, "Update", os)) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open log file"
- << std::endl);
+ << std::endl);
return -1;
- }
+ }
std::string start_time = this->CTest->CurrentTime();
unsigned int start_time_time =
static_cast<unsigned int>(cmSystemTools::GetTime());
double elapsed_time_start = cmSystemTools::GetTime();
bool updated = vc->Update();
-
- os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- << "<Update mode=\"Client\" Generator=\"ctest-"
- << cmVersion::GetCMakeVersion() << "\">\n"
- << "\t<Site>" << this->CTest->GetCTestConfiguration("Site") << "</Site>\n"
- << "\t<BuildName>" << this->CTest->GetCTestConfiguration("BuildName")
- << "</BuildName>\n"
- << "\t<BuildStamp>" << this->CTest->GetCurrentTag() << "-"
- << this->CTest->GetTestModelString() << "</BuildStamp>" << std::endl;
- os << "\t<StartDateTime>" << start_time << "</StartDateTime>\n"
- << "\t<StartTime>" << start_time_time << "</StartTime>\n"
- << "\t<UpdateCommand>"
- << cmXMLSafe(vc->GetUpdateCommandLine()).Quotes(false)
- << "</UpdateCommand>\n"
- << "\t<UpdateType>" << cmXMLSafe(
- cmCTestUpdateHandlerUpdateToString(this->UpdateType))
- << "</UpdateType>\n";
-
- vc->WriteXML(os);
+ std::string buildname =
+ cmCTest::SafeBuildIdField(this->CTest->GetCTestConfiguration("BuildName"));
+
+ cmXMLWriter xml(os);
+ xml.StartDocument();
+ xml.StartElement("Update");
+ xml.Attribute("mode", "Client");
+ xml.Attribute("Generator",
+ std::string("ctest-") + cmVersion::GetCMakeVersion());
+ xml.Element("Site", this->CTest->GetCTestConfiguration("Site"));
+ xml.Element("BuildName", buildname);
+ xml.Element("BuildStamp", this->CTest->GetCurrentTag() + "-" +
+ this->CTest->GetTestModelString());
+ xml.Element("StartDateTime", start_time);
+ xml.Element("StartTime", start_time_time);
+ xml.Element("UpdateCommand", vc->GetUpdateCommandLine());
+ xml.Element("UpdateType",
+ cmCTestUpdateHandlerUpdateToString(this->UpdateType));
+
+ bool loadedMods = vc->WriteXML(xml);
int localModifications = 0;
int numUpdated = vc->GetPathCount(cmCTestVC::PathUpdated);
- if(numUpdated)
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- " Found " << numUpdated << " updated files\n");
- }
- if(int numModified = vc->GetPathCount(cmCTestVC::PathModified))
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- " Found " << numModified << " locally modified files\n");
+ if (numUpdated) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Found " << numUpdated << " updated files\n",
+ this->Quiet);
+ }
+ if (int numModified = vc->GetPathCount(cmCTestVC::PathModified)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Found "
+ << numModified << " locally modified files\n",
+ this->Quiet);
localModifications += numModified;
- }
- if(int numConflicting = vc->GetPathCount(cmCTestVC::PathConflicting))
- {
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- " Found " << numConflicting << " conflicting files\n");
+ }
+ if (int numConflicting = vc->GetPathCount(cmCTestVC::PathConflicting)) {
+ cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
+ " Found " << numConflicting << " conflicting files\n",
+ this->Quiet);
localModifications += numConflicting;
- }
+ }
- cmCTestLog(this->CTest, DEBUG, "End" << std::endl);
+ cmCTestOptionalLog(this->CTest, DEBUG, "End" << std::endl, this->Quiet);
std::string end_time = this->CTest->CurrentTime();
- os << "\t<EndDateTime>" << end_time << "</EndDateTime>\n"
- << "\t<EndTime>" << static_cast<unsigned int>(cmSystemTools::GetTime())
- << "</EndTime>\n"
- << "<ElapsedMinutes>" <<
- static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0
- << "</ElapsedMinutes>\n"
- << "\t<UpdateReturnStatus>";
- if(localModifications)
- {
- os << "Update error: There are modified or conflicting files in the "
- "repository";
+ xml.Element("EndDateTime", end_time);
+ xml.Element("EndTime", static_cast<unsigned int>(cmSystemTools::GetTime()));
+ xml.Element(
+ "ElapsedMinutes",
+ static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start) / 6) /
+ 10.0);
+
+ xml.StartElement("UpdateReturnStatus");
+ if (localModifications) {
+ xml.Content("Update error: "
+ "There are modified or conflicting files in the repository");
cmCTestLog(this->CTest, ERROR_MESSAGE,
- " There are modified or conflicting files in the repository"
- << std::endl);
- }
- if(!updated)
- {
- os << "Update command failed:\n" << vc->GetUpdateCommandLine();
- cmCTestLog(this->CTest, ERROR_MESSAGE, " Update command failed: "
- << vc->GetUpdateCommandLine() << "\n");
- }
- os << "</UpdateReturnStatus>" << std::endl;
- os << "</Update>" << std::endl;
- return numUpdated;
+ " There are modified or conflicting files in the repository"
+ << std::endl);
+ }
+ if (!updated) {
+ xml.Content("Update command failed:\n");
+ xml.Content(vc->GetUpdateCommandLine());
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " Update command failed: "
+ << vc->GetUpdateCommandLine() << "\n");
+ }
+ xml.EndElement(); // UpdateReturnStatus
+ xml.EndElement(); // Update
+ xml.EndDocument();
+ return updated && loadedMods ? numUpdated : -1;
}
-//----------------------------------------------------------------------
int cmCTestUpdateHandler::DetectVCS(const char* dir)
{
std::string sourceDirectory = dir;
- cmCTestLog(this->CTest, DEBUG, "Check directory: "
- << sourceDirectory.c_str() << std::endl);
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "Check directory: " << sourceDirectory << std::endl,
+ this->Quiet);
sourceDirectory += "/.svn";
- if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
- {
+ if (cmSystemTools::FileExists(sourceDirectory.c_str())) {
return cmCTestUpdateHandler::e_SVN;
- }
+ }
sourceDirectory = dir;
sourceDirectory += "/CVS";
- if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
- {
+ if (cmSystemTools::FileExists(sourceDirectory.c_str())) {
return cmCTestUpdateHandler::e_CVS;
- }
+ }
sourceDirectory = dir;
sourceDirectory += "/.bzr";
- if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
- {
+ if (cmSystemTools::FileExists(sourceDirectory.c_str())) {
return cmCTestUpdateHandler::e_BZR;
- }
+ }
sourceDirectory = dir;
sourceDirectory += "/.git";
- if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
- {
+ if (cmSystemTools::FileExists(sourceDirectory.c_str())) {
return cmCTestUpdateHandler::e_GIT;
- }
+ }
sourceDirectory = dir;
sourceDirectory += "/.hg";
- if ( cmSystemTools::FileExists(sourceDirectory.c_str()) )
- {
+ if (cmSystemTools::FileExists(sourceDirectory.c_str())) {
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;
}
-//----------------------------------------------------------------------
bool cmCTestUpdateHandler::SelectVCS()
{
// Get update command
@@ -361,44 +299,53 @@ bool cmCTestUpdateHandler::SelectVCS()
// Detect the VCS managing the source tree.
this->UpdateType = this->DetectVCS(this->GetOption("SourceDirectory"));
- if (this->UpdateType == e_UNKNOWN)
- {
+ if (this->UpdateType == e_UNKNOWN) {
// The source tree does not have a recognized VCS. Check the
// configuration value or command name.
- this->UpdateType = this->DetermineType(this->UpdateCommand.c_str(),
+ this->UpdateType = this->DetermineType(
+ this->UpdateCommand.c_str(),
this->CTest->GetCTestConfiguration("UpdateType").c_str());
- }
+ }
// If no update command was specified, lookup one for this VCS tool.
- if (this->UpdateCommand.empty())
- {
- const char* key = 0;
- switch (this->UpdateType)
- {
- case e_CVS: key = "CVSCommand"; break;
- case e_SVN: key = "SVNCommand"; break;
- case e_BZR: key = "BZRCommand"; break;
- case e_GIT: key = "GITCommand"; break;
- case e_HG: key = "HGCommand"; break;
- default: break;
- }
- if (key)
- {
+ if (this->UpdateCommand.empty()) {
+ const char* key = CM_NULLPTR;
+ switch (this->UpdateType) {
+ case e_CVS:
+ key = "CVSCommand";
+ break;
+ case e_SVN:
+ key = "SVNCommand";
+ break;
+ 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) {
this->UpdateCommand = this->CTest->GetCTestConfiguration(key);
- }
- if (this->UpdateCommand.empty())
- {
- cmOStringStream e;
+ }
+ if (this->UpdateCommand.empty()) {
+ std::ostringstream e;
e << "Cannot find UpdateCommand ";
- if (key)
- {
+ if (key) {
e << "or " << key;
- }
+ }
e << " configuration key.";
cmCTestLog(this->CTest, ERROR_MESSAGE, e.str() << std::endl);
return false;
- }
}
+ }
return true;
}
diff --git a/Source/CTest/cmCTestUpdateHandler.h b/Source/CTest/cmCTestUpdateHandler.h
index 55ec974dc..0cd284421 100644
--- a/Source/CTest/cmCTestUpdateHandler.h
+++ b/Source/CTest/cmCTestUpdateHandler.h
@@ -1,25 +1,15 @@
-/*============================================================================
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestUpdateHandler_h
#define cmCTestUpdateHandler_h
+#include "cmConfigure.h"
#include "cmCTestGenericHandler.h"
-#include "cmListFileCache.h"
-#if defined(__sgi) && !defined(__GNUC__)
-# pragma set woff 1375 /* base class destructor not virtual */
-#endif
+#include <string>
+#include <utility>
+#include <vector>
/** \class cmCTestUpdateHandler
* \brief A class that handles ctest -S invocations
@@ -28,35 +18,40 @@
class cmCTestUpdateHandler : public cmCTestGenericHandler
{
public:
- cmTypeMacro(cmCTestUpdateHandler, cmCTestGenericHandler);
+ typedef cmCTestGenericHandler Superclass;
/*
* The main entry point for this class
*/
- int ProcessHandler();
+ int ProcessHandler() CM_OVERRIDE;
cmCTestUpdateHandler();
- enum {
+ enum
+ {
e_UNKNOWN = 0,
e_CVS,
e_SVN,
e_BZR,
e_GIT,
e_HG,
+ e_P4,
e_LAST
};
/**
* Initialize handler
*/
- virtual void Initialize();
+ void Initialize() CM_OVERRIDE;
private:
// Some structures needed for update
- struct StringPair :
- public std::pair<std::string, std::string>{};
- struct UpdateFiles : public std::vector<StringPair>{};
+ struct StringPair : public std::pair<std::string, std::string>
+ {
+ };
+ struct UpdateFiles : public std::vector<StringPair>
+ {
+ };
// Determine the type of version control
int DetermineType(const char* cmd, const char* type);
@@ -69,8 +64,4 @@ private:
bool SelectVCS();
};
-#if defined(__sgi) && !defined(__GNUC__)
-# pragma reset woff 1375 /* base class destructor not virtual */
-#endif
-
#endif
diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx
index 731c1c7a3..717117a5f 100644
--- a/Source/CTest/cmCTestUploadCommand.cxx
+++ b/Source/CTest/cmCTestUploadCommand.cxx
@@ -1,68 +1,67 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestUploadCommand.h"
+#include <sstream>
+#include <vector>
+
#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
#include "cmCTestUploadHandler.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
cmCTestGenericHandler* cmCTestUploadCommand::InitializeHandler()
{
- cmCTestGenericHandler* handler
- = this->CTest->GetInitializedHandler("upload");
- if ( !handler )
- {
+ cmCTestGenericHandler* handler =
+ this->CTest->GetInitializedHandler("upload");
+ if (!handler) {
this->SetError("internal CTest error. Cannot instantiate upload handler");
- return 0;
- }
+ return CM_NULLPTR;
+ }
static_cast<cmCTestUploadHandler*>(handler)->SetFiles(this->Files);
+ handler->SetQuiet(this->Quiet);
return handler;
}
-
-//----------------------------------------------------------------------------
bool cmCTestUploadCommand::CheckArgumentKeyword(std::string const& arg)
{
- if(arg == "FILES")
- {
+ if (arg == "FILES") {
this->ArgumentDoing = ArgumentDoingFiles;
return true;
- }
+ }
+ if (arg == "QUIET") {
+ this->ArgumentDoing = ArgumentDoingNone;
+ this->Quiet = true;
+ return true;
+ }
+ if (arg == "CAPTURE_CMAKE_ERROR") {
+ this->ArgumentDoing = ArgumentDoingCaptureCMakeError;
+ return true;
+ }
return false;
}
-
-//----------------------------------------------------------------------------
bool cmCTestUploadCommand::CheckArgumentValue(std::string const& arg)
{
- if(this->ArgumentDoing == ArgumentDoingFiles)
- {
- cmStdString filename(arg);
- if(cmSystemTools::FileExists(filename.c_str()))
- {
- this->Files.insert(filename);
+ if (this->ArgumentDoing == ArgumentDoingCaptureCMakeError) {
+ this->Values[ct_CAPTURE_CMAKE_ERROR] = arg.c_str();
+ return true;
+ }
+ if (this->ArgumentDoing == ArgumentDoingFiles) {
+ if (cmSystemTools::FileExists(arg.c_str())) {
+ this->Files.insert(arg);
return true;
- }
- else
- {
- cmOStringStream e;
- e << "File \"" << filename << "\" does not exist. Cannot submit "
- << "a non-existent file.";
- this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
- this->ArgumentDoing = ArgumentDoingError;
- return false;
- }
}
+ std::ostringstream e;
+ e << "File \"" << arg << "\" does not exist. Cannot submit "
+ << "a non-existent file.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ this->ArgumentDoing = ArgumentDoingError;
+ return false;
+ }
// Look for other arguments.
return this->Superclass::CheckArgumentValue(arg);
diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h
index 62f379f6d..6e721796a 100644
--- a/Source/CTest/cmCTestUploadCommand.h
+++ b/Source/CTest/cmCTestUploadCommand.h
@@ -1,19 +1,17 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestUploadCommand_h
#define cmCTestUploadCommand_h
-#include "cmCTestHandlerCommand.h"
+#include "cmConfigure.h"
+
#include "cmCTest.h"
+#include "cmCTestHandlerCommand.h"
+
+#include <string>
+
+class cmCTestGenericHandler;
+class cmCommand;
/** \class cmCTestUpload
* \brief Run a ctest script
@@ -24,62 +22,40 @@
class cmCTestUploadCommand : public cmCTestHandlerCommand
{
public:
-
- cmCTestUploadCommand()
- {
- }
+ cmCTestUploadCommand() {}
/**
* This is a virtual constructor for the command.
*/
- virtual cmCommand* Clone()
- {
+ cmCommand* Clone() CM_OVERRIDE
+ {
cmCTestUploadCommand* ni = new cmCTestUploadCommand;
ni->CTest = this->CTest;
ni->CTestScriptHandler = this->CTestScriptHandler;
return ni;
- }
+ }
/**
* The name of the command as specified in CMakeList.txt.
*/
- virtual const char* GetName() const { return "ctest_upload";}
-
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation() const
- {
- return "Upload files to a dashboard server.";
- }
+ std::string GetName() const CM_OVERRIDE { return "ctest_upload"; }
- /**
- * 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);
+ typedef cmCTestHandlerCommand Superclass;
protected:
- cmCTestGenericHandler* InitializeHandler();
+ cmCTestGenericHandler* InitializeHandler() CM_OVERRIDE;
- virtual bool CheckArgumentKeyword(std::string const& arg);
- virtual bool CheckArgumentValue(std::string const& arg);
+ bool CheckArgumentKeyword(std::string const& arg) CM_OVERRIDE;
+ bool CheckArgumentValue(std::string const& arg) CM_OVERRIDE;
enum
{
ArgumentDoingFiles = Superclass::ArgumentDoingLast1,
+ ArgumentDoingCaptureCMakeError,
ArgumentDoingLast2
};
cmCTest::SetOfStrings Files;
};
-
#endif
diff --git a/Source/CTest/cmCTestUploadHandler.cxx b/Source/CTest/cmCTestUploadHandler.cxx
index caf2e5370..05a39840d 100644
--- a/Source/CTest/cmCTestUploadHandler.cxx
+++ b/Source/CTest/cmCTestUploadHandler.cxx
@@ -1,27 +1,20 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestUploadHandler.h"
#include "cmGeneratedFileStream.h"
#include "cmVersion.h"
-#include "cmXMLSafe.h"
+#include "cmXMLWriter.h"
+
+#include <ostream>
+#include <set>
+#include <string>
-//----------------------------------------------------------------------------
cmCTestUploadHandler::cmCTestUploadHandler()
{
this->Initialize();
}
-//----------------------------------------------------------------------------
void cmCTestUploadHandler::Initialize()
{
this->Superclass::Initialize();
@@ -33,45 +26,48 @@ void cmCTestUploadHandler::SetFiles(const cmCTest::SetOfStrings& files)
this->Files = files;
}
-//----------------------------------------------------------------------------
int cmCTestUploadHandler::ProcessHandler()
{
cmGeneratedFileStream ofs;
- if ( !this->CTest->OpenOutputFile(this->CTest->GetCurrentTag(),
- "Upload.xml", ofs))
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot open Upload.xml file" << std::endl);
+ if (!this->CTest->OpenOutputFile(this->CTest->GetCurrentTag(), "Upload.xml",
+ ofs)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open Upload.xml file"
+ << std::endl);
return -1;
- }
-
+ }
+ std::string buildname =
+ cmCTest::SafeBuildIdField(this->CTest->GetCTestConfiguration("BuildName"));
cmCTest::SetOfStrings::const_iterator it;
- ofs << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- << "<?xml-stylesheet type=\"text/xsl\" "
- "href=\"Dart/Source/Server/XSL/Build.xsl "
- "<file:///Dart/Source/Server/XSL/Build.xsl> \"?>\n"
- << "<Site BuildName=\""
- << this->CTest->GetCTestConfiguration("BuildName")
- << "\" BuildStamp=\""
- << this->CTest->GetCurrentTag() << "-"
- << this->CTest->GetTestModelString() << "\" Name=\""
- << this->CTest->GetCTestConfiguration("Site") << "\" Generator=\"ctest"
- << cmVersion::GetCMakeVersion()
- << "\">\n";
- this->CTest->AddSiteProperties(ofs);
- ofs << "<Upload>\n";
- for ( it = this->Files.begin(); it != this->Files.end(); it ++ )
- {
- cmCTestLog(this->CTest, OUTPUT,
- "\tUpload file: " << it->c_str() << std::endl);
- ofs << "<File filename=\"" << cmXMLSafe(*it) << "\">\n"
- << "<Content encoding=\"base64\">\n";
- ofs << this->CTest->Base64EncodeFile(*it);
- ofs << "\n</Content>\n"
- << "</File>\n";
- }
- ofs << "</Upload>\n"
- << "</Site>\n";
+ cmXMLWriter xml(ofs);
+ xml.StartDocument();
+ xml.ProcessingInstruction("xml-stylesheet",
+ "type=\"text/xsl\" "
+ "href=\"Dart/Source/Server/XSL/Build.xsl "
+ "<file:///Dart/Source/Server/XSL/Build.xsl> \"");
+ xml.StartElement("Site");
+ xml.Attribute("BuildName", buildname);
+ xml.Attribute("BuildStamp", this->CTest->GetCurrentTag() + "-" +
+ this->CTest->GetTestModelString());
+ xml.Attribute("Name", this->CTest->GetCTestConfiguration("Site"));
+ xml.Attribute("Generator",
+ std::string("ctest") + cmVersion::GetCMakeVersion());
+ this->CTest->AddSiteProperties(xml);
+ xml.StartElement("Upload");
+
+ for (it = this->Files.begin(); it != this->Files.end(); it++) {
+ cmCTestOptionalLog(this->CTest, OUTPUT,
+ "\tUpload file: " << *it << std::endl, this->Quiet);
+ xml.StartElement("File");
+ xml.Attribute("filename", *it);
+ xml.StartElement("Content");
+ xml.Attribute("encoding", "base64");
+ xml.Content(this->CTest->Base64EncodeFile(*it));
+ xml.EndElement(); // Content
+ xml.EndElement(); // File
+ }
+ xml.EndElement(); // Upload
+ xml.EndElement(); // Site
+ xml.EndDocument();
return 0;
}
diff --git a/Source/CTest/cmCTestUploadHandler.h b/Source/CTest/cmCTestUploadHandler.h
index 23ed35a25..1e8d3c801 100644
--- a/Source/CTest/cmCTestUploadHandler.h
+++ b/Source/CTest/cmCTestUploadHandler.h
@@ -1,17 +1,11 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestUploadHandler_h
#define cmCTestUploadHandler_h
+#include "cmConfigure.h"
+
+#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
/** \class cmCTestUploadHandler
@@ -23,17 +17,17 @@
class cmCTestUploadHandler : public cmCTestGenericHandler
{
public:
- cmTypeMacro(cmCTestUploadHandler, cmCTestGenericHandler);
+ typedef cmCTestGenericHandler Superclass;
cmCTestUploadHandler();
- ~cmCTestUploadHandler() {}
+ ~cmCTestUploadHandler() CM_OVERRIDE {}
/*
* The main entry point for this class
*/
- int ProcessHandler();
+ int ProcessHandler() CM_OVERRIDE;
- void Initialize();
+ void Initialize() CM_OVERRIDE;
/** Specify a set of files to submit. */
void SetFiles(cmCTest::SetOfStrings const& files);
diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx
index fbee2272e..fb2742e08 100644
--- a/Source/CTest/cmCTestVC.cxx
+++ b/Source/CTest/cmCTestVC.cxx
@@ -1,24 +1,20 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestVC.h"
#include "cmCTest.h"
#include "cmSystemTools.h"
-#include "cmXMLSafe.h"
+#include "cmXMLWriter.h"
-#include <cmsys/Process.h>
+#include "cmsys/Process.h"
+#include <sstream>
+#include <stdio.h>
+#include <time.h>
+#include <vector>
-//----------------------------------------------------------------------------
-cmCTestVC::cmCTestVC(cmCTest* ct, std::ostream& log): CTest(ct), Log(log)
+cmCTestVC::cmCTestVC(cmCTest* ct, std::ostream& log)
+ : CTest(ct)
+ , Log(log)
{
this->PathCount[PathUpdated] = 0;
this->PathCount[PathModified] = 0;
@@ -28,24 +24,20 @@ cmCTestVC::cmCTestVC(cmCTest* ct, std::ostream& log): CTest(ct), Log(log)
this->Unknown.Rev = "Unknown";
}
-//----------------------------------------------------------------------------
cmCTestVC::~cmCTestVC()
{
}
-//----------------------------------------------------------------------------
void cmCTestVC::SetCommandLineTool(std::string const& tool)
{
this->CommandLineTool = tool;
}
-//----------------------------------------------------------------------------
void cmCTestVC::SetSourceDirectory(std::string const& dir)
{
this->SourceDirectory = dir;
}
-//----------------------------------------------------------------------------
bool cmCTestVC::InitialCheckout(const char* command)
{
cmCTestLog(this->CTest, HANDLER_OUTPUT,
@@ -55,22 +47,20 @@ bool cmCTestVC::InitialCheckout(const char* command)
std::string parent = cmSystemTools::GetFilenamePath(this->SourceDirectory);
cmCTestLog(this->CTest, HANDLER_OUTPUT,
" Perform checkout in directory: " << parent << "\n");
- if(!cmSystemTools::MakeDirectory(parent.c_str()))
- {
+ if (!cmSystemTools::MakeDirectory(parent.c_str())) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Cannot create directory: " << parent << std::endl);
return false;
- }
+ }
// Construct the initial checkout command line.
- std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);
+ std::vector<std::string> args = cmSystemTools::ParseArguments(command);
std::vector<char const*> vc_co;
- for(std::vector<cmStdString>::const_iterator ai = args.begin();
- ai != args.end(); ++ai)
- {
+ for (std::vector<std::string>::const_iterator ai = args.begin();
+ ai != args.end(); ++ai) {
vc_co.push_back(ai->c_str());
- }
- vc_co.push_back(0);
+ }
+ vc_co.push_back(CM_NULLPTR);
// Run the initial checkout command and log its output.
this->Log << "--- Begin Initial Checkout ---\n";
@@ -78,60 +68,54 @@ bool cmCTestVC::InitialCheckout(const char* command)
OutputLogger err(this->Log, "co-err> ");
bool result = this->RunChild(&vc_co[0], &out, &err, parent.c_str());
this->Log << "--- End Initial Checkout ---\n";
- if(!result)
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Initial checkout failed!" << std::endl);
- }
+ if (!result) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Initial checkout failed!"
+ << std::endl);
+ }
return result;
}
-//----------------------------------------------------------------------------
bool cmCTestVC::RunChild(char const* const* cmd, OutputParser* out,
- OutputParser* err, const char* workDir)
+ OutputParser* err, const char* workDir,
+ Encoding encoding)
{
this->Log << this->ComputeCommandLine(cmd) << "\n";
cmsysProcess* cp = cmsysProcess_New();
cmsysProcess_SetCommand(cp, cmd);
- workDir = workDir? workDir : this->SourceDirectory.c_str();
+ workDir = workDir ? workDir : this->SourceDirectory.c_str();
cmsysProcess_SetWorkingDirectory(cp, workDir);
- this->RunProcess(cp, out, err);
+ this->RunProcess(cp, out, err, encoding);
int result = cmsysProcess_GetExitValue(cp);
cmsysProcess_Delete(cp);
return result == 0;
}
-//----------------------------------------------------------------------------
std::string cmCTestVC::ComputeCommandLine(char const* const* cmd)
{
- cmOStringStream line;
+ std::ostringstream line;
const char* sep = "";
- for(const char* const* arg = cmd; *arg; ++arg)
- {
+ for (const char* const* arg = cmd; *arg; ++arg) {
line << sep << "\"" << *arg << "\"";
sep = " ";
- }
+ }
return line.str();
}
-//----------------------------------------------------------------------------
-bool cmCTestVC::RunUpdateCommand(char const* const* cmd,
- OutputParser* out, OutputParser* err)
+bool cmCTestVC::RunUpdateCommand(char const* const* cmd, OutputParser* out,
+ OutputParser* err, Encoding encoding)
{
// Report the command line.
this->UpdateCommandLine = this->ComputeCommandLine(cmd);
- if(this->CTest->GetShowOnly())
- {
+ if (this->CTest->GetShowOnly()) {
this->Log << this->UpdateCommandLine << "\n";
return true;
- }
+ }
// Run the command.
- return this->RunChild(cmd, out, err);
+ return this->RunChild(cmd, out, err, CM_NULLPTR, encoding);
}
-//----------------------------------------------------------------------------
std::string cmCTestVC::GetNightlyTime()
{
// Get the nightly start time corresponding to the current dau.
@@ -139,17 +123,11 @@ std::string cmCTestVC::GetNightlyTime()
this->CTest->GetCTestConfiguration("NightlyStartTime"),
this->CTest->GetTomorrowTag());
char current_time[1024];
- sprintf(current_time, "%04d-%02d-%02d %02d:%02d:%02d",
- t->tm_year + 1900,
- t->tm_mon + 1,
- t->tm_mday,
- t->tm_hour,
- t->tm_min,
- t->tm_sec);
+ sprintf(current_time, "%04d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900,
+ t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
return std::string(current_time);
}
-//----------------------------------------------------------------------------
void cmCTestVC::Cleanup()
{
this->Log << "--- Begin Cleanup ---\n";
@@ -157,36 +135,39 @@ void cmCTestVC::Cleanup()
this->Log << "--- End Cleanup ---\n";
}
-//----------------------------------------------------------------------------
void cmCTestVC::CleanupImpl()
{
// We do no cleanup by default.
}
-//----------------------------------------------------------------------------
bool cmCTestVC::Update()
{
- this->NoteOldRevision();
- this->Log << "--- Begin Update ---\n";
- bool result = this->UpdateImpl();
- this->Log << "--- End Update ---\n";
- this->NoteNewRevision();
+ bool result = true;
+ // if update version only is on then do not actually update,
+ // just note the current version and finish
+ if (!cmSystemTools::IsOn(
+ this->CTest->GetCTestConfiguration("UpdateVersionOnly").c_str())) {
+ result = this->NoteOldRevision() && result;
+ this->Log << "--- Begin Update ---\n";
+ result = this->UpdateImpl() && result;
+ this->Log << "--- End Update ---\n";
+ }
+ result = this->NoteNewRevision() && result;
return result;
}
-//----------------------------------------------------------------------------
-void cmCTestVC::NoteOldRevision()
+bool cmCTestVC::NoteOldRevision()
{
// We do nothing by default.
+ return true;
}
-//----------------------------------------------------------------------------
-void cmCTestVC::NoteNewRevision()
+bool cmCTestVC::NoteNewRevision()
{
// We do nothing by default.
+ return true;
}
-//----------------------------------------------------------------------------
bool cmCTestVC::UpdateImpl()
{
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
@@ -194,8 +175,7 @@ bool cmCTestVC::UpdateImpl()
return true;
}
-//----------------------------------------------------------------------------
-bool cmCTestVC::WriteXML(std::ostream& xml)
+bool cmCTestVC::WriteXML(cmXMLWriter& xml)
{
this->Log << "--- Begin Revisions ---\n";
bool result = this->WriteXMLUpdates(xml);
@@ -203,39 +183,33 @@ bool cmCTestVC::WriteXML(std::ostream& xml)
return result;
}
-//----------------------------------------------------------------------------
-bool cmCTestVC::WriteXMLUpdates(std::ostream&)
+bool cmCTestVC::WriteXMLUpdates(cmXMLWriter& /*unused*/)
{
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"* CTest cannot extract updates for this VCS tool.\n");
return true;
}
-//----------------------------------------------------------------------------
-void cmCTestVC::WriteXMLEntry(std::ostream& xml,
- std::string const& path,
- std::string const& name,
- std::string const& full,
+void cmCTestVC::WriteXMLEntry(cmXMLWriter& xml, std::string const& path,
+ std::string const& name, std::string const& full,
File const& f)
{
- static const char* desc[3] = { "Updated", "Modified", "Conflicting"};
- Revision const& rev = f.Rev? *f.Rev : this->Unknown;
- std::string prior = f.PriorRev? f.PriorRev->Rev : std::string("Unknown");
- xml << "\t\t<" << desc[f.Status] << ">\n"
- << "\t\t\t<File>" << cmXMLSafe(name) << "</File>\n"
- << "\t\t\t<Directory>" << cmXMLSafe(path) << "</Directory>\n"
- << "\t\t\t<FullName>" << cmXMLSafe(full) << "</FullName>\n"
- << "\t\t\t<CheckinDate>" << cmXMLSafe(rev.Date) << "</CheckinDate>\n"
- << "\t\t\t<Author>" << cmXMLSafe(rev.Author) << "</Author>\n"
- << "\t\t\t<Email>" << cmXMLSafe(rev.EMail) << "</Email>\n"
- << "\t\t\t<Committer>" << cmXMLSafe(rev.Committer) << "</Committer>\n"
- << "\t\t\t<CommitterEmail>" << cmXMLSafe(rev.CommitterEMail)
- << "</CommitterEmail>\n"
- << "\t\t\t<CommitDate>" << cmXMLSafe(rev.CommitDate)
- << "</CommitDate>\n"
- << "\t\t\t<Log>" << cmXMLSafe(rev.Log) << "</Log>\n"
- << "\t\t\t<Revision>" << cmXMLSafe(rev.Rev) << "</Revision>\n"
- << "\t\t\t<PriorRevision>" << cmXMLSafe(prior) << "</PriorRevision>\n"
- << "\t\t</" << desc[f.Status] << ">\n";
+ static const char* desc[3] = { "Updated", "Modified", "Conflicting" };
+ Revision const& rev = f.Rev ? *f.Rev : this->Unknown;
+ std::string prior = f.PriorRev ? f.PriorRev->Rev : std::string("Unknown");
+ xml.StartElement(desc[f.Status]);
+ xml.Element("File", name);
+ xml.Element("Directory", path);
+ xml.Element("FullName", full);
+ xml.Element("CheckinDate", rev.Date);
+ xml.Element("Author", rev.Author);
+ xml.Element("Email", rev.EMail);
+ xml.Element("Committer", rev.Committer);
+ xml.Element("CommitterEmail", rev.CommitterEMail);
+ xml.Element("CommitDate", rev.CommitDate);
+ xml.Element("Log", rev.Log);
+ xml.Element("Revision", rev.Rev);
+ xml.Element("PriorRevision", prior);
+ xml.EndElement();
++this->PathCount[f.Status];
}
diff --git a/Source/CTest/cmCTestVC.h b/Source/CTest/cmCTestVC.h
index 9dd06515d..6400bcda3 100644
--- a/Source/CTest/cmCTestVC.h
+++ b/Source/CTest/cmCTestVC.h
@@ -1,26 +1,24 @@
-/*============================================================================
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestVC_h
#define cmCTestVC_h
+#include "cmConfigure.h"
+
+#include <iosfwd>
+#include <string>
+
+#include "cmProcessOutput.h"
#include "cmProcessTools.h"
class cmCTest;
+class cmXMLWriter;
/** \class cmCTestVC
* \brief Base class for version control system handlers
*
*/
-class cmCTestVC: public cmProcessTools
+class cmCTestVC : public cmProcessTools
{
public:
/** Construct with a CTest instance and update log stream. */
@@ -48,13 +46,20 @@ public:
/** Get the command line used by the Update method. */
std::string const& GetUpdateCommandLine() const
- { return this->UpdateCommandLine; }
+ {
+ return this->UpdateCommandLine;
+ }
/** Write Update.xml entries for the updates found. */
- bool WriteXML(std::ostream& xml);
+ bool WriteXML(cmXMLWriter& xml);
/** Enumerate non-trivial working tree states during update. */
- enum PathStatus { PathUpdated, PathModified, PathConflicting };
+ enum PathStatus
+ {
+ PathUpdated,
+ PathModified,
+ PathConflicting
+ };
/** Get the number of working tree paths in each state after update. */
int GetPathCount(PathStatus s) const { return this->PathCount[s]; }
@@ -62,13 +67,14 @@ public:
protected:
// Internal API to be implemented by subclasses.
virtual void CleanupImpl();
- virtual void NoteOldRevision();
+ virtual bool NoteOldRevision();
virtual bool UpdateImpl();
- virtual void NoteNewRevision();
- virtual bool WriteXMLUpdates(std::ostream& xml);
+ virtual bool NoteNewRevision();
+ virtual bool WriteXMLUpdates(cmXMLWriter& xml);
#if defined(__SUNPRO_CC) && __SUNPRO_CC <= 0x510
-public: // Sun CC 5.1 needs help to allow cmCTestSVN::Revision to see this
+ // Sun CC 5.1 needs help to allow cmCTestSVN::Revision to see this
+public:
#endif
/** Basic information about one revision of a tree or file. */
struct Revision
@@ -84,7 +90,6 @@ public: // Sun CC 5.1 needs help to allow cmCTestSVN::Revision to see this
};
protected:
- struct File;
friend struct File;
/** Represent change to one file. */
@@ -93,24 +98,35 @@ protected:
PathStatus Status;
Revision const* Rev;
Revision const* PriorRev;
- File(): Status(PathUpdated), Rev(0), PriorRev(0) {}
- File(PathStatus status, Revision const* rev, Revision const* priorRev):
- Status(status), Rev(rev), PriorRev(priorRev) {}
+ File()
+ : Status(PathUpdated)
+ , Rev(CM_NULLPTR)
+ , PriorRev(CM_NULLPTR)
+ {
+ }
+ File(PathStatus status, Revision const* rev, Revision const* priorRev)
+ : Status(status)
+ , Rev(rev)
+ , PriorRev(priorRev)
+ {
+ }
};
/** Convert a list of arguments to a human-readable command line. */
static std::string ComputeCommandLine(char const* const* cmd);
/** Run a command line and send output to given parsers. */
- bool RunChild(char const* const* cmd, OutputParser* out,
- OutputParser* err, const char* workDir = 0);
+ bool RunChild(char const* const* cmd, OutputParser* out, OutputParser* err,
+ const char* workDir = CM_NULLPTR,
+ Encoding encoding = cmProcessOutput::Auto);
/** Run VC update command line and send output to given parsers. */
- bool RunUpdateCommand(char const* const* cmd,
- OutputParser* out, OutputParser* err = 0);
+ bool RunUpdateCommand(char const* const* cmd, OutputParser* out,
+ OutputParser* err = CM_NULLPTR,
+ Encoding encoding = cmProcessOutput::Auto);
/** Write xml element for one file. */
- void WriteXMLEntry(std::ostream& xml, std::string const& path,
+ void WriteXMLEntry(cmXMLWriter& xml, std::string const& path,
std::string const& name, std::string const& full,
File const& f);
diff --git a/Source/CTest/cmParseBlanketJSCoverage.cxx b/Source/CTest/cmParseBlanketJSCoverage.cxx
new file mode 100644
index 000000000..83a7b75eb
--- /dev/null
+++ b/Source/CTest/cmParseBlanketJSCoverage.cxx
@@ -0,0 +1,139 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmParseBlanketJSCoverage.h"
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmSystemTools.h"
+
+#include "cmsys/FStream.hxx"
+#include <stdio.h>
+#include <stdlib.h>
+
+class cmParseBlanketJSCoverage::JSONParser
+{
+public:
+ typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector
+ FileLinesType;
+ JSONParser(cmCTestCoverageHandlerContainer& cont)
+ : Coverage(cont)
+ {
+ }
+
+ virtual ~JSONParser() {}
+
+ std::string getValue(std::string const& line, int type)
+ {
+ size_t begIndex;
+ size_t endIndex;
+ endIndex = line.rfind(',');
+ begIndex = line.find_first_of(':');
+ if (type == 0) {
+ // A unique substring to remove the extra characters
+ // around the files name in the JSON (extra " and ,)
+ std::string foundFileName =
+ line.substr(begIndex + 3, endIndex - (begIndex + 4));
+ return foundFileName;
+ }
+ return line.substr(begIndex);
+ }
+ bool ParseFile(std::string const& file)
+ {
+ FileLinesType localCoverageVector;
+ std::string filename;
+ bool foundFile = false;
+ bool inSource = false;
+ std::string covResult;
+ std::string line;
+
+ cmsys::ifstream in(file.c_str());
+ if (!in) {
+ return false;
+ }
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ if (line.find("filename") != std::string::npos) {
+ if (foundFile) {
+ /*
+ * Upon finding a second file name, generate a
+ * vector within the total coverage to capture the
+ * information in the local vector
+ */
+ FileLinesType& CoverageVector =
+ this->Coverage.TotalCoverage[filename];
+ CoverageVector = localCoverageVector;
+ localCoverageVector.clear();
+ }
+ foundFile = true;
+ inSource = false;
+ filename = getValue(line, 0);
+ } else if ((line.find("coverage") != std::string::npos) && foundFile &&
+ inSource) {
+ /*
+ * two types of "coverage" in the JSON structure
+ *
+ * The coverage result over the file or set of files
+ * and the coverage for each individual line
+ *
+ * FoundFile and foundSource ensure that
+ * only the value of the line coverage is captured
+ */
+ std::string result = getValue(line, 1);
+ result = result.substr(2);
+ if (result == "\"\"") {
+ // Empty quotation marks indicate that the
+ // line is not executable
+ localCoverageVector.push_back(-1);
+ } else {
+ // Else, it contains the number of time executed
+ localCoverageVector.push_back(atoi(result.c_str()));
+ }
+ } else if (line.find("source") != std::string::npos) {
+ inSource = true;
+ }
+ }
+
+ // On exit, capture end of last file covered.
+ FileLinesType& CoverageVector = this->Coverage.TotalCoverage[filename];
+ CoverageVector = localCoverageVector;
+ localCoverageVector.clear();
+ return true;
+ }
+
+private:
+ cmCTestCoverageHandlerContainer& Coverage;
+};
+
+cmParseBlanketJSCoverage::cmParseBlanketJSCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+bool cmParseBlanketJSCoverage::LoadCoverageData(std::vector<std::string> files)
+{
+ size_t i = 0;
+ std::string path;
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found " << files.size() << " Files" << std::endl,
+ this->Coverage.Quiet);
+ for (i = 0; i < files.size(); i++) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading JSON File " << files[i] << std::endl,
+ this->Coverage.Quiet);
+
+ if (!this->ReadJSONFile(files[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmParseBlanketJSCoverage::ReadJSONFile(std::string const& file)
+{
+ cmParseBlanketJSCoverage::JSONParser parser(this->Coverage);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Parsing " << file << std::endl, this->Coverage.Quiet);
+ parser.ParseFile(file);
+ return true;
+}
diff --git a/Source/CTest/cmParseBlanketJSCoverage.h b/Source/CTest/cmParseBlanketJSCoverage.h
new file mode 100644
index 000000000..696121f21
--- /dev/null
+++ b/Source/CTest/cmParseBlanketJSCoverage.h
@@ -0,0 +1,42 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmParseBlanketJSCoverage_h
+#define cmParseBlanketJSCoverage_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
+
+/** \class cmParseBlanketJSCoverage
+ * \brief Parse BlanketJS coverage information
+ *
+ * This class is used to parse BlanketJS(Pascal) coverage information
+ * generated by the Blanket.js library when used in conjunction with the
+ * test runner mocha.js, which is used to write out the JSON format.
+ *
+ * Blanket.js:
+ * http://blanketjs.org/
+ *
+ * Mocha.js
+ * http://visionmedia.github.io/mocha/
+ */
+class cmParseBlanketJSCoverage
+{
+public:
+ cmParseBlanketJSCoverage(cmCTestCoverageHandlerContainer& cont,
+ cmCTest* ctest);
+ bool LoadCoverageData(std::vector<std::string> files);
+ // Read the JSON output
+ bool ReadJSONFile(std::string const& file);
+
+protected:
+ class JSONParser;
+
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+};
+#endif
diff --git a/Source/CTest/cmParseCacheCoverage.cxx b/Source/CTest/cmParseCacheCoverage.cxx
index 137f344df..629010cf1 100644
--- a/Source/CTest/cmParseCacheCoverage.cxx
+++ b/Source/CTest/cmParseCacheCoverage.cxx
@@ -1,49 +1,45 @@
-#include "cmStandardIncludes.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include "cmSystemTools.h"
#include "cmParseCacheCoverage.h"
-#include <cmsys/Directory.hxx>
-#include <cmsys/Glob.hxx>
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmSystemTools.h"
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+#include <map>
+#include <stdio.h>
+#include <stdlib.h>
+#include <utility>
cmParseCacheCoverage::cmParseCacheCoverage(
- cmCTestCoverageHandlerContainer& cont,
- cmCTest* ctest)
- :cmParseMumpsCoverage(cont, ctest)
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : cmParseMumpsCoverage(cont, ctest)
{
}
-
bool cmParseCacheCoverage::LoadCoverageData(const char* d)
{
// load all the .mcov files in the specified directory
cmsys::Directory dir;
- if(!dir.Load(d))
- {
+ if (!dir.Load(d)) {
return false;
- }
+ }
size_t numf;
unsigned int i;
numf = dir.GetNumberOfFiles();
- for (i = 0; i < numf; i++)
- {
+ for (i = 0; i < numf; i++) {
std::string file = dir.GetFile(i);
- if(file != "." && file != ".."
- && !cmSystemTools::FileIsDirectory(file.c_str()))
- {
+ if (file != "." && file != ".." && !cmSystemTools::FileIsDirectory(file)) {
std::string path = d;
path += "/";
path += file;
- if(cmSystemTools::GetFilenameLastExtension(path) == ".cmcov")
- {
- if(!this->ReadCMCovFile(path.c_str()))
- {
+ if (cmSystemTools::GetFilenameLastExtension(path) == ".cmcov") {
+ if (!this->ReadCMCovFile(path.c_str())) {
return false;
- }
}
}
}
+ }
return true;
}
@@ -54,32 +50,26 @@ void cmParseCacheCoverage::RemoveUnCoveredFiles()
// that only have -1 or 0 for the lines.
cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator ci =
this->Coverage.TotalCoverage.begin();
- while(ci != this->Coverage.TotalCoverage.end())
- {
- cmCTestCoverageHandlerContainer::SingleFileCoverageVector& v =
- ci->second;
+ while (ci != this->Coverage.TotalCoverage.end()) {
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& v = ci->second;
bool nothing = true;
- for(cmCTestCoverageHandlerContainer::SingleFileCoverageVector::iterator i=
- v.begin(); i != v.end(); ++i)
- {
- if(*i > 0)
- {
+ for (cmCTestCoverageHandlerContainer::SingleFileCoverageVector::iterator
+ i = v.begin();
+ i != v.end(); ++i) {
+ if (*i > 0) {
nothing = false;
break;
- }
}
- if(nothing)
- {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "No coverage found in: " << ci->first
- << std::endl);
+ }
+ if (nothing) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "No coverage found in: " << ci->first << std::endl,
+ this->Coverage.Quiet);
this->Coverage.TotalCoverage.erase(ci++);
- }
- else
- {
+ } else {
++ci;
- }
}
+ }
}
bool cmParseCacheCoverage::SplitString(std::vector<std::string>& args,
@@ -87,18 +77,16 @@ bool cmParseCacheCoverage::SplitString(std::vector<std::string>& args,
{
std::string::size_type pos1 = 0;
std::string::size_type pos2 = line.find(',', 0);
- if(pos2 == std::string::npos)
- {
+ if (pos2 == std::string::npos) {
return false;
- }
+ }
std::string arg;
- while(pos2 != std::string::npos)
- {
- arg = line.substr(pos1, pos2-pos1);
+ while (pos2 != std::string::npos) {
+ arg = line.substr(pos1, pos2 - pos1);
args.push_back(arg);
- pos1 = pos2+1;
- pos2 = line.find(',',pos1);
- }
+ pos1 = pos2 + 1;
+ pos2 = line.find(',', pos1);
+ }
arg = line.substr(pos1);
args.push_back(arg);
return true;
@@ -106,115 +94,107 @@ bool cmParseCacheCoverage::SplitString(std::vector<std::string>& args,
bool cmParseCacheCoverage::ReadCMCovFile(const char* file)
{
- std::ifstream in(file);
- if(!in)
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Can not open : "
- << file << "\n");
+ cmsys::ifstream in(file);
+ if (!in) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Can not open : " << file << "\n");
return false;
- }
+ }
std::string line;
std::vector<std::string> separateLine;
- if(!cmSystemTools::GetLineFromStream(in, line))
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Empty file : "
- << file << " referenced in this line of cmcov data:\n"
- "[" << line << "]\n");
+ if (!cmSystemTools::GetLineFromStream(in, line)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Empty file : "
+ << file << " referenced in this line of cmcov data:\n"
+ "["
+ << line << "]\n");
return false;
- }
+ }
separateLine.clear();
this->SplitString(separateLine, line);
- if(separateLine.size() !=4 || separateLine[0] != "Routine"
- || separateLine[1] != "Line" || separateLine[2] != "RtnLine"
- || separateLine[3] != "Code")
- {
+ if (separateLine.size() != 4 || separateLine[0] != "Routine" ||
+ separateLine[1] != "Line" || separateLine[2] != "RtnLine" ||
+ separateLine[3] != "Code") {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Bad first line of cmcov file : "
- << file << " line:\n"
- "[" << line << "]\n");
- }
+ "Bad first line of cmcov file : " << file << " line:\n"
+ "["
+ << line << "]\n");
+ }
std::string routine;
std::string filepath;
- while(cmSystemTools::GetLineFromStream(in, line))
- {
+ while (cmSystemTools::GetLineFromStream(in, line)) {
// clear out line argument vector
separateLine.clear();
// parse the comma separated line
this->SplitString(separateLine, line);
// might have more because code could have a quoted , in it
// but we only care about the first 3 args anyway
- if(separateLine.size() < 4)
- {
+ if (separateLine.size() < 4) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Bad line of cmcov file expected at least 4 found: "
- << separateLine.size() << " "
- << file << " line:\n"
- "[" << line << "]\n");
- for(std::string::size_type i = 0; i < separateLine.size(); ++i)
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,""
- << separateLine[1] << " ");
- }
+ << separateLine.size() << " " << file << " line:\n"
+ "["
+ << line << "]\n");
+ for (std::string::size_type i = 0; i < separateLine.size(); ++i) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "" << separateLine[1] << " ");
+ }
cmCTestLog(this->CTest, ERROR_MESSAGE, "\n");
return false;
- }
+ }
// if we do not have a routine yet, then it should be
// the first argument in the vector
- if(routine.size() == 0)
- {
+ if (routine.empty()) {
routine = separateLine[0];
// Find the full path to the file
- if(!this->FindMumpsFile(routine, filepath))
- {
+ if (!this->FindMumpsFile(routine, filepath)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Could not find mumps file for routine: "
- << routine << "\n");
+ "Could not find mumps file for routine: " << routine
+ << "\n");
filepath = "";
continue; // move to next line
- }
}
+ }
// if we have a routine name, check for end of routine
- else
- {
+ else {
// Totals in arg 0 marks the end of a routine
- if(separateLine[0].substr(0, 6) == "Totals")
- {
+ if (separateLine[0].substr(0, 6) == "Totals") {
routine = ""; // at the end of this routine
filepath = "";
continue; // move to next line
- }
}
+ }
// if the file path was not found for the routine
// move to next line. We should have already warned
// after the call to FindMumpsFile that we did not find
// it, so don't report again to cut down on output
- if(filepath.size() == 0)
- {
+ if (filepath.empty()) {
continue;
- }
+ }
// now we are ready to set the coverage from the line of data
- cmCTestCoverageHandlerContainer::SingleFileCoverageVector&
- coverageVector = this->Coverage.TotalCoverage[filepath];
- std::string::size_type linenumber = atoi(separateLine[1].c_str()) -1;
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector =
+ this->Coverage.TotalCoverage[filepath];
+ std::string::size_type linenumber = atoi(separateLine[1].c_str()) - 1;
int count = atoi(separateLine[2].c_str());
- if(linenumber > coverageVector.size())
- {
+ if (linenumber > coverageVector.size()) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Parse error line is greater than number of lines in file: "
- << linenumber << " " << filepath << "\n");
+ << linenumber << " " << filepath << "\n");
continue; // skip setting count to avoid crash
- }
+ }
// now add to count for linenumber
// for some reason the cache coverage adds extra lines to the
// end of the file in some cases. Since they do not exist, we will
// mark them as non executable
- while(linenumber >= coverageVector.size())
- {
+ while (linenumber >= coverageVector.size()) {
coverageVector.push_back(-1);
- }
- coverageVector[linenumber] += count;
}
+ // Accounts for lines that were previously marked
+ // as non-executable code (-1). if the parser comes back with
+ // a non-zero count, increase the count by 1 to push the line
+ // into the executable code set in addition to the count found.
+ if (coverageVector[linenumber] == -1 && count > 0) {
+ coverageVector[linenumber] += count + 1;
+ } else {
+ coverageVector[linenumber] += count;
+ }
+ }
return true;
}
diff --git a/Source/CTest/cmParseCacheCoverage.h b/Source/CTest/cmParseCacheCoverage.h
index 114eb92d3..005d27258 100644
--- a/Source/CTest/cmParseCacheCoverage.h
+++ b/Source/CTest/cmParseCacheCoverage.h
@@ -1,20 +1,18 @@
-/*============================================================================
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmParseCacheCoverage_h
#define cmParseCacheCoverage_h
+#include "cmConfigure.h"
+
#include "cmParseMumpsCoverage.h"
+#include <string>
+#include <vector>
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
+
/** \class cmParseCacheCoverage
* \brief Parse Cache coverage information
*
@@ -24,19 +22,17 @@
class cmParseCacheCoverage : public cmParseMumpsCoverage
{
public:
- cmParseCacheCoverage(cmCTestCoverageHandlerContainer& cont,
- cmCTest* ctest);
+ cmParseCacheCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+
protected:
// implement virtual from parent
- bool LoadCoverageData(const char* dir);
+ bool LoadCoverageData(const char* dir) CM_OVERRIDE;
// remove files with no coverage
void RemoveUnCoveredFiles();
// Read a single mcov file
bool ReadCMCovFile(const char* f);
// split a string based on ,
- bool SplitString(std::vector<std::string>& args,
- std::string const& line);
+ bool SplitString(std::vector<std::string>& args, std::string const& line);
};
-
#endif
diff --git a/Source/CTest/cmParseCoberturaCoverage.cxx b/Source/CTest/cmParseCoberturaCoverage.cxx
new file mode 100644
index 000000000..ba55cd7b2
--- /dev/null
+++ b/Source/CTest/cmParseCoberturaCoverage.cxx
@@ -0,0 +1,171 @@
+#include "cmParseCoberturaCoverage.h"
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+
+#include "cmConfigure.h"
+#include "cmsys/FStream.hxx"
+#include <stdlib.h>
+#include <string.h>
+
+class cmParseCoberturaCoverage::XMLParser : public cmXMLParser
+{
+public:
+ XMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont)
+ : CTest(ctest)
+ , Coverage(cont)
+ {
+ this->InSources = false;
+ this->InSource = false;
+ this->SkipThisClass = false;
+ this->FilePaths.push_back(this->Coverage.SourceDir);
+ this->FilePaths.push_back(this->Coverage.BinaryDir);
+ this->CurFileName = "";
+ }
+
+ ~XMLParser() CM_OVERRIDE {}
+
+protected:
+ void EndElement(const std::string& name) CM_OVERRIDE
+ {
+ if (name == "source") {
+ this->InSource = false;
+ } else if (name == "sources") {
+ this->InSources = false;
+ } else if (name == "class") {
+ this->SkipThisClass = false;
+ }
+ }
+
+ void CharacterDataHandler(const char* data, int length) CM_OVERRIDE
+ {
+ std::string tmp;
+ tmp.insert(0, data, length);
+ if (this->InSources && this->InSource) {
+ this->FilePaths.push_back(tmp);
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Adding Source: " << tmp << std::endl,
+ this->Coverage.Quiet);
+ }
+ }
+
+ void StartElement(const std::string& name, const char** atts) CM_OVERRIDE
+ {
+ std::string FoundSource;
+ std::string finalpath;
+ if (name == "source") {
+ this->InSource = true;
+ } else if (name == "sources") {
+ this->InSources = true;
+ } else if (name == "class") {
+ int tagCount = 0;
+ while (true) {
+ if (strcmp(atts[tagCount], "filename") == 0) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading file: " << atts[tagCount + 1]
+ << std::endl,
+ this->Coverage.Quiet);
+ std::string filename = atts[tagCount + 1];
+ this->CurFileName = "";
+
+ // Check if this is an absolute path that falls within our
+ // source or binary directories.
+ for (size_t i = 0; i < FilePaths.size(); i++) {
+ if (filename.find(FilePaths[i]) == 0) {
+ this->CurFileName = filename;
+ break;
+ }
+ }
+
+ if (this->CurFileName == "") {
+ // Check if this is a path that is relative to our source or
+ // binary directories.
+ for (size_t i = 0; i < FilePaths.size(); i++) {
+ finalpath = FilePaths[i] + "/" + filename;
+ if (cmSystemTools::FileExists(finalpath.c_str())) {
+ this->CurFileName = finalpath;
+ break;
+ }
+ }
+ }
+
+ cmsys::ifstream fin(this->CurFileName.c_str());
+ if (this->CurFileName == "" || !fin) {
+ this->CurFileName =
+ this->Coverage.BinaryDir + "/" + atts[tagCount + 1];
+ fin.open(this->CurFileName.c_str());
+ if (!fin) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Skipping system file " << filename
+ << std::endl,
+ this->Coverage.Quiet);
+
+ this->SkipThisClass = true;
+ break;
+ }
+ }
+ std::string line;
+ FileLinesType& curFileLines =
+ this->Coverage.TotalCoverage[this->CurFileName];
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ curFileLines.push_back(-1);
+ }
+
+ break;
+ }
+ ++tagCount;
+ }
+ } else if (name == "line") {
+ int tagCount = 0;
+ int curNumber = -1;
+ int curHits = -1;
+ while (true) {
+ if (this->SkipThisClass) {
+ break;
+ }
+ 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 > 0) {
+ FileLinesType& curFileLines =
+ this->Coverage.TotalCoverage[this->CurFileName];
+ {
+ curFileLines[curNumber - 1] = curHits;
+ }
+ break;
+ }
+ ++tagCount;
+ }
+ }
+ }
+
+private:
+ bool InSources;
+ bool InSource;
+ bool SkipThisClass;
+ std::vector<std::string> FilePaths;
+ typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector
+ FileLinesType;
+ cmCTest* CTest;
+ cmCTestCoverageHandlerContainer& Coverage;
+ std::string CurFileName;
+};
+
+cmParseCoberturaCoverage::cmParseCoberturaCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+bool cmParseCoberturaCoverage::ReadCoverageXML(const char* xmlFile)
+{
+ cmParseCoberturaCoverage::XMLParser parser(this->CTest, this->Coverage);
+ parser.ParseFile(xmlFile);
+ return true;
+}
diff --git a/Source/CTest/cmParseCoberturaCoverage.h b/Source/CTest/cmParseCoberturaCoverage.h
new file mode 100644
index 000000000..cb6d0976b
--- /dev/null
+++ b/Source/CTest/cmParseCoberturaCoverage.h
@@ -0,0 +1,45 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmParseCoberturaCoverage_h
+#define cmParseCoberturaCoverage_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
+
+/** \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 cmParseCoberturaCoverage
+{
+public:
+ //! Create the coverage parser by passing in the coverage handler
+ //! container and the cmCTest object
+ cmParseCoberturaCoverage(cmCTestCoverageHandlerContainer& cont,
+ cmCTest* ctest);
+
+ bool inSources;
+ bool inSource;
+ std::vector<std::string> filepaths;
+ //! Read the XML produced by running `coverage xml`
+ bool ReadCoverageXML(const char* xmlFile);
+
+private:
+ class XMLParser;
+
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+ std::string CurFileName;
+};
+
+#endif
diff --git a/Source/CTest/cmParseDelphiCoverage.cxx b/Source/CTest/cmParseDelphiCoverage.cxx
new file mode 100644
index 000000000..4b781a6db
--- /dev/null
+++ b/Source/CTest/cmParseDelphiCoverage.cxx
@@ -0,0 +1,229 @@
+#include "cmParseDelphiCoverage.h"
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmSystemTools.h"
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+#include <stdio.h>
+#include <stdlib.h>
+
+class cmParseDelphiCoverage::HTMLParser
+{
+public:
+ typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector
+ FileLinesType;
+ HTMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont)
+ : CTest(ctest)
+ , Coverage(cont)
+ {
+ }
+
+ virtual ~HTMLParser() {}
+
+ bool initializeDelphiFile(
+ std::string const& filename,
+ cmParseDelphiCoverage::HTMLParser::FileLinesType& coverageVector)
+ {
+ std::string line;
+ size_t comPos;
+ size_t semiPos;
+ bool blockComFlag = false;
+ bool lineComFlag = false;
+ std::vector<std::string> beginSet;
+ cmsys::ifstream in(filename.c_str());
+ if (!in) {
+ return false;
+ }
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ lineComFlag = false;
+ // Unique cases found in lines.
+ size_t beginPos = line.find("begin");
+
+ // Check that the begin is the first non-space string on the line
+ if ((beginPos == line.find_first_not_of(' ')) &&
+ beginPos != std::string::npos) {
+ beginSet.push_back("begin");
+ coverageVector.push_back(-1);
+ continue;
+ }
+ if (line.find('{') != std::string::npos) {
+ blockComFlag = true;
+ } else if (line.find('}') != std::string::npos) {
+ blockComFlag = false;
+ coverageVector.push_back(-1);
+ continue;
+ } else if ((line.find("end;") != std::string::npos) &&
+ !beginSet.empty()) {
+ beginSet.pop_back();
+ coverageVector.push_back(-1);
+ continue;
+ }
+
+ // This checks for comments after lines of code, finding the
+ // comment symbol after the ending semicolon.
+ comPos = line.find("//");
+ if (comPos != std::string::npos) {
+ semiPos = line.find(';');
+ if (comPos < semiPos) {
+ lineComFlag = true;
+ }
+ }
+ // Based up what was found, add a line to the coverageVector
+ if (!beginSet.empty() && line != "" && !blockComFlag && !lineComFlag) {
+ coverageVector.push_back(0);
+ } else {
+ coverageVector.push_back(-1);
+ }
+ }
+ return true;
+ }
+ bool ParseFile(const char* file)
+ {
+ std::string line = file;
+ std::string lineresult;
+ std::string lastroutine;
+ std::string filename;
+ std::string filelineoffset;
+ size_t afterLineNum = 0;
+ size_t lastoffset = 0;
+ size_t endcovpos = 0;
+ size_t endnamepos = 0;
+ size_t pos = 0;
+
+ /*
+ * This first 'while' section goes through the found HTML
+ * file name and attempts to capture the source file name
+ * which is set as part of the HTML file name: the name of
+ * the file is found in parenthesis '()'
+ *
+ * See test HTML file name: UTCovTest(UTCovTest.pas).html.
+ *
+ * Find the text inside each pair of parenthesis and check
+ * to see if it ends in '.pas'. If it can't be found,
+ * exit the function.
+ */
+ while (true) {
+ lastoffset = line.find('(', pos);
+ if (lastoffset == std::string::npos) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, endnamepos
+ << "File not found " << lastoffset << std::endl,
+ this->Coverage.Quiet);
+ return false;
+ }
+ endnamepos = line.find(')', lastoffset);
+ filename = line.substr(lastoffset + 1, (endnamepos - 1) - lastoffset);
+ if (filename.find(".pas") != std::string::npos) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Coverage found for file: " << filename
+ << std::endl,
+ this->Coverage.Quiet);
+ break;
+ }
+ pos = lastoffset + 1;
+ }
+ /*
+ * Glob through the source directory for the
+ * file found above
+ */
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOff();
+ std::string glob = Coverage.SourceDir + "*/" + filename;
+ gl.FindFiles(glob);
+ std::vector<std::string> const& files = gl.GetFiles();
+ if (files.empty()) {
+ /*
+ * If that doesn't find any matching files
+ * return a failure.
+ */
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Unable to find file matching" << glob << std::endl,
+ this->Coverage.Quiet);
+ return false;
+ }
+ FileLinesType& coverageVector = this->Coverage.TotalCoverage[files[0]];
+
+ /*
+ * Initialize the file to have all code between 'begin' and
+ * 'end' tags marked as executable
+ */
+
+ this->initializeDelphiFile(files[0], coverageVector);
+
+ cmsys::ifstream in(file);
+ if (!in) {
+ return false;
+ }
+
+ /*
+ * Now read the HTML file, looking for the lines that have an
+ * "inline" in it. Then parse out the "class" value of that
+ * line to determine if the line is executed or not.
+ *
+ * Sample HTML line:
+ *
+ * <tr class="covered"><td>47</td><td><pre style="display:inline;">
+ * &nbsp;CheckEquals(1,2-1);</pre></td></tr>
+ *
+ */
+
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ if (line.find("inline") == std::string::npos) {
+ continue;
+ }
+
+ lastoffset = line.find("class=");
+ endcovpos = line.find('>', lastoffset);
+ lineresult = line.substr(lastoffset + 7, (endcovpos - 8) - lastoffset);
+
+ if (lineresult == "covered") {
+ afterLineNum = line.find('<', endcovpos + 5);
+ filelineoffset =
+ line.substr(endcovpos + 5, afterLineNum - (endcovpos + 5));
+ coverageVector[atoi(filelineoffset.c_str()) - 1] = 1;
+ }
+ }
+ return true;
+ }
+
+private:
+ cmCTest* CTest;
+ cmCTestCoverageHandlerContainer& Coverage;
+};
+
+cmParseDelphiCoverage::cmParseDelphiCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+bool cmParseDelphiCoverage::LoadCoverageData(
+ std::vector<std::string> const& files)
+{
+ size_t i;
+ std::string path;
+ size_t numf = files.size();
+ for (i = 0; i < numf; i++) {
+ path = files[i];
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading HTML File " << path << std::endl,
+ this->Coverage.Quiet);
+ if (cmSystemTools::GetFilenameLastExtension(path) == ".html") {
+ if (!this->ReadDelphiHTML(path.c_str())) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool cmParseDelphiCoverage::ReadDelphiHTML(const char* file)
+{
+ cmParseDelphiCoverage::HTMLParser parser(this->CTest, this->Coverage);
+ parser.ParseFile(file);
+ return true;
+}
diff --git a/Source/CTest/cmParseDelphiCoverage.h b/Source/CTest/cmParseDelphiCoverage.h
new file mode 100644
index 000000000..1b374050a
--- /dev/null
+++ b/Source/CTest/cmParseDelphiCoverage.h
@@ -0,0 +1,38 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmParseDelphiCoverage_h
+#define cmParseDelphiCoverage_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
+
+/** \class cmParseDelphiCoverage
+ * \brief Parse Delphi coverage information
+ *
+ * This class is used to parse Delphi(Pascal) coverage information
+ * generated by the Delphi-Code-Coverage tool
+ *
+ * https://code.google.com/p/delphi-code-coverage/
+ */
+
+class cmParseDelphiCoverage
+{
+public:
+ cmParseDelphiCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+ bool LoadCoverageData(std::vector<std::string> const& files);
+ bool ReadDelphiHTML(const char* file);
+ // Read a single HTML file from output
+ bool ReadHTMLFile(const char* f);
+
+protected:
+ class HTMLParser;
+
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+};
+#endif
diff --git a/Source/CTest/cmParseGTMCoverage.cxx b/Source/CTest/cmParseGTMCoverage.cxx
index 6b4adb4bd..e4ee699c4 100644
--- a/Source/CTest/cmParseGTMCoverage.cxx
+++ b/Source/CTest/cmParseGTMCoverage.cxx
@@ -1,70 +1,64 @@
-#include "cmStandardIncludes.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include "cmSystemTools.h"
#include "cmParseGTMCoverage.h"
-#include <cmsys/Directory.hxx>
-#include <cmsys/Glob.hxx>
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmSystemTools.h"
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+#include <map>
+#include <stdio.h>
+#include <stdlib.h>
+#include <vector>
cmParseGTMCoverage::cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont,
cmCTest* ctest)
- :cmParseMumpsCoverage(cont, ctest)
+ : cmParseMumpsCoverage(cont, ctest)
{
}
-
bool cmParseGTMCoverage::LoadCoverageData(const char* d)
{
// load all the .mcov files in the specified directory
cmsys::Directory dir;
- if(!dir.Load(d))
- {
+ if (!dir.Load(d)) {
return false;
- }
+ }
size_t numf;
unsigned int i;
numf = dir.GetNumberOfFiles();
- for (i = 0; i < numf; i++)
- {
+ for (i = 0; i < numf; i++) {
std::string file = dir.GetFile(i);
- if(file != "." && file != ".."
- && !cmSystemTools::FileIsDirectory(file.c_str()))
- {
+ if (file != "." && file != ".." && !cmSystemTools::FileIsDirectory(file)) {
std::string path = d;
path += "/";
path += file;
- if(cmSystemTools::GetFilenameLastExtension(path) == ".mcov")
- {
- if(!this->ReadMCovFile(path.c_str()))
- {
+ if (cmSystemTools::GetFilenameLastExtension(path) == ".mcov") {
+ if (!this->ReadMCovFile(path.c_str())) {
return false;
- }
}
}
}
+ }
return true;
}
bool cmParseGTMCoverage::ReadMCovFile(const char* file)
{
- std::ifstream in(file);
- if(!in)
- {
+ cmsys::ifstream in(file);
+ if (!in) {
return false;
- }
+ }
std::string line;
std::string lastfunction;
std::string lastroutine;
std::string lastpath;
int lastoffset = 0;
- while( cmSystemTools::GetLineFromStream(in, line))
- {
+ while (cmSystemTools::GetLineFromStream(in, line)) {
// only look at lines that have coverage data
- if(line.find("^ZZCOVERAGE") == line.npos)
- {
+ if (line.find("^ZZCOVERAGE") == std::string::npos) {
continue;
- }
+ }
std::string filepath;
std::string function;
std::string routine;
@@ -72,54 +66,51 @@ bool cmParseGTMCoverage::ReadMCovFile(const char* file)
int count = 0;
this->ParseMCOVLine(line, routine, function, linenumber, count);
// skip this one
- if(routine == "RSEL")
- {
+ if (routine == "RSEL") {
continue;
- }
+ }
// no need to search the file if we just did it
- if(function == lastfunction && lastroutine == routine)
- {
- if(lastpath.size())
- {
- this->Coverage.TotalCoverage[lastpath][lastoffset + linenumber]
- += count;
- }
- else
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Can not find mumps file : "
- << lastroutine <<
- " referenced in this line of mcov data:\n"
- "[" << line << "]\n");
- }
- continue;
+ if (function == lastfunction && lastroutine == routine) {
+ if (!lastpath.empty()) {
+ this->Coverage.TotalCoverage[lastpath][lastoffset + linenumber] +=
+ count;
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Can not find mumps file : "
+ << lastroutine
+ << " referenced in this line of mcov data:\n"
+ "["
+ << line << "]\n");
}
+ continue;
+ }
// Find the full path to the file
bool found = this->FindMumpsFile(routine, filepath);
- if(found)
- {
+ if (found) {
int lineoffset = 0;
- if(this->FindFunctionInMumpsFile(filepath,
- function,
- lineoffset))
- {
+ if (this->FindFunctionInMumpsFile(filepath, function, lineoffset)) {
cmCTestCoverageHandlerContainer::SingleFileCoverageVector&
coverageVector = this->Coverage.TotalCoverage[filepath];
- coverageVector[lineoffset + linenumber] += count;
- lastoffset = lineoffset;
+ // This section accounts for lines that were previously marked
+ // as non-executable code (-1), if the parser comes back with
+ // a non-zero count, increase the count by 1 to push the line
+ // into the executable code set in addtion to the count found.
+ if (coverageVector[lineoffset + linenumber] == -1 && count > 0) {
+ coverageVector[lineoffset + linenumber] += count + 1;
+ } else {
+ coverageVector[lineoffset + linenumber] += count;
}
+ lastoffset = lineoffset;
}
- else
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Can not find mumps file : "
- << routine << " referenced in this line of mcov data:\n"
- "[" << line << "]\n");
- }
+ } else {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Can not find mumps file : "
+ << routine << " referenced in this line of mcov data:\n"
+ "["
+ << line << "]\n");
+ }
lastfunction = function;
lastroutine = routine;
lastpath = filepath;
- }
+ }
return true;
}
@@ -127,48 +118,40 @@ bool cmParseGTMCoverage::FindFunctionInMumpsFile(std::string const& filepath,
std::string const& function,
int& lineoffset)
{
- std::ifstream in(filepath.c_str());
- if(!in)
- {
+ cmsys::ifstream in(filepath.c_str());
+ if (!in) {
return false;
- }
+ }
std::string line;
int linenum = 0;
- while( cmSystemTools::GetLineFromStream(in, line))
- {
- std::string::size_type pos = line.find(function.c_str());
- if(pos == 0)
- {
+ while (cmSystemTools::GetLineFromStream(in, line)) {
+ std::string::size_type pos = line.find(function);
+ if (pos == 0) {
char nextchar = line[function.size()];
- if(nextchar == ' ' || nextchar == '(')
- {
+ if (nextchar == ' ' || nextchar == '(' || nextchar == '\t') {
lineoffset = linenum;
return true;
- }
}
- if(pos == 1)
- {
+ }
+ if (pos == 1) {
char prevchar = line[0];
- char nextchar = line[function.size()+1];
- if(prevchar == '%' && (nextchar == ' ' || nextchar == '('))
- {
+ char nextchar = line[function.size() + 1];
+ if (prevchar == '%' && (nextchar == ' ' || nextchar == '(')) {
lineoffset = linenum;
return true;
- }
}
- linenum++; // move to next line count
}
+ linenum++; // move to next line count
+ }
lineoffset = 0;
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Could not find entry point : "
- << function << " in " << filepath << "\n");
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Could not find entry point : "
+ << function << " in " << filepath << "\n");
return false;
}
bool cmParseGTMCoverage::ParseMCOVLine(std::string const& line,
std::string& routine,
- std::string& function,
- int& linenumber,
+ std::string& function, int& linenumber,
int& count)
{
// this method parses lines from the .mcov file
@@ -181,63 +164,52 @@ bool cmParseGTMCoverage::ParseMCOVLine(std::string const& line,
// ( file , entry ) = "number_executed:timing_info"
// ^COVERAGE("%RSEL","init",8,"FOR_LOOP",1)=1
// ( file , entry, line, IGNORE ) =number_executed
- std::vector<cmStdString> args;
+ std::vector<std::string> args;
std::string::size_type pos = line.find('(', 0);
// if no ( is found, then return line has no coverage
- if(pos == std::string::npos)
- {
+ if (pos == std::string::npos) {
return false;
- }
+ }
std::string arg;
bool done = false;
// separate out all of the comma separated arguments found
// in the COVERAGE(...) line
- while(line[pos] && !done)
- {
+ while (line[pos] && !done) {
// save the char we are looking at
char cur = line[pos];
// , or ) means end of argument
- if(cur == ',' || cur == ')')
- {
+ if (cur == ',' || cur == ')') {
// save the argument into the argument vector
args.push_back(arg);
// start on a new argument
arg = "";
// if we are at the end of the ), then finish while loop
- if(cur == ')')
- {
+ if (cur == ')') {
done = true;
- }
}
- else
- {
+ } else {
// all chars except ", (, and % get stored in the arg string
- if(cur != '\"' && cur != '(' && cur != '%')
- {
+ if (cur != '\"' && cur != '(' && cur != '%') {
arg.append(1, line[pos]);
- }
}
+ }
// move to next char
pos++;
- }
+ }
// now parse the right hand side of the =
pos = line.find('=');
// no = found, this is an error
- if(pos == line.npos)
- {
+ if (pos == std::string::npos) {
return false;
- }
+ }
pos++; // move past =
// if the next positing is not a ", then this is a
// COVERAGE(..)=count line and turn the rest of the string
// past the = into an integer and set it to count
- if(line[pos] != '\"')
- {
+ if (line[pos] != '\"') {
count = atoi(line.substr(pos).c_str());
- }
- else
- {
+ } else {
// this means line[pos] is a ", and we have a
// COVERAGE(...)="1:0:0:0" type of line
pos++; // move past "
@@ -245,28 +217,28 @@ bool cmParseGTMCoverage::ParseMCOVLine(std::string const& line,
std::string::size_type pos2 = line.find(':', pos);
// turn the string between the " and the first : into an integer
// and set it to count
- count = atoi(line.substr(pos, pos2-pos).c_str());
- }
+ count = atoi(line.substr(pos, pos2 - pos).c_str());
+ }
// less then two arguments is an error
- if(args.size() < 2)
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error parsing mcov line: [" << line << "]\n");
+ if (args.size() < 2) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Error parsing mcov line: ["
+ << line << "]\n");
return false;
- }
- routine = args[0]; // the routine is the first argument
+ }
+ routine = args[0]; // the routine is the first argument
function = args[1]; // the function in the routine is the second
// in the two argument only format
// ^COVERAGE("%RSEL","SRC"), the line offset is 0
- if(args.size() == 2)
- {
- linenumber = 0;
- }
- else
- {
+ if (args.size() == 2) {
+ // To avoid double counting of line 0 of each entry point,
+ // Don't count the lines that do not give an explicit line
+ // number.
+ routine = "";
+ function = "";
+ } else {
// this is the format for this line
// ^COVERAGE("%RSEL","SRC",count)
linenumber = atoi(args[2].c_str());
- }
+ }
return true;
}
diff --git a/Source/CTest/cmParseGTMCoverage.h b/Source/CTest/cmParseGTMCoverage.h
index c6d7ef919..c4949d416 100644
--- a/Source/CTest/cmParseGTMCoverage.h
+++ b/Source/CTest/cmParseGTMCoverage.h
@@ -1,20 +1,17 @@
-/*============================================================================
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmParseGTMCoverage_h
#define cmParseGTMCoverage_h
+#include "cmConfigure.h"
+
#include "cmParseMumpsCoverage.h"
+#include <string>
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
+
/** \class cmParseGTMCoverage
* \brief Parse GTM coverage information
*
@@ -24,26 +21,21 @@
class cmParseGTMCoverage : public cmParseMumpsCoverage
{
public:
- cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont,
- cmCTest* ctest);
+ cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+
protected:
// implement virtual from parent
- bool LoadCoverageData(const char* dir);
+ bool LoadCoverageData(const char* dir) CM_OVERRIDE;
// Read a single mcov file
bool ReadMCovFile(const char* f);
// find out what line in a mumps file (filepath) the given entry point
// or function is. lineoffset is set by this method.
bool FindFunctionInMumpsFile(std::string const& filepath,
- std::string const& function,
- int& lineoffset);
+ std::string const& function, int& lineoffset);
// parse a line from a .mcov file, and fill in the
// routine, function, linenumber and coverage count
- bool ParseMCOVLine(std::string const& line,
- std::string& routine,
- std::string& function,
- int& linenumber,
- int& count);
+ bool ParseMCOVLine(std::string const& line, std::string& routine,
+ std::string& function, int& linenumber, int& count);
};
-
#endif
diff --git a/Source/CTest/cmParseJacocoCoverage.cxx b/Source/CTest/cmParseJacocoCoverage.cxx
new file mode 100644
index 000000000..d15864a79
--- /dev/null
+++ b/Source/CTest/cmParseJacocoCoverage.cxx
@@ -0,0 +1,184 @@
+#include "cmParseJacocoCoverage.h"
+
+#include "cmConfigure.h"
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+#include <stdlib.h>
+#include <string.h>
+
+class cmParseJacocoCoverage::XMLParser : public cmXMLParser
+{
+public:
+ XMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont)
+ : CTest(ctest)
+ , Coverage(cont)
+ {
+ this->FilePath = "";
+ this->PackagePath = "";
+ this->PackageName = "";
+ }
+
+ ~XMLParser() CM_OVERRIDE {}
+
+protected:
+ void EndElement(const std::string& /*name*/) CM_OVERRIDE {}
+
+ void StartElement(const std::string& name, const char** atts) CM_OVERRIDE
+ {
+ if (name == "package") {
+ this->PackageName = atts[1];
+ this->PackagePath = "";
+ } else if (name == "sourcefile") {
+ std::string fileName = atts[1];
+
+ if (this->PackagePath == "") {
+ if (!this->FindPackagePath(fileName)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find file: "
+ << this->PackageName << "/" << fileName << std::endl);
+ this->Coverage.Error++;
+ return;
+ }
+ }
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading file: " << fileName << std::endl,
+ this->Coverage.Quiet);
+
+ this->FilePath = this->PackagePath + "/" + fileName;
+ cmsys::ifstream fin(this->FilePath.c_str());
+ if (!fin) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Jacoco Coverage: Error opening " << this->FilePath
+ << std::endl);
+ }
+ std::string line;
+ FileLinesType& curFileLines =
+ this->Coverage.TotalCoverage[this->FilePath];
+ if (fin) {
+ curFileLines.push_back(-1);
+ }
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ curFileLines.push_back(-1);
+ }
+ } else if (name == "line") {
+ int tagCount = 0;
+ int nr = -1;
+ int ci = -1;
+ while (true) {
+ if (strcmp(atts[tagCount], "ci") == 0) {
+ ci = atoi(atts[tagCount + 1]);
+ } else if (strcmp(atts[tagCount], "nr") == 0) {
+ nr = atoi(atts[tagCount + 1]);
+ }
+ if (ci > -1 && nr > 0) {
+ FileLinesType& curFileLines =
+ this->Coverage.TotalCoverage[this->FilePath];
+ if (!curFileLines.empty()) {
+ curFileLines[nr - 1] = ci;
+ }
+ break;
+ }
+ ++tagCount;
+ }
+ }
+ }
+
+ virtual bool FindPackagePath(std::string const& fileName)
+ {
+ // Search for the source file in the source directory.
+ if (this->PackagePathFound(fileName, this->Coverage.SourceDir)) {
+ return true;
+ }
+
+ // If not found there, check the binary directory.
+ if (this->PackagePathFound(fileName, this->Coverage.BinaryDir)) {
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool PackagePathFound(std::string const& fileName,
+ std::string const& baseDir)
+ {
+ // Search for the file in the baseDir and its subdirectories.
+ std::string packageGlob = baseDir;
+ packageGlob += "/";
+ packageGlob += fileName;
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOn();
+ gl.FindFiles(packageGlob);
+ std::vector<std::string> const& files = gl.GetFiles();
+ if (files.empty()) {
+ return false;
+ }
+
+ // Check if any of the locations found match our package.
+ for (std::vector<std::string>::const_iterator fi = files.begin();
+ fi != files.end(); ++fi) {
+ std::string dir = cmsys::SystemTools::GetParentDirectory(*fi);
+ if (cmsys::SystemTools::StringEndsWith(dir, this->PackageName.c_str())) {
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Found package directory for " << fileName << ": "
+ << dir << std::endl,
+ this->Coverage.Quiet);
+ this->PackagePath = dir;
+ return true;
+ }
+ }
+ return false;
+ }
+
+private:
+ std::string FilePath;
+ std::string PackagePath;
+ std::string PackageName;
+ typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector
+ FileLinesType;
+ cmCTest* CTest;
+ cmCTestCoverageHandlerContainer& Coverage;
+};
+
+cmParseJacocoCoverage::cmParseJacocoCoverage(
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
+{
+}
+
+bool cmParseJacocoCoverage::LoadCoverageData(
+ std::vector<std::string> const& files)
+{
+ // load all the jacoco.xml files in the source directory
+ cmsys::Directory dir;
+ size_t i;
+ std::string path;
+ size_t numf = files.size();
+ for (i = 0; i < numf; i++) {
+ path = files[i];
+
+ cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Reading XML File " << path << std::endl,
+ this->Coverage.Quiet);
+ if (cmSystemTools::GetFilenameLastExtension(path) == ".xml") {
+ if (!this->ReadJacocoXML(path.c_str())) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool cmParseJacocoCoverage::ReadJacocoXML(const char* file)
+{
+ cmParseJacocoCoverage::XMLParser parser(this->CTest, this->Coverage);
+ parser.ParseFile(file);
+ return true;
+}
diff --git a/Source/CTest/cmParseJacocoCoverage.h b/Source/CTest/cmParseJacocoCoverage.h
new file mode 100644
index 000000000..f2aec6db9
--- /dev/null
+++ b/Source/CTest/cmParseJacocoCoverage.h
@@ -0,0 +1,53 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmParseJacocoCoverage_h
+#define cmParseJacocoCoverage_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <map>
+#include <string>
+#include <vector>
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
+
+/** \class cmParseJacocoCoverage
+ * \brief Parse JaCoCO coverage information
+ *
+ * This class is used to parse coverage information for
+ * java using the JaCoCo tool:
+ *
+ * http://www.eclemma.org/jacoco/trunk/index.html
+ */
+class cmParseJacocoCoverage
+{
+public:
+ cmParseJacocoCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
+ bool LoadCoverageData(std::vector<std::string> const& files);
+
+ std::string PackageName;
+ std::string FileName;
+ std::string ModuleName;
+ std::string CurFileName;
+
+private:
+ // implement virtual from parent
+ // remove files with no coverage
+ void RemoveUnCoveredFiles();
+ // Read a single mcov file
+ bool ReadJacocoXML(const char* f);
+ // split a string based on ,
+ bool SplitString(std::vector<std::string>& args, std::string const& line);
+ bool FindJavaFile(std::string const& routine, std::string& filepath);
+ void InitializeJavaFile(std::string& file);
+ bool LoadSource(std::string d);
+
+ class XMLParser;
+
+ std::map<std::string, std::string> RoutineToDirectory;
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+};
+
+#endif
diff --git a/Source/CTest/cmParseMumpsCoverage.cxx b/Source/CTest/cmParseMumpsCoverage.cxx
index 37e8bd082..eb29f55c0 100644
--- a/Source/CTest/cmParseMumpsCoverage.cxx
+++ b/Source/CTest/cmParseMumpsCoverage.cxx
@@ -1,16 +1,21 @@
-#include "cmStandardIncludes.h"
-#include <stdio.h>
-#include <stdlib.h>
+#include "cmParseMumpsCoverage.h"
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
#include "cmSystemTools.h"
-#include "cmParseGTMCoverage.h"
-#include <cmsys/Directory.hxx>
-#include <cmsys/Glob.hxx>
+#include "cmConfigure.h"
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
cmParseMumpsCoverage::cmParseMumpsCoverage(
- cmCTestCoverageHandlerContainer& cont,
- cmCTest* ctest)
- :Coverage(cont), CTest(ctest)
+ cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
{
}
@@ -23,96 +28,82 @@ 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);
- if(!in)
- {
+ cmsys::ifstream in(file);
+ if (!in) {
return false;
- }
+ }
std::string line;
- while(cmSystemTools::GetLineFromStream(in, line))
- {
+ while (cmSystemTools::GetLineFromStream(in, line)) {
std::string::size_type pos = line.find(':', 0);
std::string packages;
- if(pos != std::string::npos)
- {
+ if (pos != std::string::npos) {
std::string type = line.substr(0, pos);
- std::string path = line.substr(pos+1);
- if(type == "packages")
- {
+ std::string path = line.substr(pos + 1);
+ if (type == "packages") {
this->LoadPackages(path.c_str());
- }
- else if(type == "coverage_dir")
- {
+ } else if (type == "coverage_dir") {
this->LoadCoverageData(path.c_str());
- }
- else
- {
+ } else {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Parse Error in Mumps coverage file :\n"
- << file <<
- "\ntype: [" << type << "]\npath:[" << path << "]\n"
- "input line: [" << line << "]\n");
- }
+ << file << "\ntype: [" << type << "]\npath:[" << path
+ << "]\n"
+ "input line: ["
+ << line << "]\n");
}
}
+ }
return true;
}
void cmParseMumpsCoverage::InitializeMumpsFile(std::string& file)
{
// initialize the coverage information for a given mumps file
- std::ifstream in(file.c_str());
- if(!in)
- {
+ cmsys::ifstream in(file.c_str());
+ if (!in) {
return;
- }
+ }
std::string line;
- cmCTestCoverageHandlerContainer::SingleFileCoverageVector&
- coverageVector = this->Coverage.TotalCoverage[file];
- if(!cmSystemTools::GetLineFromStream(in, line))
- {
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector =
+ this->Coverage.TotalCoverage[file];
+ if (!cmSystemTools::GetLineFromStream(in, line)) {
return;
- }
+ }
// first line of a .m file can never be run
coverageVector.push_back(-1);
- while( cmSystemTools::GetLineFromStream(in, line) )
- {
+ while (cmSystemTools::GetLineFromStream(in, line)) {
// putting in a 0 for a line means it is executable code
// putting in a -1 for a line means it is not executable code
int val = -1; // assume line is not executable
bool found = false;
std::string::size_type i = 0;
// (1) Search for the first whitespace or semicolon character on a line.
- //This will skip over labels if the line starts with one, or will simply
- //be the first character on the line for non-label lines.
- for(; i < line.size(); ++i)
- {
- if(line[i] == ' ' || line[i] == '\t' || line[i] == ';')
- {
+ // This will skip over labels if the line starts with one, or will simply
+ // be the first character on the line for non-label lines.
+ for (; i < line.size(); ++i) {
+ if (line[i] == ' ' || line[i] == '\t' || line[i] == ';') {
found = true;
break;
- }
}
- if(found)
- {
- // (2) If the first character found above is whitespace then continue the
- // search for the first following non-whitespace character.
- if(line[i] == ' ' || line[i] == '\t')
- {
- while(i < line.size() && (line[i] == ' ' || line[i] == '\t'))
- {
+ }
+ if (found) {
+ // (2) If the first character found above is whitespace or a period
+ // then continue the search for the first following non-whitespace
+ // character.
+ if (line[i] == ' ' || line[i] == '\t') {
+ while (i < line.size() &&
+ (line[i] == ' ' || line[i] == '\t' || line[i] == '.')) {
i++;
- }
}
+ }
// (3) If the character found is not a semicolon then the line counts for
// coverage.
- if(i < line.size() && line[i] != ';')
- {
+ if (i < line.size() && line[i] != ';') {
val = 0;
- }
}
- coverageVector.push_back(val);
}
+ coverageVector.push_back(val);
+ }
}
bool cmParseMumpsCoverage::LoadPackages(const char* d)
@@ -121,45 +112,37 @@ bool cmParseMumpsCoverage::LoadPackages(const char* d)
glob.RecurseOn();
std::string pat = d;
pat += "/*.m";
- glob.FindFiles(pat.c_str());
+ glob.FindFiles(pat);
std::vector<std::string>& files = glob.GetFiles();
std::vector<std::string>::iterator fileIt;
- for ( fileIt = files.begin(); fileIt != files.end();
- ++ fileIt )
- {
+ for (fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
std::string name = cmSystemTools::GetFilenameName(*fileIt);
- this->RoutineToDirectory[name.substr(0, name.size()-2)] = *fileIt;
+ this->RoutineToDirectory[name.substr(0, name.size() - 2)] = *fileIt;
// initialze each file, this is left out until CDash is fixed
// to handle large numbers of files
this->InitializeMumpsFile(*fileIt);
- }
+ }
return true;
}
bool cmParseMumpsCoverage::FindMumpsFile(std::string const& routine,
std::string& filepath)
{
- std::map<cmStdString, cmStdString>::iterator i =
+ std::map<std::string, std::string>::iterator i =
this->RoutineToDirectory.find(routine);
- if(i != this->RoutineToDirectory.end())
- {
+ if (i != this->RoutineToDirectory.end()) {
filepath = i->second;
return true;
+ }
+ // try some alternate names
+ const char* tryname[] = { "GUX", "GTM", "ONT", CM_NULLPTR };
+ for (int k = 0; tryname[k] != CM_NULLPTR; k++) {
+ std::string routine2 = routine + tryname[k];
+ i = this->RoutineToDirectory.find(routine2);
+ if (i != this->RoutineToDirectory.end()) {
+ filepath = i->second;
+ return true;
}
- else
- {
- // try some alternate names
- const char* tryname[] = {"GUX", "GTM", "ONT", 0};
- for(int k=0; tryname[k] != 0; k++)
- {
- std::string routine2 = routine + tryname[k];
- i = this->RoutineToDirectory.find(routine2);
- if(i != this->RoutineToDirectory.end())
- {
- filepath = i->second;
- return true;
- }
- }
- }
+ }
return false;
}
diff --git a/Source/CTest/cmParseMumpsCoverage.h b/Source/CTest/cmParseMumpsCoverage.h
index c1effa79b..2c544954b 100644
--- a/Source/CTest/cmParseMumpsCoverage.h
+++ b/Source/CTest/cmParseMumpsCoverage.h
@@ -1,20 +1,15 @@
-/*============================================================================
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmParseMumpsCoverage_h
#define cmParseMumpsCoverage_h
-#include "cmStandardIncludes.h"
-#include "cmCTestCoverageHandler.h"
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <map>
+#include <string>
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
/** \class cmParseMumpsCoverage
* \brief Parse Mumps coverage information
@@ -25,12 +20,12 @@
class cmParseMumpsCoverage
{
public:
- cmParseMumpsCoverage(cmCTestCoverageHandlerContainer& cont,
- cmCTest* ctest);
+ cmParseMumpsCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
virtual ~cmParseMumpsCoverage();
// This is the toplevel coverage file locating the coverage files
// and the mumps source code package tree.
bool ReadCoverageFile(const char* file);
+
protected:
// sub classes will use this to
// load all coverage files found in the given directory
@@ -41,10 +36,10 @@ protected:
// initialize the coverage information for a single mumps file
void InitializeMumpsFile(std::string& file);
// Find mumps file for routine
- bool FindMumpsFile(std::string const& routine,
- std::string& filepath);
+ bool FindMumpsFile(std::string const& routine, std::string& filepath);
+
protected:
- std::map<cmStdString, cmStdString> RoutineToDirectory;
+ std::map<std::string, std::string> RoutineToDirectory;
cmCTestCoverageHandlerContainer& Coverage;
cmCTest* CTest;
};
diff --git a/Source/CTest/cmParsePHPCoverage.cxx b/Source/CTest/cmParsePHPCoverage.cxx
index 593b2d1a8..761ebec65 100644
--- a/Source/CTest/cmParsePHPCoverage.cxx
+++ b/Source/CTest/cmParsePHPCoverage.cxx
@@ -1,7 +1,13 @@
-#include "cmStandardIncludes.h"
-#include "cmSystemTools.h"
#include "cmParsePHPCoverage.h"
-#include <cmsys/Directory.hxx>
+
+#include "cmCTest.h"
+#include "cmCTestCoverageHandler.h"
+#include "cmSystemTools.h"
+
+#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+#include <stdlib.h>
+#include <string.h>
/*
To setup coverage for php.
@@ -15,55 +21,45 @@
*/
cmParsePHPCoverage::cmParsePHPCoverage(cmCTestCoverageHandlerContainer& cont,
- cmCTest* ctest)
- :Coverage(cont), CTest(ctest)
+ cmCTest* ctest)
+ : Coverage(cont)
+ , CTest(ctest)
{
}
-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)
- {
- }
- if(c != until)
- {
- return false;
- }
- return true;
+ while (in.get(c) && c != until) {
+ }
+ return c == until;
}
-bool cmParsePHPCoverage::ReadCoverageArray(std::ifstream& in,
- cmStdString const& fileName)
+bool cmParsePHPCoverage::ReadCoverageArray(std::istream& in,
+ std::string const& fileName)
{
- cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector
- = this->Coverage.TotalCoverage[fileName];
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector =
+ this->Coverage.TotalCoverage[fileName];
char c;
char buf[4];
in.read(buf, 3);
buf[3] = 0;
- if(strcmp(buf, ";a:") != 0)
- {
+ if (strcmp(buf, ";a:") != 0) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "failed to read start of coverage array, found : "
- << buf << "\n");
+ "failed to read start of coverage array, found : " << buf
+ << "\n");
return false;
- }
+ }
int size = 0;
- if(!this->ReadInt(in, size))
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "failed to read size ");
+ if (!this->ReadInt(in, size)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "failed to read size ");
return false;
- }
- if(!in.get(c) && c == '{')
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "failed to read open {\n");
+ }
+ if (!in.get(c) && c == '{') {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "failed to read open {\n");
return false;
- }
- for(int i =0; i < size; i++)
- {
+ }
+ for (int i = 0; i < size; i++) {
this->ReadUntil(in, ':');
int line = 0;
this->ReadInt(in, line);
@@ -71,19 +67,17 @@ bool cmParsePHPCoverage::ReadCoverageArray(std::ifstream& in,
// it seems to be 1 based but often times
// seems to have a 0'th line.
line--;
- if(line < 0)
- {
+ if (line < 0) {
line = 0;
- }
+ }
this->ReadUntil(in, ':');
int value = 0;
this->ReadInt(in, value);
// make sure the vector is the right size and is
// initialized with -1 for each line
- while(coverageVector.size() <= static_cast<size_t>(line) )
- {
+ while (coverageVector.size() <= static_cast<size_t>(line)) {
coverageVector.push_back(-1);
- }
+ }
// if value is less than 0, set it to zero
// TODO figure out the difference between
// -1 and -2 in xdebug coverage?? For now
@@ -91,163 +85,137 @@ bool cmParsePHPCoverage::ReadCoverageArray(std::ifstream& in,
// CDash expects -1 for non executable code (like comments)
// and 0 for uncovered code, and a positive value
// for number of times a line was executed
- if(value < 0)
- {
+ if (value < 0) {
value = 0;
- }
+ }
// if unset then set it to value
- if(coverageVector[line] == -1)
- {
+ if (coverageVector[line] == -1) {
coverageVector[line] = value;
- }
+ }
// otherwise increment by value
- else
- {
+ else {
coverageVector[line] += value;
- }
}
+ }
return true;
}
-bool cmParsePHPCoverage::ReadInt(std::ifstream& in, int& v)
+bool cmParsePHPCoverage::ReadInt(std::istream& in, int& v)
{
std::string s;
char c = 0;
- while(in.get(c) && c != ':' && c != ';')
- {
+ while (in.get(c) && c != ':' && c != ';') {
s += c;
- }
+ }
v = atoi(s.c_str());
return true;
}
-bool cmParsePHPCoverage::ReadArraySize(std::ifstream& in, int& size)
+bool cmParsePHPCoverage::ReadArraySize(std::istream& in, int& size)
{
char c = 0;
in.get(c);
- if(c != 'a')
- {
+ if (c != 'a') {
return false;
- }
- if(in.get(c) && c == ':')
- {
- if(this->ReadInt(in, size))
- {
+ }
+ if (in.get(c) && c == ':') {
+ if (this->ReadInt(in, size)) {
return true;
- }
}
+ }
return false;
}
-bool cmParsePHPCoverage::ReadFileInformation(std::ifstream& in)
+bool cmParsePHPCoverage::ReadFileInformation(std::istream& in)
{
char buf[4];
in.read(buf, 2);
buf[2] = 0;
- if(strcmp(buf, "s:") != 0)
- {
+ if (strcmp(buf, "s:") != 0) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"failed to read start of file info found: [" << buf << "]\n");
return false;
- }
+ }
char c;
int size = 0;
- if(this->ReadInt(in, size))
- {
+ if (this->ReadInt(in, size)) {
size++; // add one for null termination
- char* s = new char[size+1];
+ char* s = new char[size + 1];
// read open quote
- if(in.get(c) && c != '"')
- {
+ if (in.get(c) && c != '"') {
delete[] s;
return false;
- }
+ }
// read the string data
- in.read(s, size-1);
- s[size-1] = 0;
- cmStdString fileName = s;
- delete [] s;
+ in.read(s, size - 1);
+ s[size - 1] = 0;
+ std::string fileName = s;
+ delete[] s;
// read close quote
- if(in.get(c) && c != '"')
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "failed to read close quote\n"
- << "read [" << c << "]\n");
+ if (in.get(c) && c != '"') {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "failed to read close quote\n"
+ << "read [" << c << "]\n");
return false;
- }
- if(!this->ReadCoverageArray(in, fileName) )
- {
+ }
+ if (!this->ReadCoverageArray(in, fileName)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "failed to read coverage array for file: "
- << fileName << "\n");
+ "failed to read coverage array for file: " << fileName
+ << "\n");
return false;
- }
- return true;
}
+ return true;
+ }
return false;
}
-
bool cmParsePHPCoverage::ReadPHPData(const char* file)
{
- std::ifstream in(file);
- if(!in)
- {
+ cmsys::ifstream in(file);
+ if (!in) {
return false;
- }
+ }
int size = 0;
this->ReadArraySize(in, size);
char c = 0;
in.get(c);
- if(c != '{')
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "failed to read open array\n");
+ if (c != '{') {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "failed to read open array\n");
return false;
- }
- for(int i =0; i < size; i++)
- {
- if(!this->ReadFileInformation(in))
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Failed to read file #" << i << "\n");
+ }
+ for (int i = 0; i < size; i++) {
+ if (!this->ReadFileInformation(in)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Failed to read file #" << i
+ << "\n");
return false;
- }
+ }
in.get(c);
- if(c != '}')
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "failed to read close array\n");
+ if (c != '}') {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "failed to read close array\n");
return false;
- }
}
+ }
return true;
}
bool cmParsePHPCoverage::ReadPHPCoverageDirectory(const char* d)
{
cmsys::Directory dir;
- if(!dir.Load(d))
- {
+ if (!dir.Load(d)) {
return false;
- }
+ }
size_t numf;
unsigned int i;
numf = dir.GetNumberOfFiles();
- for (i = 0; i < numf; i++)
- {
+ for (i = 0; i < numf; i++) {
std::string file = dir.GetFile(i);
- if(file != "." && file != ".."
- && !cmSystemTools::FileIsDirectory(file.c_str()))
- {
+ if (file != "." && file != ".." && !cmSystemTools::FileIsDirectory(file)) {
std::string path = d;
path += "/";
path += file;
- if(!this->ReadPHPData(path.c_str()))
- {
+ if (!this->ReadPHPData(path.c_str())) {
return false;
- }
}
}
+ }
return true;
}
diff --git a/Source/CTest/cmParsePHPCoverage.h b/Source/CTest/cmParsePHPCoverage.h
index d50a83c58..ff0e6366d 100644
--- a/Source/CTest/cmParsePHPCoverage.h
+++ b/Source/CTest/cmParsePHPCoverage.h
@@ -1,20 +1,15 @@
-/*============================================================================
- 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.
-============================================================================*/
-
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmParsePHPCoverage_h
#define cmParsePHPCoverage_h
-#include "cmStandardIncludes.h"
-#include "cmCTestCoverageHandler.h"
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <string>
+
+class cmCTest;
+class cmCTestCoverageHandlerContainer;
/** \class cmParsePHPCoverage
* \brief Parse xdebug PHP coverage information
@@ -26,20 +21,19 @@
class cmParsePHPCoverage
{
public:
- cmParsePHPCoverage(cmCTestCoverageHandlerContainer& cont,
- cmCTest* ctest);
+ cmParsePHPCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest);
bool ReadPHPCoverageDirectory(const char* dir);
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, std::string const&);
+ bool ReadUntil(std::istream& in, char until);
cmCTestCoverageHandlerContainer& Coverage;
cmCTest* CTest;
};
-
#endif
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index 167b992c9..f4ec6da29 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -1,21 +1,15 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmProcess.h"
- 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 <cmProcess.h>
-#include <cmSystemTools.h>
+#include "cmConfigure.h"
+#include "cmProcessOutput.h"
+#include "cmSystemTools.h"
+#include <iostream>
cmProcess::cmProcess()
{
- this->Process = 0;
+ this->Process = CM_NULLPTR;
this->Timeout = 0;
this->TotalTime = 0;
this->ExitValue = 0;
@@ -39,49 +33,43 @@ void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
bool cmProcess::StartProcess()
{
- if(this->Command.size() == 0)
- {
+ if (this->Command.empty()) {
return false;
- }
+ }
this->StartTime = cmSystemTools::GetTime();
this->ProcessArgs.clear();
// put the command as arg0
this->ProcessArgs.push_back(this->Command.c_str());
// now put the command arguments in
- for(std::vector<std::string>::iterator i = this->Arguments.begin();
- i != this->Arguments.end(); ++i)
- {
+ for (std::vector<std::string>::iterator i = this->Arguments.begin();
+ i != this->Arguments.end(); ++i) {
this->ProcessArgs.push_back(i->c_str());
- }
- this->ProcessArgs.push_back(0); // null terminate the list
+ }
+ this->ProcessArgs.push_back(CM_NULLPTR); // null terminate the list
this->Process = cmsysProcess_New();
cmsysProcess_SetCommand(this->Process, &*this->ProcessArgs.begin());
- if(this->WorkingDirectory.size())
- {
+ if (!this->WorkingDirectory.empty()) {
cmsysProcess_SetWorkingDirectory(this->Process,
this->WorkingDirectory.c_str());
- }
+ }
cmsysProcess_SetTimeout(this->Process, this->Timeout);
+ cmsysProcess_SetOption(this->Process, cmsysProcess_Option_MergeOutput, 1);
cmsysProcess_Execute(this->Process);
- return (cmsysProcess_GetState(this->Process)
- == cmsysProcess_State_Executing);
+ return (cmsysProcess_GetState(this->Process) ==
+ cmsysProcess_State_Executing);
}
-//----------------------------------------------------------------------------
bool cmProcess::Buffer::GetLine(std::string& line)
{
// Scan for the next newline.
- for(size_type sz = this->size(); this->Last != sz; ++this->Last)
- {
- if((*this)[this->Last] == '\n' || (*this)[this->Last] == '\0')
- {
+ for (size_type sz = this->size(); this->Last != sz; ++this->Last) {
+ if ((*this)[this->Last] == '\n' || (*this)[this->Last] == '\0') {
// Extract the range first..last as a line.
const char* text = &*this->begin() + this->First;
size_type length = this->Last - this->First;
- while(length && text[length-1] == '\r')
- {
- length --;
- }
+ while (length && text[length - 1] == '\r') {
+ length--;
+ }
line.assign(text, length);
// Start a new range for the next line.
@@ -90,87 +78,70 @@ bool cmProcess::Buffer::GetLine(std::string& line)
// Return the line extracted.
return true;
- }
}
+ }
// Available data have been exhausted without a newline.
- if(this->First != 0)
- {
+ if (this->First != 0) {
// Move the partial line to the beginning of the buffer.
this->erase(this->begin(), this->begin() + this->First);
this->First = 0;
this->Last = this->size();
- }
+ }
return false;
}
-//----------------------------------------------------------------------------
bool cmProcess::Buffer::GetLast(std::string& line)
{
// Return the partial last line, if any.
- if(!this->empty())
- {
+ if (!this->empty()) {
line.assign(&*this->begin(), this->size());
this->First = this->Last = 0;
this->clear();
return true;
- }
+ }
return false;
}
-//----------------------------------------------------------------------------
int cmProcess::GetNextOutputLine(std::string& line, double timeout)
{
- for(;;)
- {
+ cmProcessOutput processOutput(cmProcessOutput::UTF8);
+ std::string strdata;
+ for (;;) {
// Look for lines already buffered.
- if(this->StdOut.GetLine(line))
- {
+ if (this->Output.GetLine(line)) {
return cmsysProcess_Pipe_STDOUT;
- }
- else if(this->StdErr.GetLine(line))
- {
- return cmsysProcess_Pipe_STDERR;
- }
+ }
// Check for more data from the process.
char* data;
int length;
int p = cmsysProcess_WaitForData(this->Process, &data, &length, &timeout);
- if(p == cmsysProcess_Pipe_Timeout)
- {
+ if (p == cmsysProcess_Pipe_Timeout) {
return cmsysProcess_Pipe_Timeout;
- }
- else if(p == cmsysProcess_Pipe_STDOUT)
- {
- this->StdOut.insert(this->StdOut.end(), data, data+length);
- }
- else if(p == cmsysProcess_Pipe_STDERR)
- {
- this->StdErr.insert(this->StdErr.end(), data, data+length);
- }
- else // p == cmsysProcess_Pipe_None
- {
+ }
+ if (p == cmsysProcess_Pipe_STDOUT) {
+ processOutput.DecodeText(data, length, strdata);
+ this->Output.insert(this->Output.end(), strdata.begin(), strdata.end());
+ } else { // p == cmsysProcess_Pipe_None
// The process will provide no more data.
break;
- }
}
+ }
+ processOutput.DecodeText(std::string(), strdata);
+ if (!strdata.empty()) {
+ this->Output.insert(this->Output.end(), strdata.begin(), strdata.end());
+ }
// Look for partial last lines.
- if(this->StdOut.GetLast(line))
- {
+ if (this->Output.GetLast(line)) {
return cmsysProcess_Pipe_STDOUT;
- }
- else if(this->StdErr.GetLast(line))
- {
- return cmsysProcess_Pipe_STDERR;
- }
+ }
// No more data. Wait for process exit.
- if(!cmsysProcess_WaitForExit(this->Process, &timeout))
- {
+ if (!cmsysProcess_WaitForExit(this->Process, &timeout)) {
return cmsysProcess_Pipe_Timeout;
- }
+ }
// Record exit information.
this->ExitValue = cmsysProcess_GetExitValue(this->Process);
@@ -179,10 +150,9 @@ int cmProcess::GetNextOutputLine(std::string& line, double timeout)
// negative. If someone changed the system clock while the process was
// running this may be even more. Make sure not to report a negative
// duration here.
- if (this->TotalTime <= 0.0)
- {
+ if (this->TotalTime <= 0.0) {
this->TotalTime = 0.0;
- }
+ }
// std::cerr << "Time to run: " << this->TotalTime << "\n";
return cmsysProcess_Pipe_None;
}
@@ -190,89 +160,81 @@ int cmProcess::GetNextOutputLine(std::string& line, double timeout)
// return the process status
int cmProcess::GetProcessStatus()
{
- if(!this->Process)
- {
+ if (!this->Process) {
return cmsysProcess_State_Exited;
- }
+ }
return cmsysProcess_GetState(this->Process);
}
int cmProcess::ReportStatus()
{
int result = 1;
- switch(cmsysProcess_GetState(this->Process))
- {
- case cmsysProcess_State_Starting:
- {
- std::cerr << "cmProcess: Never started "
- << this->Command << " process.\n";
- } break;
- case cmsysProcess_State_Error:
- {
+ switch (cmsysProcess_GetState(this->Process)) {
+ case cmsysProcess_State_Starting: {
+ std::cerr << "cmProcess: Never started " << this->Command
+ << " process.\n";
+ } break;
+ case cmsysProcess_State_Error: {
std::cerr << "cmProcess: Error executing " << this->Command
- << " process: "
- << cmsysProcess_GetErrorString(this->Process)
+ << " process: " << cmsysProcess_GetErrorString(this->Process)
<< "\n";
- } break;
- case cmsysProcess_State_Exception:
- {
+ } break;
+ case cmsysProcess_State_Exception: {
std::cerr << "cmProcess: " << this->Command
- << " process exited with an exception: ";
- switch(cmsysProcess_GetExitException(this->Process))
- {
- case cmsysProcess_Exception_None:
- {
+ << " process exited with an exception: ";
+ switch (cmsysProcess_GetExitException(this->Process)) {
+ case cmsysProcess_Exception_None: {
std::cerr << "None";
- } break;
- case cmsysProcess_Exception_Fault:
- {
+ } break;
+ case cmsysProcess_Exception_Fault: {
std::cerr << "Segmentation fault";
- } break;
- case cmsysProcess_Exception_Illegal:
- {
+ } break;
+ case cmsysProcess_Exception_Illegal: {
std::cerr << "Illegal instruction";
- } break;
- case cmsysProcess_Exception_Interrupt:
- {
+ } break;
+ case cmsysProcess_Exception_Interrupt: {
std::cerr << "Interrupted by user";
- } break;
- case cmsysProcess_Exception_Numerical:
- {
+ } break;
+ case cmsysProcess_Exception_Numerical: {
std::cerr << "Numerical exception";
- } break;
- case cmsysProcess_Exception_Other:
- {
+ } break;
+ case cmsysProcess_Exception_Other: {
std::cerr << "Unknown";
- } break;
- }
+ } break;
+ }
std::cerr << "\n";
- } break;
- case cmsysProcess_State_Executing:
- {
- std::cerr << "cmProcess: Never terminated " <<
- this->Command << " process.\n";
- } break;
- case cmsysProcess_State_Exited:
- {
+ } break;
+ case cmsysProcess_State_Executing: {
+ std::cerr << "cmProcess: Never terminated " << this->Command
+ << " process.\n";
+ } break;
+ case cmsysProcess_State_Exited: {
result = cmsysProcess_GetExitValue(this->Process);
std::cerr << "cmProcess: " << this->Command
- << " process exited with code "
- << result << "\n";
- } break;
- case cmsysProcess_State_Expired:
- {
+ << " process exited with code " << result << "\n";
+ } break;
+ case cmsysProcess_State_Expired: {
std::cerr << "cmProcess: killed " << this->Command
<< " process due to timeout.\n";
- } break;
- case cmsysProcess_State_Killed:
- {
+ } break;
+ case cmsysProcess_State_Killed: {
std::cerr << "cmProcess: killed " << this->Command << " process.\n";
- } break;
- }
+ } break;
+ }
return result;
+}
+void cmProcess::ChangeTimeout(double t)
+{
+ this->Timeout = t;
+ cmsysProcess_SetTimeout(this->Process, this->Timeout);
}
+void cmProcess::ResetStartTime()
+{
+ cmsysProcess_ResetStartTime(this->Process);
+ this->StartTime = cmSystemTools::GetTime();
+}
int cmProcess::GetExitException()
{
diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h
index 1479df05f..86e905aca 100644
--- a/Source/CTest/cmProcess.h
+++ b/Source/CTest/cmProcess.h
@@ -1,21 +1,13 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- 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.
-============================================================================*/
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmProcess_h
#define cmProcess_h
+#include "cmConfigure.h" // IWYU pragma: keep
-#include "cmStandardIncludes.h"
-#include <cmsys/Process.h>
-
+#include "cmsys/Process.h"
+#include <string>
+#include <vector>
/** \class cmProcess
* \brief run a process with c++
@@ -27,11 +19,13 @@ class cmProcess
public:
cmProcess();
~cmProcess();
- const char* GetCommand() { return this->Command.c_str();}
+ const char* GetCommand() { return this->Command.c_str(); }
void SetCommand(const char* command);
void SetCommandArguments(std::vector<std::string> const& arg);
- void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir;}
- void SetTimeout(double t) { this->Timeout = t;}
+ void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; }
+ void SetTimeout(double t) { this->Timeout = t; }
+ void ChangeTimeout(double t);
+ void ResetStartTime();
// Return true if the process starts
bool StartProcess();
@@ -40,41 +34,44 @@ public:
// Report the status of the program
int ReportStatus();
int GetId() { return this->Id; }
- void SetId(int id) { this->Id = id;}
- int GetExitValue() { return this->ExitValue;}
- double GetTotalTime() { return this->TotalTime;}
+ void SetId(int id) { this->Id = id; }
+ int GetExitValue() { return this->ExitValue; }
+ double GetTotalTime() { return this->TotalTime; }
int GetExitException();
/**
* Read one line of output but block for no more than timeout.
* Returns:
* cmsysProcess_Pipe_None = Process terminated and all output read
- * cmsysProcess_Pipe_STDOUT = Line came from stdout
- * cmsysProcess_Pipe_STDOUT = Line came from stderr
+ * cmsysProcess_Pipe_STDOUT = Line came from stdout or stderr
* cmsysProcess_Pipe_Timeout = Timeout expired while waiting
*/
int GetNextOutputLine(std::string& line, double timeout);
+
private:
double Timeout;
double StartTime;
double TotalTime;
cmsysProcess* Process;
- class Buffer: public std::vector<char>
+ class Buffer : public std::vector<char>
{
// Half-open index range of partial line already scanned.
size_type First;
size_type Last;
+
public:
- Buffer(): First(0), Last(0) {}
+ Buffer()
+ : First(0)
+ , Last(0)
+ {
+ }
bool GetLine(std::string& line);
bool GetLast(std::string& line);
};
- Buffer StdErr;
- Buffer StdOut;
+ Buffer Output;
std::string Command;
std::string WorkingDirectory;
std::vector<std::string> Arguments;
std::vector<const char*> ProcessArgs;
- std::string Output;
int Id;
int ExitValue;
};