summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2024-01-22 19:55:47 (GMT)
committerBrad King <brad.king@kitware.com>2024-01-24 22:10:00 (GMT)
commitbcbb212df704d36736731aa567b291fd97401804 (patch)
tree6fef8b57dd7aa10c9f15447b18dc74951de68dad /Source
parentadb3e13d323aeb19c3824112cfa712cc122db3b4 (diff)
downloadCMake-bcbb212df704d36736731aa567b291fd97401804.zip
CMake-bcbb212df704d36736731aa567b291fd97401804.tar.gz
CMake-bcbb212df704d36736731aa567b291fd97401804.tar.bz2
Revert use of libuv for process execution for 3.28
Wide use of CMake 3.28.{1,0[-rcN]} has uncovered some hangs and crashes in libuv SIGCHLD handling on some platforms, particularly in virtualization environments on macOS hosts. Although the bug does not seem to be in CMake, we can restore stability in the CMake 3.28 release series for users of such platforms by reverting our new uses of libuv for process execution. Revert implementation changes merged by commit 4771544386 (Merge topic 'replace-cmsysprocess-with-cmuvprocesschain', 2023-09-06, v3.28.0-rc1~138), but keep test suite updates. Issue: #25414, #25500, #25562, #25589
Diffstat (limited to 'Source')
-rw-r--r--Source/CPack/cmCPackSTGZGenerator.cxx2
-rw-r--r--Source/CTest/cmCTestBZR.cxx31
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.cxx15
-rw-r--r--Source/CTest/cmCTestBuildHandler.cxx291
-rw-r--r--Source/CTest/cmCTestBuildHandler.h6
-rw-r--r--Source/CTest/cmCTestCVS.cxx18
-rw-r--r--Source/CTest/cmCTestConfigureHandler.cxx2
-rw-r--r--Source/CTest/cmCTestCoverageHandler.cxx109
-rw-r--r--Source/CTest/cmCTestGIT.cxx130
-rw-r--r--Source/CTest/cmCTestHG.cxx35
-rw-r--r--Source/CTest/cmCTestLaunch.cxx121
-rw-r--r--Source/CTest/cmCTestLaunch.h5
-rw-r--r--Source/CTest/cmCTestLaunchReporter.cxx50
-rw-r--r--Source/CTest/cmCTestLaunchReporter.h4
-rw-r--r--Source/CTest/cmCTestP4.cxx66
-rw-r--r--Source/CTest/cmCTestP4.h2
-rw-r--r--Source/CTest/cmCTestSVN.cxx36
-rw-r--r--Source/CTest/cmCTestSVN.h2
-rw-r--r--Source/CTest/cmCTestScriptHandler.cxx84
-rw-r--r--Source/CTest/cmCTestVC.cxx45
-rw-r--r--Source/CTest/cmCTestVC.h9
-rw-r--r--Source/LexerParser/cmCTestResourceGroupsLexer.cxx4
-rw-r--r--Source/LexerParser/cmCTestResourceGroupsLexer.in.l4
-rw-r--r--Source/cmCTest.cxx429
-rw-r--r--Source/cmCTest.h16
-rw-r--r--Source/cmExecuteProcessCommand.cxx399
-rw-r--r--Source/cmProcessTools.cxx82
-rw-r--r--Source/cmProcessTools.h8
-rw-r--r--Source/cmSystemTools.cxx284
-rw-r--r--Source/cmSystemTools.h21
-rw-r--r--Source/cmcmd.cxx97
31 files changed, 1186 insertions, 1221 deletions
diff --git a/Source/CPack/cmCPackSTGZGenerator.cxx b/Source/CPack/cmCPackSTGZGenerator.cxx
index 1248d17..6ad3755 100644
--- a/Source/CPack/cmCPackSTGZGenerator.cxx
+++ b/Source/CPack/cmCPackSTGZGenerator.cxx
@@ -7,8 +7,6 @@
#include <string>
#include <vector>
-#include <fcntl.h>
-
#include "cmsys/FStream.hxx"
#include "cm_sys_stat.h"
diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx
index 36df344..246e811 100644
--- a/Source/CTest/cmCTestBZR.cxx
+++ b/Source/CTest/cmCTestBZR.cxx
@@ -135,14 +135,14 @@ private:
std::string cmCTestBZR::LoadInfo()
{
// Run "bzr info" to get the repository info from the work tree.
- std::string bzr = this->CommandLineTool;
- std::vector<std::string> bzr_info = { bzr, "info" };
+ const char* bzr = this->CommandLineTool.c_str();
+ const char* bzr_info[] = { bzr, "info", 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.
- std::vector<std::string> bzr_revno = { bzr, "revno" };
+ const char* bzr_revno[] = { bzr, "revno", nullptr };
std::string rev;
RevnoParser rout(this, "revno-out> ", rev);
OutputLogger rerr(this->Log, "revno-err> ");
@@ -372,18 +372,22 @@ bool cmCTestBZR::UpdateImpl()
// TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
// Use "bzr pull" to update the working tree.
- std::vector<std::string> bzr_update;
- bzr_update.push_back(this->CommandLineTool);
+ std::vector<char const*> bzr_update;
+ bzr_update.push_back(this->CommandLineTool.c_str());
bzr_update.push_back("pull");
- cm::append(bzr_update, args);
+ for (std::string const& arg : args) {
+ bzr_update.push_back(arg.c_str());
+ }
+
+ bzr_update.push_back(this->URL.c_str());
- bzr_update.push_back(this->URL);
+ bzr_update.push_back(nullptr);
// For some reason bzr uses stderr to display the update status.
OutputLogger out(this->Log, "pull-out> ");
UpdateParser err(this, "pull-err> ");
- return this->RunUpdateCommand(bzr_update, &out, &err);
+ return this->RunUpdateCommand(bzr_update.data(), &out, &err);
}
bool cmCTestBZR::LoadRevisions()
@@ -404,9 +408,10 @@ bool cmCTestBZR::LoadRevisions()
}
// Run "bzr log" to get all global revisions of interest.
- std::string bzr = this->CommandLineTool;
- std::vector<std::string> bzr_log = { bzr, "log", "-v", "-r",
- revs, "--xml", this->URL };
+ const char* bzr = this->CommandLineTool.c_str();
+ const char* bzr_log[] = {
+ bzr, "log", "-v", "-r", revs.c_str(), "--xml", this->URL.c_str(), nullptr
+ };
{
LogParser out(this, "log-out> ");
OutputLogger err(this->Log, "log-err> ");
@@ -462,8 +467,8 @@ private:
bool cmCTestBZR::LoadModifications()
{
// Run "bzr status" which reports local modifications.
- std::string bzr = this->CommandLineTool;
- std::vector<std::string> bzr_status = { bzr, "status", "-SV" };
+ const char* bzr = this->CommandLineTool.c_str();
+ const char* bzr_status[] = { bzr, "status", "-SV", nullptr };
StatusParser out(this, "status-out> ");
OutputLogger err(this->Log, "status-err> ");
this->RunChild(bzr_status, &out, &err);
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index bb6ccc3..5feb953 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -7,6 +7,8 @@
#include <cstring>
#include <ratio>
+#include "cmsys/Process.h"
+
#include "cmBuildOptions.h"
#include "cmCTest.h"
#include "cmCTestTestHandler.h"
@@ -306,11 +308,12 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
return 1;
}
- std::vector<std::string> testCommand;
- testCommand.push_back(fullPath);
+ std::vector<const char*> testCommand;
+ testCommand.push_back(fullPath.c_str());
for (std::string const& testCommandArg : this->TestCommandArgs) {
- testCommand.push_back(testCommandArg);
+ testCommand.push_back(testCommandArg.c_str());
}
+ testCommand.push_back(nullptr);
std::string outs;
int retval = 0;
// run the test from the this->BuildRunDir if set
@@ -346,10 +349,10 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
}
}
- bool runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr,
- remainingTime, nullptr);
+ int runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr,
+ remainingTime, nullptr);
- if (!runTestRes || retval != 0) {
+ if (runTestRes != cmsysProcess_State_Exited || retval != 0) {
out << "Test command failed: " << testCommand[0] << "\n";
retval = 1;
}
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index 859798e..00ecf42 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -3,17 +3,15 @@
#include "cmCTestBuildHandler.h"
#include <cstdlib>
-#include <memory>
#include <ratio>
#include <set>
#include <utility>
#include <cmext/algorithm>
-#include <cm3p/uv.h>
-
#include "cmsys/Directory.hxx"
#include "cmsys/FStream.hxx"
+#include "cmsys/Process.h"
#include "cmCTest.h"
#include "cmCTestLaunchReporter.h"
@@ -26,9 +24,6 @@
#include "cmStringAlgorithms.h"
#include "cmStringReplaceHelper.h"
#include "cmSystemTools.h"
-#include "cmUVHandlePtr.h"
-#include "cmUVProcessChain.h"
-#include "cmUVStream.h"
#include "cmValue.h"
#include "cmXMLWriter.h"
@@ -425,7 +420,7 @@ int cmCTestBuildHandler::ProcessHandler()
cmStringReplaceHelper colorRemover("\x1b\\[[0-9;]*m", "", nullptr);
this->ColorRemover = &colorRemover;
int retVal = 0;
- bool res = true;
+ int res = cmsysProcess_State_Exited;
if (!this->CTest->GetShowOnly()) {
res = this->RunMakeCommand(makeCommand, &retVal, buildDirectory.c_str(), 0,
ofs);
@@ -480,7 +475,7 @@ int cmCTestBuildHandler::ProcessHandler()
}
this->GenerateXMLFooter(xml, elapsed_build_time);
- if (!res || retVal || this->TotalErrors > 0) {
+ if (res != cmsysProcess_State_Exited || retVal || this->TotalErrors > 0) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Error(s) when building project" << std::endl);
}
@@ -769,10 +764,10 @@ void cmCTestBuildHandler::LaunchHelper::WriteScrapeMatchers(
}
}
-bool cmCTestBuildHandler::RunMakeCommand(const std::string& command,
- int* retVal, const char* dir,
- int timeout, std::ostream& ofs,
- Encoding encoding)
+int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
+ int* retVal, const char* dir,
+ int timeout, std::ostream& ofs,
+ Encoding encoding)
{
// First generate the command and arguments
std::vector<std::string> args = cmSystemTools::ParseArguments(command);
@@ -781,9 +776,19 @@ bool cmCTestBuildHandler::RunMakeCommand(const std::string& command,
return false;
}
+ std::vector<const char*> argv;
+ argv.reserve(args.size() + 1);
+ for (std::string const& arg : args) {
+ argv.push_back(arg.c_str());
+ }
+ argv.push_back(nullptr);
+
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Run command:", this->Quiet);
- for (auto const& arg : args) {
+ for (char const* arg : argv) {
+ if (!arg) {
+ break;
+ }
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
" \"" << arg << "\"", this->Quiet);
}
@@ -795,20 +800,21 @@ bool cmCTestBuildHandler::RunMakeCommand(const std::string& command,
static_cast<void>(launchHelper);
// Now create process object
- cmUVProcessChainBuilder builder;
- builder.AddCommand(args)
- .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
- .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
- if (dir) {
- builder.SetWorkingDirectory(dir);
- }
- auto chain = builder.Start();
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, argv.data());
+ cmsysProcess_SetWorkingDirectory(cp, dir);
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ cmsysProcess_SetTimeout(cp, timeout);
+ cmsysProcess_Execute(cp);
// Initialize tick's
std::string::size_type tick = 0;
- static constexpr std::string::size_type tick_len = 1024;
+ const std::string::size_type tick_len = 1024;
+ char* data;
+ int length;
cmProcessOutput processOutput(encoding);
+ std::string strdata;
cmCTestOptionalLog(
this->CTest, HANDLER_PROGRESS_OUTPUT,
" Each symbol represents "
@@ -830,65 +836,39 @@ bool cmCTestBuildHandler::RunMakeCommand(const std::string& command,
this->WarningQuotaReached = false;
this->ErrorQuotaReached = false;
- cm::uv_timer_ptr timer;
- bool timedOut = false;
- timer.init(chain.GetLoop(), &timedOut);
- if (timeout > 0) {
- timer.start(
- [](uv_timer_t* t) {
- auto* timedOutPtr = static_cast<bool*>(t->data);
- *timedOutPtr = true;
- },
- timeout * 1000, 0);
- }
-
// For every chunk of data
- cm::uv_pipe_ptr outputStream;
- bool outFinished = false;
- cm::uv_pipe_ptr errorStream;
- bool errFinished = false;
- auto startRead = [this, &chain, &processOutput, &tick,
- &ofs](cm::uv_pipe_ptr& pipe, int stream,
- t_BuildProcessingQueueType& queue, bool& finished,
- int id) -> std::unique_ptr<cmUVStreamReadHandle> {
- pipe.init(chain.GetLoop(), 0);
- uv_pipe_open(pipe, stream);
- return cmUVStreamRead(
- pipe,
- [this, &processOutput, &queue, id, &tick, &ofs](std::vector<char> data) {
- // Replace '\0' with '\n', since '\0' does not really make sense. This
- // is for Visual Studio output
- for (auto& c : data) {
- if (c == 0) {
- c = '\n';
- }
- }
+ int res;
+ while ((res = cmsysProcess_WaitForData(cp, &data, &length, 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) {
+ data[cc] = '\n';
+ }
+ }
- // Process the chunk of data
- std::string strdata;
- processOutput.DecodeText(data.data(), data.size(), strdata, id);
- this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len,
- ofs, &queue);
- },
- [this, &processOutput, &queue, id, &tick, &ofs, &finished]() {
- std::string strdata;
- processOutput.DecodeText(std::string(), strdata, id);
- if (!strdata.empty()) {
- this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len,
- ofs, &queue);
- }
- finished = true;
- });
- };
- auto outputHandle = startRead(outputStream, chain.OutputStream(),
- this->BuildProcessingQueue, outFinished, 1);
- auto errorHandle =
- startRead(errorStream, chain.ErrorStream(),
- this->BuildProcessingErrorQueue, errFinished, 2);
-
- while (!timedOut && !(outFinished && errFinished && chain.Finished())) {
- uv_run(&chain.GetLoop(), UV_RUN_ONCE);
+ // Process the chunk of data
+ 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);
+ }
+ }
+ 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(nullptr, 0, tick, tick_len, ofs,
&this->BuildProcessingQueue);
this->ProcessBuffer(nullptr, 0, tick, tick_len, ofs,
@@ -899,93 +879,90 @@ bool cmCTestBuildHandler::RunMakeCommand(const std::string& command,
<< std::endl,
this->Quiet);
- if (chain.Finished()) {
- auto const& status = chain.GetStatus(0);
- auto exception = status.GetException();
- switch (exception.first) {
- case cmUVProcessChain::ExceptionCode::None:
- if (retVal) {
- *retVal = static_cast<int>(status.ExitStatus);
- 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 there was an error running command, report that on the
- // dashboard.
- if (this->UseCTestLaunch) {
- // For launchers, do not record this top-level error if other
- // more granular build errors have already been captured.
- bool launcherXMLFound = false;
- cmsys::Directory launchDir;
- launchDir.Load(this->CTestLaunchDir);
- unsigned long n = launchDir.GetNumberOfFiles();
- for (unsigned long i = 0; i < n; ++i) {
- const char* fname = launchDir.GetFile(i);
- if (cmHasLiteralSuffix(fname, ".xml")) {
- launcherXMLFound = true;
- break;
- }
- }
- if (!launcherXMLFound) {
- cmCTestLaunchReporter reporter;
- reporter.RealArgs = args;
- reporter.ComputeFileNames();
- reporter.ExitCode = *retVal;
- reporter.Status = status;
- // Use temporary BuildLog file to populate this error for
- // CDash.
- ofs.flush();
- reporter.LogOut = this->LogFileNames["Build"];
- reporter.LogOut += ".tmp";
- reporter.WriteXML();
- }
- } else {
- cmCTestBuildErrorWarning errorwarning;
- errorwarning.LineNumber = 0;
- errorwarning.LogLine = 1;
- errorwarning.Text = cmStrCat(
- "*** WARNING non-zero return value in ctest from: ", args[0]);
- errorwarning.PreContext.clear();
- errorwarning.PostContext.clear();
- errorwarning.Error = false;
- this->ErrorsAndWarnings.push_back(std::move(errorwarning));
- this->TotalWarnings++;
+ // Properly handle output of the build command
+ cmsysProcess_WaitForExit(cp, nullptr);
+ int result = cmsysProcess_GetState(cp);
+
+ if (result == cmsysProcess_State_Exited) {
+ if (retVal) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ 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 there was an error running command, report that on the
+ // dashboard.
+ if (this->UseCTestLaunch) {
+ // For launchers, do not record this top-level error if other
+ // more granular build errors have already been captured.
+ bool launcherXMLFound = false;
+ cmsys::Directory launchDir;
+ launchDir.Load(this->CTestLaunchDir);
+ unsigned long n = launchDir.GetNumberOfFiles();
+ for (unsigned long i = 0; i < n; ++i) {
+ const char* fname = launchDir.GetFile(i);
+ if (cmHasLiteralSuffix(fname, ".xml")) {
+ launcherXMLFound = true;
+ break;
}
}
+ if (!launcherXMLFound) {
+ cmCTestLaunchReporter reporter;
+ reporter.RealArgs = args;
+ reporter.ComputeFileNames();
+ reporter.ExitCode = *retVal;
+ reporter.Process = cp;
+ // Use temporary BuildLog file to populate this error for CDash.
+ ofs.flush();
+ reporter.LogOut = this->LogFileNames["Build"];
+ reporter.LogOut += ".tmp";
+ reporter.WriteXML();
+ }
+ } else {
+ cmCTestBuildErrorWarning errorwarning;
+ errorwarning.LineNumber = 0;
+ errorwarning.LogLine = 1;
+ errorwarning.Text = cmStrCat(
+ "*** WARNING non-zero return value in ctest from: ", argv[0]);
+ errorwarning.PreContext.clear();
+ errorwarning.PostContext.clear();
+ errorwarning.Error = false;
+ this->ErrorsAndWarnings.push_back(std::move(errorwarning));
+ this->TotalWarnings++;
}
- break;
- case cmUVProcessChain::ExceptionCode::Spawn: {
- // If there was an error running command, report that on the dashboard.
- cmCTestBuildErrorWarning errorwarning;
- errorwarning.LineNumber = 0;
- errorwarning.LogLine = 1;
- errorwarning.Text =
- cmStrCat("*** ERROR executing: ", exception.second);
- errorwarning.PreContext.clear();
- errorwarning.PostContext.clear();
- errorwarning.Error = true;
- this->ErrorsAndWarnings.push_back(std::move(errorwarning));
- this->TotalErrors++;
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "There was an error: " << exception.second << std::endl);
- } break;
- default:
- if (retVal) {
- *retVal = status.TermSignal;
- cmCTestOptionalLog(
- this->CTest, WARNING,
- "There was an exception: " << *retVal << std::endl, this->Quiet);
- }
- break;
+ }
}
- } else {
+ } else if (result == cmsysProcess_State_Exception) {
+ if (retVal) {
+ *retVal = cmsysProcess_GetExitException(cp);
+ cmCTestOptionalLog(this->CTest, WARNING,
+ "There was an exception: " << *retVal << std::endl,
+ this->Quiet);
+ }
+ } 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.LineNumber = 0;
+ errorwarning.LogLine = 1;
+ errorwarning.Text =
+ cmStrCat("*** ERROR executing: ", cmsysProcess_GetErrorString(cp));
+ errorwarning.PreContext.clear();
+ errorwarning.PostContext.clear();
+ errorwarning.Error = true;
+ this->ErrorsAndWarnings.push_back(std::move(errorwarning));
+ this->TotalErrors++;
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "There was an error: " << cmsysProcess_GetErrorString(cp)
+ << std::endl);
}
- return true;
+ cmsysProcess_Delete(cp);
+ return result;
}
// ######################################################################
diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h
index 90945b1..e33294d 100644
--- a/Source/CTest/cmCTestBuildHandler.h
+++ b/Source/CTest/cmCTestBuildHandler.h
@@ -53,9 +53,9 @@ private:
//! Run command specialized for make and configure. Returns process status
// and retVal is return value or exception.
- bool RunMakeCommand(const std::string& command, int* retVal, const char* dir,
- int timeout, std::ostream& ofs,
- Encoding encoding = cmProcessOutput::Auto);
+ int RunMakeCommand(const std::string& command, int* retVal, const char* dir,
+ int timeout, std::ostream& ofs,
+ Encoding encoding = cmProcessOutput::Auto);
enum
{
diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx
index ef95b25..95e898c 100644
--- a/Source/CTest/cmCTestCVS.cxx
+++ b/Source/CTest/cmCTestCVS.cxx
@@ -5,7 +5,6 @@
#include <utility>
#include <cm/string_view>
-#include <cmext/algorithm>
#include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
@@ -90,15 +89,18 @@ bool cmCTestCVS::UpdateImpl()
}
// Run "cvs update" to update the work tree.
- std::vector<std::string> cvs_update;
- cvs_update.push_back(this->CommandLineTool);
+ std::vector<char const*> cvs_update;
+ cvs_update.push_back(this->CommandLineTool.c_str());
cvs_update.push_back("-z3");
cvs_update.push_back("update");
- cm::append(cvs_update, args);
+ for (std::string const& arg : args) {
+ cvs_update.push_back(arg.c_str());
+ }
+ cvs_update.push_back(nullptr);
UpdateParser out(this, "up-out> ");
UpdateParser err(this, "up-err> ");
- return this->RunUpdateCommand(cvs_update, &out, &err);
+ return this->RunUpdateCommand(cvs_update.data(), &out, &err);
}
class cmCTestCVS::LogParser : public cmCTestVC::LineParser
@@ -219,8 +221,10 @@ void cmCTestCVS::LoadRevisions(std::string const& file, const char* branchFlag,
cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
// Run "cvs log" to get revisions of this file on this branch.
- std::string cvs = this->CommandLineTool;
- std::vector<std::string> cvs_log = { cvs, "log", "-N", branchFlag, file };
+ const char* cvs = this->CommandLineTool.c_str();
+ const char* cvs_log[] = {
+ cvs, "log", "-N", branchFlag, file.c_str(), nullptr
+ };
LogParser out(this, "log-out> ", revisions);
OutputLogger err(this->Log, "log-err> ");
diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx
index dd8952f..914930e 100644
--- a/Source/CTest/cmCTestConfigureHandler.cxx
+++ b/Source/CTest/cmCTestConfigureHandler.cxx
@@ -45,7 +45,7 @@ int cmCTestConfigureHandler::ProcessHandler()
auto elapsed_time_start = std::chrono::steady_clock::now();
std::string output;
int retVal = 0;
- bool res = false;
+ int res = 0;
if (!this->CTest->GetShowOnly()) {
cmGeneratedFileStream os;
if (!this->StartResultingXML(cmCTest::PartConfigure, "Configure", os)) {
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index f9f9add..2874be7 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -9,7 +9,6 @@
#include <cstring>
#include <iomanip>
#include <iterator>
-#include <memory>
#include <ratio>
#include <sstream>
#include <type_traits>
@@ -19,6 +18,7 @@
#include "cmsys/FStream.hxx"
#include "cmsys/Glob.hxx"
+#include "cmsys/Process.h"
#include "cmsys/RegularExpression.hxx"
#include "cmCTest.h"
@@ -33,7 +33,6 @@
#include "cmParsePHPCoverage.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
-#include "cmUVProcessChain.h"
#include "cmWorkingDirectory.h"
#include "cmXMLWriter.h"
@@ -41,6 +40,85 @@ class cmMakefile;
#define SAFEDIV(x, y) (((y) != 0) ? ((x) / (y)) : (0))
+class cmCTestRunProcess
+{
+public:
+ cmCTestRunProcess()
+ {
+ this->Process = cmsysProcess_New();
+ this->PipeState = -1;
+ this->TimeOut = cmDuration(-1);
+ }
+ ~cmCTestRunProcess()
+ {
+ if (this->PipeState != -1 && this->PipeState != cmsysProcess_Pipe_None &&
+ this->PipeState != cmsysProcess_Pipe_Timeout) {
+ this->WaitForExit();
+ }
+ cmsysProcess_Delete(this->Process);
+ }
+ cmCTestRunProcess(const cmCTestRunProcess&) = delete;
+ cmCTestRunProcess& operator=(const cmCTestRunProcess&) = delete;
+ void SetCommand(const char* command)
+ {
+ this->CommandLineStrings.clear();
+ this->CommandLineStrings.emplace_back(command);
+ }
+ void AddArgument(const char* arg)
+ {
+ if (arg) {
+ this->CommandLineStrings.emplace_back(arg);
+ }
+ }
+ void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; }
+ void SetTimeout(cmDuration t) { this->TimeOut = t; }
+ bool StartProcess()
+ {
+ std::vector<const char*> args;
+ args.reserve(this->CommandLineStrings.size());
+ for (std::string const& cl : this->CommandLineStrings) {
+ args.push_back(cl.c_str());
+ }
+ args.push_back(nullptr); // null terminate
+ cmsysProcess_SetCommand(this->Process, args.data());
+ if (!this->WorkingDirectory.empty()) {
+ cmsysProcess_SetWorkingDirectory(this->Process,
+ this->WorkingDirectory.c_str());
+ }
+
+ cmsysProcess_SetOption(this->Process, cmsysProcess_Option_HideWindow, 1);
+ if (this->TimeOut >= cmDuration::zero()) {
+ cmsysProcess_SetTimeout(this->Process, this->TimeOut.count());
+ }
+ 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 = nullptr)
+ {
+ this->PipeState = cmsysProcess_WaitForExit(this->Process, timeout);
+ return this->PipeState;
+ }
+ int GetProcessState() const { return this->PipeState; }
+
+private:
+ int PipeState;
+ cmsysProcess* Process;
+ std::vector<std::string> CommandLineStrings;
+ std::string WorkingDirectory;
+ cmDuration TimeOut;
+};
+
cmCTestCoverageHandler::cmCTestCoverageHandler() = default;
void cmCTestCoverageHandler::Initialize()
@@ -1862,35 +1940,34 @@ int cmCTestCoverageHandler::RunBullseyeCommand(
cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find :" << cmd << "\n");
return 0;
}
- std::vector<std::string> args{ cmd };
if (arg) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Run : " << program << " " << arg << "\n", this->Quiet);
- args.emplace_back(arg);
} else {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Run : " << program << "\n", this->Quiet);
}
// create a process object and start it
- cmUVProcessChainBuilder builder;
+ cmCTestRunProcess runCoverageSrc;
+ runCoverageSrc.SetCommand(program.c_str());
+ runCoverageSrc.AddArgument(arg);
std::string stdoutFile =
cmStrCat(cont->BinaryDir, "/Testing/Temporary/",
this->GetCTestInstance()->GetCurrentTag(), '-', cmd);
std::string stderrFile = stdoutFile;
stdoutFile += ".stdout";
stderrFile += ".stderr";
- std::unique_ptr<FILE, int (*)(FILE*)> stdoutHandle(
- cmsys::SystemTools::Fopen(stdoutFile, "w"), fclose);
- std::unique_ptr<FILE, int (*)(FILE*)> stderrHandle(
- cmsys::SystemTools::Fopen(stderrFile, "w"), fclose);
- builder.AddCommand(args)
- .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT,
- stdoutHandle.get())
- .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
- stderrHandle.get());
+ runCoverageSrc.SetStdoutFile(stdoutFile.c_str());
+ runCoverageSrc.SetStderrFile(stderrFile.c_str());
+ 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
- auto chain = builder.Start();
- chain.Wait();
+ runCoverageSrc.WaitForExit();
outputFile = stdoutFile;
return 1;
}
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
index ca8659e..5f8cb74 100644
--- a/Source/CTest/cmCTestGIT.cxx
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -9,9 +9,8 @@
#include <utility>
#include <vector>
-#include <cmext/algorithm>
-
#include "cmsys/FStream.hxx"
+#include "cmsys/Process.h"
#include "cmCTest.h"
#include "cmCTestVC.h"
@@ -19,7 +18,6 @@
#include "cmProcessOutput.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
-#include "cmUVProcessChain.h"
#include "cmValue.h"
static unsigned int cmCTestGITVersion(unsigned int epic, unsigned int major,
@@ -60,9 +58,9 @@ private:
std::string cmCTestGIT::GetWorkingRevision()
{
// Run plumbing "git rev-list" to get work tree revision.
- std::string git = this->CommandLineTool;
- std::vector<std::string> git_rev_list = { git, "rev-list", "-n",
- "1", "HEAD", "--" };
+ const char* git = this->CommandLineTool.c_str();
+ const char* git_rev_list[] = { git, "rev-list", "-n", "1",
+ "HEAD", "--", nullptr };
std::string rev;
OneLineParser out(this, "rl-out> ", rev);
OutputLogger err(this->Log, "rl-err> ");
@@ -94,13 +92,13 @@ std::string cmCTestGIT::FindGitDir()
std::string git_dir;
// Run "git rev-parse --git-dir" to locate the real .git directory.
- std::string git = this->CommandLineTool;
- std::vector<std::string> git_rev_parse = { git, "rev-parse", "--git-dir" };
+ const char* git = this->CommandLineTool.c_str();
+ char const* git_rev_parse[] = { git, "rev-parse", "--git-dir", 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,
- std::string{}, cmProcessOutput::UTF8)) {
+ if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, nullptr,
+ cmProcessOutput::UTF8)) {
git_dir = git_dir_line;
}
if (git_dir.empty()) {
@@ -119,10 +117,11 @@ std::string cmCTestGIT::FindGitDir()
std::string cygpath_exe =
cmStrCat(cmSystemTools::GetFilenamePath(git), "/cygpath.exe");
if (cmSystemTools::FileExists(cygpath_exe)) {
- std::vector<std::string> cygpath = { cygpath_exe, "-w", git_dir };
+ 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, std::string{},
+ if (this->RunChild(cygpath, &cygpath_out, &cygpath_err, nullptr,
cmProcessOutput::UTF8)) {
git_dir = git_dir_line;
}
@@ -137,12 +136,12 @@ std::string cmCTestGIT::FindTopDir()
std::string top_dir = this->SourceDirectory;
// Run "git rev-parse --show-cdup" to locate the top of the tree.
- std::string git = this->CommandLineTool;
- std::vector<std::string> git_rev_parse = { git, "rev-parse", "--show-cdup" };
+ const char* git = this->CommandLineTool.c_str();
+ char const* git_rev_parse[] = { git, "rev-parse", "--show-cdup", 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, "",
+ if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, nullptr,
cmProcessOutput::UTF8) &&
!cdup.empty()) {
top_dir += "/";
@@ -154,10 +153,10 @@ std::string cmCTestGIT::FindTopDir()
bool cmCTestGIT::UpdateByFetchAndReset()
{
- std::string git = this->CommandLineTool;
+ const char* git = this->CommandLineTool.c_str();
// Use "git fetch" to get remote commits.
- std::vector<std::string> git_fetch;
+ std::vector<char const*> git_fetch;
git_fetch.push_back(git);
git_fetch.push_back("fetch");
@@ -167,12 +166,17 @@ bool cmCTestGIT::UpdateByFetchAndReset()
opts = this->CTest->GetCTestConfiguration("GITUpdateOptions");
}
std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
- cm::append(git_fetch, args);
+ for (std::string const& arg : args) {
+ git_fetch.push_back(arg.c_str());
+ }
+
+ // Sentinel argument.
+ git_fetch.push_back(nullptr);
// Fetch upstream refs.
OutputLogger fetch_out(this->Log, "fetch-out> ");
OutputLogger fetch_err(this->Log, "fetch-err> ");
- if (!this->RunUpdateCommand(git_fetch, &fetch_out, &fetch_err)) {
+ if (!this->RunUpdateCommand(git_fetch.data(), &fetch_out, &fetch_err)) {
return false;
}
@@ -203,22 +207,25 @@ bool cmCTestGIT::UpdateByFetchAndReset()
}
// Reset the local branch to point at that tracked from upstream.
- std::vector<std::string> git_reset = { git, "reset", "--hard", sha1 };
+ char const* git_reset[] = { git, "reset", "--hard", sha1.c_str(), nullptr };
OutputLogger reset_out(this->Log, "reset-out> ");
OutputLogger reset_err(this->Log, "reset-err> ");
- return this->RunChild(git_reset, &reset_out, &reset_err);
+ return this->RunChild(&git_reset[0], &reset_out, &reset_err);
}
bool cmCTestGIT::UpdateByCustom(std::string const& custom)
{
cmList git_custom_command{ custom, cmList::EmptyElements::Yes };
- std::vector<std::string> git_custom;
- git_custom.reserve(git_custom_command.size());
- cm::append(git_custom, git_custom_command);
+ std::vector<char const*> git_custom;
+ git_custom.reserve(git_custom_command.size() + 1);
+ for (std::string const& i : git_custom_command) {
+ git_custom.push_back(i.c_str());
+ }
+ git_custom.push_back(nullptr);
OutputLogger custom_out(this->Log, "custom-out> ");
OutputLogger custom_err(this->Log, "custom-err> ");
- return this->RunUpdateCommand(git_custom, &custom_out, &custom_err);
+ return this->RunUpdateCommand(git_custom.data(), &custom_out, &custom_err);
}
bool cmCTestGIT::UpdateInternal()
@@ -237,14 +244,13 @@ bool cmCTestGIT::UpdateImpl()
}
std::string top_dir = this->FindTopDir();
- std::string git = this->CommandLineTool;
- std::string recursive = "--recursive";
- std::string sync_recursive = "--recursive";
+ 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
- bool support_recursive = true;
if (this->GetGitVersion() < cmCTestGITVersion(1, 6, 5, 0)) {
- support_recursive = false;
+ recursive = nullptr;
// No need to require >= 1.6.5 if there are no submodules.
if (cmSystemTools::FileExists(top_dir + "/.gitmodules")) {
this->Log << "Git < 1.6.5 cannot update submodules recursively\n";
@@ -252,9 +258,8 @@ bool cmCTestGIT::UpdateImpl()
}
// Git < 1.8.1 did not support sync --recursive
- bool support_sync_recursive = true;
if (this->GetGitVersion() < cmCTestGITVersion(1, 8, 1, 0)) {
- support_sync_recursive = false;
+ sync_recursive = nullptr;
// No need to require >= 1.8.1 if there are no submodules.
if (cmSystemTools::FileExists(top_dir + "/.gitmodules")) {
this->Log << "Git < 1.8.1 cannot synchronize submodules recursively\n";
@@ -269,39 +274,35 @@ bool cmCTestGIT::UpdateImpl()
std::string init_submodules =
this->CTest->GetCTestConfiguration("GITInitSubmodules");
if (cmIsOn(init_submodules)) {
- std::vector<std::string> git_submodule_init = { git, "submodule", "init" };
+ char const* git_submodule_init[] = { git, "submodule", "init", nullptr };
ret = this->RunChild(git_submodule_init, &submodule_out, &submodule_err,
- top_dir);
+ top_dir.c_str());
if (!ret) {
return false;
}
}
- std::vector<std::string> git_submodule_sync = { git, "submodule", "sync" };
- if (support_sync_recursive) {
- git_submodule_sync.push_back(sync_recursive);
- }
+ char const* git_submodule_sync[] = { git, "submodule", "sync",
+ sync_recursive, nullptr };
ret = this->RunChild(git_submodule_sync, &submodule_out, &submodule_err,
- top_dir);
+ top_dir.c_str());
if (!ret) {
return false;
}
- std::vector<std::string> git_submodule = { git, "submodule", "update" };
- if (support_recursive) {
- git_submodule.push_back(recursive);
- }
+ char const* git_submodule[] = { git, "submodule", "update", recursive,
+ nullptr };
return this->RunChild(git_submodule, &submodule_out, &submodule_err,
- top_dir);
+ top_dir.c_str());
}
unsigned int cmCTestGIT::GetGitVersion()
{
if (!this->CurrentGitVersion) {
- std::string git = this->CommandLineTool;
- std::vector<std::string> git_version = { git, "--version" };
+ const char* git = this->CommandLineTool.c_str();
+ char const* git_version[] = { git, "--version", nullptr };
std::string version;
OneLineParser version_out(this, "version-out> ", version);
OutputLogger version_err(this->Log, "version-err> ");
@@ -604,49 +605,50 @@ bool cmCTestGIT::LoadRevisions()
{
// Use 'git rev-list ... | git diff-tree ...' to get revisions.
std::string range = this->OldRevision + ".." + this->NewRevision;
- std::string git = this->CommandLineTool;
- std::vector<std::string> git_rev_list = { git, "rev-list", "--reverse",
- range, "--" };
- std::vector<std::string> git_diff_tree = {
- git, "diff-tree", "--stdin", "--always",
- "-z", "-r", "--pretty=raw", "--encoding=utf-8"
+ const char* git = this->CommandLineTool.c_str();
+ const char* git_rev_list[] = { git, "rev-list", "--reverse",
+ range.c_str(), "--", nullptr };
+ const char* git_diff_tree[] = {
+ git, "diff-tree", "--stdin", "--always", "-z",
+ "-r", "--pretty=raw", "--encoding=utf-8", nullptr
};
this->Log << cmCTestGIT::ComputeCommandLine(git_rev_list) << " | "
<< cmCTestGIT::ComputeCommandLine(git_diff_tree) << "\n";
- cmUVProcessChainBuilder builder;
- builder.AddCommand(git_rev_list)
- .AddCommand(git_diff_tree)
- .SetWorkingDirectory(this->SourceDirectory);
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_AddCommand(cp, git_rev_list);
+ cmsysProcess_AddCommand(cp, git_diff_tree);
+ cmsysProcess_SetWorkingDirectory(cp, this->SourceDirectory.c_str());
CommitParser out(this, "dt-out> ");
OutputLogger err(this->Log, "dt-err> ");
- cmCTestGIT::RunProcess(builder, &out, &err, cmProcessOutput::UTF8);
+ cmCTestGIT::RunProcess(cp, &out, &err, cmProcessOutput::UTF8);
// Send one extra zero-byte to terminate the last record.
out.Process("", 1);
+ cmsysProcess_Delete(cp);
return true;
}
bool cmCTestGIT::LoadModifications()
{
- std::string git = this->CommandLineTool;
+ const char* git = this->CommandLineTool.c_str();
// Use 'git update-index' to refresh the index w.r.t. the work tree.
- std::vector<std::string> git_update_index = { git, "update-index",
- "--refresh" };
+ const char* git_update_index[] = { git, "update-index", "--refresh",
+ 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, nullptr,
cmProcessOutput::UTF8);
// Use 'git diff-index' to get modified files.
- std::vector<std::string> git_diff_index = { git, "diff-index", "-z", "HEAD",
- "--" };
+ const char* git_diff_index[] = { git, "diff-index", "-z",
+ "HEAD", "--", nullptr };
DiffParser out(this, "di-out> ");
OutputLogger err(this->Log, "di-err> ");
- this->RunChild(git_diff_index, &out, &err, "", cmProcessOutput::UTF8);
+ this->RunChild(git_diff_index, &out, &err, nullptr, cmProcessOutput::UTF8);
for (Change const& c : out.Changes) {
this->DoModification(PathModified, c.Path);
diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx
index e1a945d..02837ba 100644
--- a/Source/CTest/cmCTestHG.cxx
+++ b/Source/CTest/cmCTestHG.cxx
@@ -95,8 +95,8 @@ private:
std::string cmCTestHG::GetWorkingRevision()
{
// Run plumbing "hg identify" to get work tree revision.
- std::string hg = this->CommandLineTool;
- std::vector<std::string> hg_identify = { hg, "identify", "-i" };
+ const char* hg = this->CommandLineTool.c_str();
+ const char* hg_identify[] = { hg, "identify", "-i", nullptr };
std::string rev;
IdentifyParser out(this, "rev-out> ", rev);
OutputLogger err(this->Log, "rev-err> ");
@@ -127,16 +127,16 @@ bool cmCTestHG::UpdateImpl()
{
// Use "hg pull" followed by "hg update" to update the working tree.
{
- std::string hg = this->CommandLineTool;
- std::vector<std::string> hg_pull = { hg, "pull", "-v" };
+ const char* hg = this->CommandLineTool.c_str();
+ const char* hg_pull[] = { hg, "pull", "-v", nullptr };
OutputLogger out(this->Log, "pull-out> ");
OutputLogger err(this->Log, "pull-err> ");
- this->RunChild(hg_pull, &out, &err);
+ this->RunChild(&hg_pull[0], &out, &err);
}
// TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
- std::vector<std::string> hg_update;
+ std::vector<char const*> hg_update;
hg_update.push_back(this->CommandLineTool.c_str());
hg_update.push_back("update");
hg_update.push_back("-v");
@@ -147,11 +147,16 @@ bool cmCTestHG::UpdateImpl()
opts = this->CTest->GetCTestConfiguration("HGUpdateOptions");
}
std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
- cm::append(hg_update, args);
+ for (std::string const& arg : args) {
+ hg_update.push_back(arg.c_str());
+ }
+
+ // Sentinel argument.
+ hg_update.push_back(nullptr);
OutputLogger out(this->Log, "update-out> ");
OutputLogger err(this->Log, "update-err> ");
- return this->RunUpdateCommand(hg_update, &out, &err);
+ return this->RunUpdateCommand(hg_update.data(), &out, &err);
}
class cmCTestHG::LogParser
@@ -272,8 +277,8 @@ bool cmCTestHG::LoadRevisions()
// the project has spaces in the path. Also, they may not have
// proper XML escapes.
std::string range = this->OldRevision + ":" + this->NewRevision;
- std::string hg = this->CommandLineTool;
- std::string hgXMLTemplate = "<logentry\n"
+ 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"
@@ -283,8 +288,10 @@ bool cmCTestHG::LoadRevisions()
" <file_adds>{file_adds}</file_adds>\n"
" <file_dels>{file_dels}</file_dels>\n"
"</logentry>\n";
- std::vector<std::string> hg_log = { hg, "log", "--removed", "-r",
- range, "--template", hgXMLTemplate };
+ const char* hg_log[] = {
+ hg, "log", "--removed", "-r", range.c_str(),
+ "--template", hgXMLTemplate, nullptr
+ };
LogParser out(this, "log-out> ");
out.Process("<?xml version=\"1.0\"?>\n"
@@ -298,8 +305,8 @@ bool cmCTestHG::LoadRevisions()
bool cmCTestHG::LoadModifications()
{
// Use 'hg status' to get modified files.
- std::string hg = this->CommandLineTool;
- std::vector<std::string> hg_status = { hg, "status" };
+ const char* hg = this->CommandLineTool.c_str();
+ const char* hg_status[] = { hg, "status", nullptr };
StatusParser out(this, "status-out> ");
OutputLogger err(this->Log, "status-err> ");
this->RunChild(hg_status, &out, &err);
diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
index 9669d76..4a33869 100644
--- a/Source/CTest/cmCTestLaunch.cxx
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -2,15 +2,11 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestLaunch.h"
-#include <cstdio>
#include <cstring>
#include <iostream>
-#include <memory>
-#include <utility>
-
-#include <cm3p/uv.h>
#include "cmsys/FStream.hxx"
+#include "cmsys/Process.h"
#include "cmsys/RegularExpression.hxx"
#include "cmCTestLaunchReporter.h"
@@ -21,9 +17,6 @@
#include "cmStateSnapshot.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
-#include "cmUVHandlePtr.h"
-#include "cmUVProcessChain.h"
-#include "cmUVStream.h"
#include "cmake.h"
#ifdef _WIN32
@@ -35,6 +28,8 @@
cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
{
+ this->Process = nullptr;
+
if (!this->ParseArguments(argc, argv)) {
return;
}
@@ -45,9 +40,13 @@ cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
this->ScrapeRulesLoaded = false;
this->HaveOut = false;
this->HaveErr = false;
+ this->Process = cmsysProcess_New();
}
-cmCTestLaunch::~cmCTestLaunch() = default;
+cmCTestLaunch::~cmCTestLaunch()
+{
+ cmsysProcess_Delete(this->Process);
+}
bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
{
@@ -114,12 +113,15 @@ bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
// Extract the real command line.
if (arg0) {
- for (int i = 0; i < argc - arg0; ++i) {
- this->RealArgV.emplace_back((argv + arg0)[i]);
- this->HandleRealArg((argv + arg0)[i]);
+ this->RealArgC = argc - arg0;
+ this->RealArgV = argv + arg0;
+ for (int i = 0; i < this->RealArgC; ++i) {
+ this->HandleRealArg(this->RealArgV[i]);
}
return true;
}
+ this->RealArgC = 0;
+ this->RealArgV = nullptr;
std::cerr << "No launch/command separator ('--') found!\n";
return false;
}
@@ -149,19 +151,17 @@ void cmCTestLaunch::RunChild()
}
// Prepare to run the real command.
- cmUVProcessChainBuilder builder;
- builder.AddCommand(this->RealArgV);
+ cmsysProcess* cp = this->Process;
+ cmsysProcess_SetCommand(cp, this->RealArgV);
cmsys::ofstream fout;
cmsys::ofstream ferr;
if (this->Reporter.Passthru) {
// In passthru mode we just share the output pipes.
- builder.SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, stdout)
- .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, stderr);
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
} else {
// In full mode we record the child output pipes to log files.
- builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
- .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
fout.open(this->Reporter.LogOut.c_str(), std::ios::out | std::ios::binary);
ferr.open(this->Reporter.LogErr.c_str(), std::ios::out | std::ios::binary);
}
@@ -174,65 +174,51 @@ void cmCTestLaunch::RunChild()
#endif
// Run the real command.
- auto chain = builder.Start();
+ cmsysProcess_Execute(cp);
// Record child stdout and stderr if necessary.
- cm::uv_pipe_ptr outPipe;
- cm::uv_pipe_ptr errPipe;
- bool outFinished = true;
- bool errFinished = true;
- cmProcessOutput processOutput;
- std::unique_ptr<cmUVStreamReadHandle> outputHandle;
- std::unique_ptr<cmUVStreamReadHandle> errorHandle;
if (!this->Reporter.Passthru) {
- auto beginRead = [&chain, &processOutput](
- cm::uv_pipe_ptr& pipe, int stream, std::ostream& out,
- cmsys::ofstream& file, bool& haveData, bool& finished,
- int id) -> std::unique_ptr<cmUVStreamReadHandle> {
- pipe.init(chain.GetLoop(), 0);
- uv_pipe_open(pipe, stream);
- finished = false;
- return cmUVStreamRead(
- pipe,
- [&processOutput, &out, &file, id, &haveData](std::vector<char> data) {
- std::string strdata;
- processOutput.DecodeText(data.data(), data.size(), strdata, id);
- file.write(strdata.c_str(), strdata.size());
- out.write(strdata.c_str(), strdata.size());
- haveData = true;
- },
- [&processOutput, &out, &file, &finished, id]() {
- std::string strdata;
- processOutput.DecodeText(std::string(), strdata, id);
- if (!strdata.empty()) {
- file.write(strdata.c_str(), strdata.size());
- out.write(strdata.c_str(), strdata.size());
- }
- finished = true;
- });
- };
- outputHandle = beginRead(outPipe, chain.OutputStream(), std::cout, fout,
- this->HaveOut, outFinished, 1);
- errorHandle = beginRead(errPipe, chain.ErrorStream(), std::cerr, ferr,
- this->HaveErr, errFinished, 2);
+ char* data = nullptr;
+ int length = 0;
+ cmProcessOutput processOutput;
+ std::string strdata;
+ while (int p = cmsysProcess_WaitForData(cp, &data, &length, 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) {
+ 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.
- while (!(chain.Finished() && outFinished && errFinished)) {
- uv_run(&chain.GetLoop(), UV_RUN_ONCE);
- }
- this->Reporter.Status = chain.GetStatus(0);
- if (this->Reporter.Status.GetException().first ==
- cmUVProcessChain::ExceptionCode::Spawn) {
- this->Reporter.ExitCode = 1;
- } else {
- this->Reporter.ExitCode =
- static_cast<int>(this->Reporter.Status.ExitStatus);
- }
+ cmsysProcess_WaitForExit(cp, nullptr);
+ this->Reporter.ExitCode = cmsysProcess_GetExitValue(cp);
}
int cmCTestLaunch::Run()
{
+ if (!this->Process) {
+ std::cerr << "Could not allocate cmsysProcess instance!\n";
+ return -1;
+ }
+
this->RunChild();
if (this->CheckResults()) {
@@ -240,6 +226,7 @@ int cmCTestLaunch::Run()
}
this->LoadConfig();
+ this->Reporter.Process = this->Process;
this->Reporter.WriteXML();
return this->Reporter.ExitCode;
diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h
index ef21a26..c5a6476 100644
--- a/Source/CTest/cmCTestLaunch.h
+++ b/Source/CTest/cmCTestLaunch.h
@@ -43,12 +43,15 @@ private:
bool ParseArguments(int argc, const char* const* argv);
// The real command line appearing after launcher arguments.
- std::vector<std::string> RealArgV;
+ int RealArgC;
+ const char* const* RealArgV;
// The real command line after response file expansion.
std::vector<std::string> RealArgs;
void HandleRealArg(const char* arg);
+ struct cmsysProcess_s* Process;
+
// Whether or not any data have been written to stdout or stderr.
bool HaveOut;
bool HaveErr;
diff --git a/Source/CTest/cmCTestLaunchReporter.cxx b/Source/CTest/cmCTestLaunchReporter.cxx
index 4b4e5c5..149ba5d 100644
--- a/Source/CTest/cmCTestLaunchReporter.cxx
+++ b/Source/CTest/cmCTestLaunchReporter.cxx
@@ -2,9 +2,8 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestLaunchReporter.h"
-#include <utility>
-
#include "cmsys/FStream.hxx"
+#include "cmsys/Process.h"
#include "cmsys/RegularExpression.hxx"
#include "cmCryptoHash.h"
@@ -23,7 +22,6 @@
cmCTestLaunchReporter::cmCTestLaunchReporter()
{
this->Passthru = true;
- this->Status.Finished = true;
this->ExitCode = 1;
this->CWD = cmSystemTools::GetCurrentWorkingDirectory();
@@ -233,23 +231,35 @@ void cmCTestLaunchReporter::WriteXMLResult(cmXMLElement& e2)
// ExitCondition
cmXMLElement e4(e3, "ExitCondition");
- if (this->Status.Finished) {
- auto exception = this->Status.GetException();
- switch (exception.first) {
- case cmUVProcessChain::ExceptionCode::None:
- e4.Content(this->ExitCode);
- break;
- case cmUVProcessChain::ExceptionCode::Spawn:
- e4.Content("Error administrating child process: ");
- e4.Content(exception.second);
- break;
- default:
- e4.Content("Terminated abnormally: ");
- e4.Content(exception.second);
- break;
- }
- } else {
- e4.Content("Killed when timeout expired");
+ cmsysProcess* cp = this->Process;
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Starting:
+ e4.Content("No process has been executed");
+ break;
+ case cmsysProcess_State_Executing:
+ e4.Content("The process is still executing");
+ break;
+ case cmsysProcess_State_Disowned:
+ e4.Content("Disowned");
+ break;
+ case cmsysProcess_State_Killed:
+ e4.Content("Killed by parent");
+ break;
+
+ case cmsysProcess_State_Expired:
+ e4.Content("Killed when timeout expired");
+ break;
+ case cmsysProcess_State_Exited:
+ e4.Content(this->ExitCode);
+ break;
+ case cmsysProcess_State_Exception:
+ e4.Content("Terminated abnormally: ");
+ e4.Content(cmsysProcess_GetExceptionString(cp));
+ break;
+ case cmsysProcess_State_Error:
+ e4.Content("Error administrating child process: ");
+ e4.Content(cmsysProcess_GetErrorString(cp));
+ break;
}
}
diff --git a/Source/CTest/cmCTestLaunchReporter.h b/Source/CTest/cmCTestLaunchReporter.h
index 2bb78f8..4be0d9b 100644
--- a/Source/CTest/cmCTestLaunchReporter.h
+++ b/Source/CTest/cmCTestLaunchReporter.h
@@ -10,8 +10,6 @@
#include "cmsys/RegularExpression.hxx"
-#include "cmUVProcessChain.h"
-
class cmXMLElement;
/** \class cmCTestLaunchReporter
@@ -50,7 +48,7 @@ public:
void ComputeFileNames();
bool Passthru;
- cmUVProcessChain::Status Status;
+ struct cmsysProcess_s* Process;
int ExitCode;
// Temporary log files for stdout and stderr of real command.
diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx
index 5d71b84..0e002b9 100644
--- a/Source/CTest/cmCTestP4.cxx
+++ b/Source/CTest/cmCTestP4.cxx
@@ -149,16 +149,17 @@ cmCTestP4::User cmCTestP4::GetUserData(const std::string& username)
auto it = this->Users.find(username);
if (it == this->Users.end()) {
- std::vector<std::string> p4_users;
+ std::vector<char const*> p4_users;
this->SetP4Options(p4_users);
p4_users.push_back("users");
p4_users.push_back("-m");
p4_users.push_back("1");
- p4_users.push_back(username);
+ p4_users.push_back(username.c_str());
+ p4_users.push_back(nullptr);
UserParser out(this, "users-out> ");
OutputLogger err(this->Log, "users-err> ");
- this->RunChild(p4_users, &out, &err);
+ this->RunChild(p4_users.data(), &out, &err);
// The user should now be added to the map. Search again.
it = this->Users.find(username);
@@ -302,10 +303,10 @@ private:
}
};
-void cmCTestP4::SetP4Options(std::vector<std::string>& CommandOptions)
+void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions)
{
if (this->P4Options.empty()) {
- std::string p4 = this->CommandLineTool;
+ const char* p4 = this->CommandLineTool.c_str();
this->P4Options.emplace_back(p4);
// The CTEST_P4_CLIENT variable sets the P4 client used when issuing
@@ -327,12 +328,15 @@ void cmCTestP4::SetP4Options(std::vector<std::string>& CommandOptions)
cm::append(this->P4Options, cmSystemTools::ParseArguments(opts));
}
- CommandOptions = this->P4Options;
+ CommandOptions.clear();
+ for (std::string const& o : this->P4Options) {
+ CommandOptions.push_back(o.c_str());
+ }
}
std::string cmCTestP4::GetWorkingRevision()
{
- std::vector<std::string> p4_identify;
+ std::vector<char const*> p4_identify;
this->SetP4Options(p4_identify);
p4_identify.push_back("changes");
@@ -341,13 +345,14 @@ std::string cmCTestP4::GetWorkingRevision()
p4_identify.push_back("-t");
std::string source = this->SourceDirectory + "/...#have";
- p4_identify.push_back(source);
+ p4_identify.push_back(source.c_str());
+ p4_identify.push_back(nullptr);
std::string rev;
IdentifyParser out(this, "p4_changes-out> ", rev);
OutputLogger err(this->Log, "p4_changes-err> ");
- bool result = this->RunChild(p4_identify, &out, &err);
+ bool result = this->RunChild(p4_identify.data(), &out, &err);
// If there was a problem contacting the server return "<unknown>"
if (!result) {
@@ -383,7 +388,7 @@ bool cmCTestP4::NoteNewRevision()
bool cmCTestP4::LoadRevisions()
{
- std::vector<std::string> p4_changes;
+ std::vector<char const*> p4_changes;
this->SetP4Options(p4_changes);
// Use 'p4 changes ...@old,new' to get a list of changelists
@@ -404,36 +409,38 @@ bool cmCTestP4::LoadRevisions()
.append(this->NewRevision);
p4_changes.push_back("changes");
- p4_changes.push_back(range);
+ p4_changes.push_back(range.c_str());
+ p4_changes.push_back(nullptr);
ChangesParser out(this, "p4_changes-out> ");
OutputLogger err(this->Log, "p4_changes-err> ");
this->ChangeLists.clear();
- this->RunChild(p4_changes, &out, &err);
+ this->RunChild(p4_changes.data(), &out, &err);
if (this->ChangeLists.empty()) {
return true;
}
// p4 describe -s ...@1111111,2222222
- std::vector<std::string> p4_describe;
+ std::vector<char const*> p4_describe;
for (std::string const& i : cmReverseRange(this->ChangeLists)) {
this->SetP4Options(p4_describe);
p4_describe.push_back("describe");
p4_describe.push_back("-s");
- p4_describe.push_back(i);
+ p4_describe.push_back(i.c_str());
+ p4_describe.push_back(nullptr);
DescribeParser outDescribe(this, "p4_describe-out> ");
OutputLogger errDescribe(this->Log, "p4_describe-err> ");
- this->RunChild(p4_describe, &outDescribe, &errDescribe);
+ this->RunChild(p4_describe.data(), &outDescribe, &errDescribe);
}
return true;
}
bool cmCTestP4::LoadModifications()
{
- std::vector<std::string> p4_diff;
+ std::vector<char const*> p4_diff;
this->SetP4Options(p4_diff);
p4_diff.push_back("diff");
@@ -441,11 +448,12 @@ bool cmCTestP4::LoadModifications()
// 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);
+ p4_diff.push_back(source.c_str());
+ p4_diff.push_back(nullptr);
DiffParser out(this, "p4_diff-out> ");
OutputLogger err(this->Log, "p4_diff-err> ");
- this->RunChild(p4_diff, &out, &err);
+ this->RunChild(p4_diff.data(), &out, &err);
return true;
}
@@ -453,14 +461,17 @@ bool cmCTestP4::UpdateCustom(const std::string& custom)
{
cmList p4_custom_command{ custom, cmList::EmptyElements::Yes };
- std::vector<std::string> p4_custom;
- p4_custom.reserve(p4_custom_command.size());
- cm::append(p4_custom, p4_custom_command);
+ std::vector<char const*> p4_custom;
+ p4_custom.reserve(p4_custom_command.size() + 1);
+ for (std::string const& i : p4_custom_command) {
+ p4_custom.push_back(i.c_str());
+ }
+ p4_custom.push_back(nullptr);
OutputLogger custom_out(this->Log, "p4_customsync-out> ");
OutputLogger custom_err(this->Log, "p4_customsync-err> ");
- return this->RunUpdateCommand(p4_custom, &custom_out, &custom_err);
+ return this->RunUpdateCommand(p4_custom.data(), &custom_out, &custom_err);
}
bool cmCTestP4::UpdateImpl()
@@ -477,7 +488,7 @@ bool cmCTestP4::UpdateImpl()
return false;
}
- std::vector<std::string> p4_sync;
+ std::vector<char const*> p4_sync;
this->SetP4Options(p4_sync);
p4_sync.push_back("sync");
@@ -488,7 +499,9 @@ bool cmCTestP4::UpdateImpl()
opts = this->CTest->GetCTestConfiguration("P4UpdateOptions");
}
std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
- cm::append(p4_sync, args);
+ for (std::string const& arg : args) {
+ p4_sync.push_back(arg.c_str());
+ }
std::string source = this->SourceDirectory + "/...";
@@ -502,10 +515,11 @@ bool cmCTestP4::UpdateImpl()
source.append("@\"").append(date).append("\"");
}
- p4_sync.push_back(source);
+ p4_sync.push_back(source.c_str());
+ p4_sync.push_back(nullptr);
OutputLogger out(this->Log, "p4_sync-out> ");
OutputLogger err(this->Log, "p4_sync-err> ");
- return this->RunUpdateCommand(p4_sync, &out, &err);
+ return this->RunUpdateCommand(p4_sync.data(), &out, &err);
}
diff --git a/Source/CTest/cmCTestP4.h b/Source/CTest/cmCTestP4.h
index 827caa1..1889520 100644
--- a/Source/CTest/cmCTestP4.h
+++ b/Source/CTest/cmCTestP4.h
@@ -39,7 +39,7 @@ private:
std::vector<std::string> P4Options;
User GetUserData(const std::string& username);
- void SetP4Options(std::vector<std::string>& options);
+ void SetP4Options(std::vector<char const*>& options);
std::string GetWorkingRevision();
bool NoteOldRevision() override;
diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx
index 14bc510..91a1177 100644
--- a/Source/CTest/cmCTestSVN.cxx
+++ b/Source/CTest/cmCTestSVN.cxx
@@ -33,7 +33,7 @@ cmCTestSVN::~cmCTestSVN() = default;
void cmCTestSVN::CleanupImpl()
{
- std::vector<std::string> svn_cleanup;
+ std::vector<const char*> svn_cleanup;
svn_cleanup.push_back("cleanup");
OutputLogger out(this->Log, "cleanup-out> ");
OutputLogger err(this->Log, "cleanup-err> ");
@@ -88,9 +88,9 @@ static bool cmCTestSVNPathStarts(std::string const& p1, std::string const& p2)
std::string cmCTestSVN::LoadInfo(SVNInfo& svninfo)
{
// Run "svn info" to get the repository info from the work tree.
- std::vector<std::string> svn_info;
+ std::vector<const char*> svn_info;
svn_info.push_back("info");
- svn_info.push_back(svninfo.LocalPath);
+ svn_info.push_back(svninfo.LocalPath.c_str());
std::string rev;
InfoParser out(this, "info-out> ", rev, svninfo);
OutputLogger err(this->Log, "info-err> ");
@@ -251,24 +251,26 @@ bool cmCTestSVN::UpdateImpl()
args.push_back("-r{" + this->GetNightlyTime() + " +0000}");
}
- std::vector<std::string> svn_update;
+ std::vector<char const*> svn_update;
svn_update.push_back("update");
- cm::append(svn_update, args);
+ for (std::string const& arg : args) {
+ svn_update.push_back(arg.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<std::string> const& parameters,
+bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters,
OutputParser* out, OutputParser* err)
{
if (parameters.empty()) {
return false;
}
- std::vector<std::string> args;
- args.push_back(this->CommandLineTool);
+ std::vector<char const*> args;
+ args.push_back(this->CommandLineTool.c_str());
cm::append(args, parameters);
args.push_back("--non-interactive");
@@ -276,12 +278,16 @@ bool cmCTestSVN::RunSVNCommand(std::vector<std::string> const& parameters,
std::vector<std::string> parsedUserOptions =
cmSystemTools::ParseArguments(userOptions);
- cm::append(args, parsedUserOptions);
+ for (std::string const& opt : parsedUserOptions) {
+ args.push_back(opt.c_str());
+ }
+
+ args.push_back(nullptr);
- if (parameters[0] == "update") {
- return this->RunUpdateCommand(args, out, err);
+ if (strcmp(parameters[0], "update") == 0) {
+ return this->RunUpdateCommand(args.data(), out, err);
}
- return this->RunChild(args, out, err);
+ return this->RunChild(args.data(), out, err);
}
class cmCTestSVN::LogParser
@@ -387,7 +393,7 @@ bool cmCTestSVN::LoadRevisions(SVNInfo& svninfo)
}
// Run "svn log" to get all global revisions of interest.
- std::vector<std::string> svn_log;
+ std::vector<const char*> svn_log;
svn_log.push_back("log");
svn_log.push_back("--xml");
svn_log.push_back("-v");
@@ -466,7 +472,7 @@ private:
bool cmCTestSVN::LoadModifications()
{
// Run "svn status" which reports local modifications.
- std::vector<std::string> svn_status;
+ std::vector<const char*> svn_status;
svn_status.push_back("status");
StatusParser out(this, "status-out> ");
OutputLogger err(this->Log, "status-err> ");
@@ -528,7 +534,7 @@ bool cmCTestSVN::LoadRepositories()
this->RootInfo = &(this->Repositories.back());
// Run "svn status" to get the list of external repositories
- std::vector<std::string> svn_status;
+ std::vector<const char*> svn_status;
svn_status.push_back("status");
ExternalParser out(this, "external-out> ");
OutputLogger err(this->Log, "external-err> ");
diff --git a/Source/CTest/cmCTestSVN.h b/Source/CTest/cmCTestSVN.h
index 1485dc0..370d176 100644
--- a/Source/CTest/cmCTestSVN.h
+++ b/Source/CTest/cmCTestSVN.h
@@ -33,7 +33,7 @@ private:
bool NoteNewRevision() override;
bool UpdateImpl() override;
- bool RunSVNCommand(std::vector<std::string> const& parameters,
+ bool RunSVNCommand(std::vector<char const*> const& parameters,
OutputParser* out, OutputParser* err);
// Information about an SVN repository (root repository or external)
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 48f8f6d..461ad1a 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -11,9 +11,8 @@
#include <cm/memory>
-#include <cm3p/uv.h>
-
#include "cmsys/Directory.hxx"
+#include "cmsys/Process.h"
#include "cmCTest.h"
#include "cmCTestBuildCommand.h"
@@ -41,8 +40,6 @@
#include "cmStateSnapshot.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
-#include "cmUVHandlePtr.h"
-#include "cmUVProcessChain.h"
#include "cmValue.h"
#include "cmake.h"
@@ -151,65 +148,66 @@ int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
// now pass through all the other arguments
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) {
+ argv.push_back(initArgs[i].c_str());
+ }
+ argv.push_back(nullptr);
// Now create process object
- cmUVProcessChainBuilder builder;
- builder.AddCommand(initArgs)
- .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
- .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
- auto process = builder.Start();
- cm::uv_pipe_ptr outPipe;
- outPipe.init(process.GetLoop(), 0);
- uv_pipe_open(outPipe, process.OutputStream());
- cm::uv_pipe_ptr errPipe;
- errPipe.init(process.GetLoop(), 0);
- uv_pipe_open(errPipe, process.ErrorStream());
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, argv.data());
+ // cmsysProcess_SetWorkingDirectory(cp, dir);
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ // cmsysProcess_SetTimeout(cp, timeout);
+ cmsysProcess_Execute(cp);
std::vector<char> out;
std::vector<char> err;
std::string line;
- auto pipe =
- cmSystemTools::WaitForLine(&process.GetLoop(), outPipe, errPipe, line,
- std::chrono::seconds(100), out, err);
- while (pipe != cmSystemTools::WaitForLineResult::None) {
+ int pipe =
+ cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, err);
+ while (pipe != cmsysProcess_Pipe_None) {
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Output: " << line << "\n");
- if (pipe == cmSystemTools::WaitForLineResult::STDERR) {
+ if (pipe == cmsysProcess_Pipe_STDERR) {
cmCTestLog(this->CTest, ERROR_MESSAGE, line << "\n");
- } else if (pipe == cmSystemTools::WaitForLineResult::STDOUT) {
+ } else if (pipe == cmsysProcess_Pipe_STDOUT) {
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n");
}
- pipe =
- cmSystemTools::WaitForLine(&process.GetLoop(), outPipe, errPipe, line,
- std::chrono::seconds(100), out, err);
+ pipe = cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out,
+ err);
}
// Properly handle output of the build command
- process.Wait();
- auto const& status = process.GetStatus(0);
- auto result = status.GetException();
+ cmsysProcess_WaitForExit(cp, nullptr);
+ int result = cmsysProcess_GetState(cp);
int retVal = 0;
bool failed = false;
- switch (result.first) {
- case cmUVProcessChain::ExceptionCode::None:
- retVal = static_cast<int>(status.ExitStatus);
- break;
- case cmUVProcessChain::ExceptionCode::Spawn:
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "\tError executing ctest: " << result.second << std::endl);
- failed = true;
- break;
- default:
- retVal = status.TermSignal;
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "\tThere was an exception: " << result.second << " " << retVal
- << std::endl);
- failed = true;
+ if (result == cmsysProcess_State_Exited) {
+ retVal = cmsysProcess_GetExitValue(cp);
+ } 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);
+ failed = true;
+ } else if (result == cmsysProcess_State_Expired) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "\tThere was a timeout" << std::endl);
+ failed = true;
+ } else if (result == cmsysProcess_State_Error) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "\tError executing ctest: " << cmsysProcess_GetErrorString(cp)
+ << std::endl);
+ failed = true;
}
+ cmsysProcess_Delete(cp);
if (failed) {
std::ostringstream message;
message << "Error running command: [";
- message << static_cast<int>(result.first) << "] ";
+ message << result << "] ";
for (const char* arg : argv) {
if (arg) {
message << arg << " ";
diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx
index cbbb5a5..609ccba 100644
--- a/Source/CTest/cmCTestVC.cxx
+++ b/Source/CTest/cmCTestVC.cxx
@@ -7,9 +7,10 @@
#include <sstream>
#include <vector>
+#include "cmsys/Process.h"
+
#include "cmCTest.h"
#include "cmSystemTools.h"
-#include "cmUVProcessChain.h"
#include "cmValue.h"
#include "cmXMLWriter.h"
@@ -54,12 +55,18 @@ bool cmCTestVC::InitialCheckout(const std::string& command)
// Construct the initial checkout command line.
std::vector<std::string> args = cmSystemTools::ParseArguments(command);
+ std::vector<char const*> vc_co;
+ vc_co.reserve(args.size() + 1);
+ for (std::string const& arg : args) {
+ vc_co.push_back(arg.c_str());
+ }
+ vc_co.push_back(nullptr);
// Run the initial checkout command and log its output.
this->Log << "--- Begin Initial Checkout ---\n";
OutputLogger out(this->Log, "co-out> ");
OutputLogger err(this->Log, "co-err> ");
- bool result = this->RunChild(args, &out, &err, parent);
+ bool result = this->RunChild(vc_co.data(), &out, &err, parent.c_str());
this->Log << "--- End Initial Checkout ---\n";
if (!result) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
@@ -68,35 +75,35 @@ bool cmCTestVC::InitialCheckout(const std::string& command)
return result;
}
-bool cmCTestVC::RunChild(const std::vector<std::string>& cmd,
- OutputParser* out, OutputParser* err,
- std::string workDir, Encoding encoding)
+bool cmCTestVC::RunChild(char const* const* cmd, OutputParser* out,
+ OutputParser* err, const char* workDir,
+ Encoding encoding)
{
this->Log << cmCTestVC::ComputeCommandLine(cmd) << "\n";
- cmUVProcessChainBuilder builder;
- if (workDir.empty()) {
- workDir = this->SourceDirectory;
- }
- builder.AddCommand(cmd).SetWorkingDirectory(workDir);
- auto status = cmCTestVC::RunProcess(builder, out, err, encoding);
- return status.front().SpawnResult == 0 && status.front().ExitStatus == 0;
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, cmd);
+ workDir = workDir ? workDir : this->SourceDirectory.c_str();
+ cmsysProcess_SetWorkingDirectory(cp, workDir);
+ cmCTestVC::RunProcess(cp, out, err, encoding);
+ int result = cmsysProcess_GetExitValue(cp);
+ cmsysProcess_Delete(cp);
+ return result == 0;
}
-std::string cmCTestVC::ComputeCommandLine(const std::vector<std::string>& cmd)
+std::string cmCTestVC::ComputeCommandLine(char const* const* cmd)
{
std::ostringstream line;
const char* sep = "";
- for (auto const& arg : cmd) {
- line << sep << "\"" << arg << "\"";
+ for (const char* const* arg = cmd; *arg; ++arg) {
+ line << sep << "\"" << *arg << "\"";
sep = " ";
}
return line.str();
}
-bool cmCTestVC::RunUpdateCommand(const std::vector<std::string>& cmd,
- OutputParser* out, OutputParser* err,
- Encoding encoding)
+bool cmCTestVC::RunUpdateCommand(char const* const* cmd, OutputParser* out,
+ OutputParser* err, Encoding encoding)
{
// Report the command line.
this->UpdateCommandLine = this->ComputeCommandLine(cmd);
@@ -106,7 +113,7 @@ bool cmCTestVC::RunUpdateCommand(const std::vector<std::string>& cmd,
}
// Run the command.
- return this->RunChild(cmd, out, err, "", encoding);
+ return this->RunChild(cmd, out, err, nullptr, encoding);
}
std::string cmCTestVC::GetNightlyTime()
diff --git a/Source/CTest/cmCTestVC.h b/Source/CTest/cmCTestVC.h
index dd5456d..7b03d10 100644
--- a/Source/CTest/cmCTestVC.h
+++ b/Source/CTest/cmCTestVC.h
@@ -6,7 +6,6 @@
#include <iosfwd>
#include <string>
-#include <vector>
#include "cmProcessOutput.h"
#include "cmProcessTools.h"
@@ -109,15 +108,15 @@ protected:
};
/** Convert a list of arguments to a human-readable command line. */
- static std::string ComputeCommandLine(const std::vector<std::string>& cmd);
+ static std::string ComputeCommandLine(char const* const* cmd);
/** Run a command line and send output to given parsers. */
- bool RunChild(const std::vector<std::string>& cmd, OutputParser* out,
- OutputParser* err, std::string workDir = {},
+ bool RunChild(char const* const* cmd, OutputParser* out, OutputParser* err,
+ const char* workDir = nullptr,
Encoding encoding = cmProcessOutput::Auto);
/** Run VC update command line and send output to given parsers. */
- bool RunUpdateCommand(const std::vector<std::string>& cmd, OutputParser* out,
+ bool RunUpdateCommand(char const* const* cmd, OutputParser* out,
OutputParser* err = nullptr,
Encoding encoding = cmProcessOutput::Auto);
diff --git a/Source/LexerParser/cmCTestResourceGroupsLexer.cxx b/Source/LexerParser/cmCTestResourceGroupsLexer.cxx
index f1d351a..85b379b 100644
--- a/Source/LexerParser/cmCTestResourceGroupsLexer.cxx
+++ b/Source/LexerParser/cmCTestResourceGroupsLexer.cxx
@@ -667,10 +667,6 @@ Modify cmCTestResourceGroupsLexer.cxx:
#include <cstddef>
-#ifndef _WIN32
-# include <termios.h>
-#endif
-
/*--------------------------------------------------------------------------*/
#define INITIAL 0
diff --git a/Source/LexerParser/cmCTestResourceGroupsLexer.in.l b/Source/LexerParser/cmCTestResourceGroupsLexer.in.l
index ac9cbaf..2befa85 100644
--- a/Source/LexerParser/cmCTestResourceGroupsLexer.in.l
+++ b/Source/LexerParser/cmCTestResourceGroupsLexer.in.l
@@ -26,10 +26,6 @@ Modify cmCTestResourceGroupsLexer.cxx:
#include <cstddef>
-#ifndef _WIN32
-# include <termios.h>
-#endif
-
/*--------------------------------------------------------------------------*/
%}
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 6e684a3..988a4eb 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -5,7 +5,6 @@
#include <algorithm>
#include <cctype>
#include <chrono>
-#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
@@ -25,13 +24,13 @@
#include <cmext/string_view>
#include <cm3p/curl/curl.h>
-#include <cm3p/uv.h>
#include <cm3p/zlib.h>
#include "cmsys/Base64.h"
#include "cmsys/Directory.hxx"
#include "cmsys/FStream.hxx"
#include "cmsys/Glob.hxx"
+#include "cmsys/Process.h"
#include "cmsys/RegularExpression.hxx"
#include "cmsys/SystemInformation.hxx"
#if defined(_WIN32)
@@ -65,9 +64,6 @@
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
-#include "cmUVHandlePtr.h"
-#include "cmUVProcessChain.h"
-#include "cmUVStream.h"
#include "cmValue.h"
#include "cmVersion.h"
#include "cmVersionConfig.h"
@@ -1077,9 +1073,9 @@ int cmCTest::GetTestModelFromString(const std::string& str)
// ######################################################################
// ######################################################################
-bool cmCTest::RunMakeCommand(const std::string& command, std::string& output,
- int* retVal, const char* dir, cmDuration timeout,
- std::ostream& ofs, Encoding encoding)
+int cmCTest::RunMakeCommand(const std::string& command, std::string& output,
+ int* retVal, const char* dir, cmDuration timeout,
+ std::ostream& ofs, Encoding encoding)
{
// First generate the command and arguments
std::vector<std::string> args = cmSystemTools::ParseArguments(command);
@@ -1088,107 +1084,107 @@ bool cmCTest::RunMakeCommand(const std::string& command, std::string& output,
return false;
}
+ std::vector<const char*> argv;
+ argv.reserve(args.size() + 1);
+ for (std::string const& a : args) {
+ argv.push_back(a.c_str());
+ }
+ argv.push_back(nullptr);
+
output.clear();
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Run command:");
- for (auto const& arg : args) {
+ for (char const* arg : argv) {
+ if (!arg) {
+ break;
+ }
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, " \"" << arg << "\"");
}
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, std::endl);
// Now create process object
- cmUVProcessChainBuilder builder;
- builder.AddCommand(args).SetMergedBuiltinStreams();
- if (dir) {
- builder.SetWorkingDirectory(dir);
- }
- auto chain = builder.Start();
- cm::uv_pipe_ptr outputStream;
- outputStream.init(chain.GetLoop(), 0);
- uv_pipe_open(outputStream, chain.OutputStream());
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, argv.data());
+ cmsysProcess_SetWorkingDirectory(cp, dir);
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ cmsysProcess_SetTimeout(cp, timeout.count());
+ cmsysProcess_Execute(cp);
// Initialize tick's
std::string::size_type tick = 0;
std::string::size_type tick_len = 1024;
std::string::size_type tick_line_len = 50;
+ char* data;
+ int length;
cmProcessOutput processOutput(encoding);
+ std::string strdata;
cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
" Each . represents " << tick_len
<< " bytes of output\n"
" "
<< std::flush);
- auto outputHandle = cmUVStreamRead(
- outputStream,
- [this, &processOutput, &output, &tick, &tick_len, &tick_line_len,
- &ofs](std::vector<char> data) {
- std::string strdata;
- processOutput.DecodeText(data.data(), data.size(), strdata);
- for (char& cc : strdata) {
- if (cc == 0) {
- cc = '\n';
- }
+ while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
+ processOutput.DecodeText(data, length, strdata);
+ for (char& cc : strdata) {
+ if (cc == 0) {
+ cc = '\n';
}
- output.append(strdata);
- while (output.size() > (tick * tick_len)) {
- tick++;
- cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, "." << std::flush);
- if (tick % tick_line_len == 0 && tick > 0) {
- cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
- " Size: " << int((double(output.size()) / 1024.0) + 1)
- << "K\n " << std::flush);
- }
- }
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
- cmCTestLogWrite(strdata.c_str(), strdata.size()));
- if (ofs) {
- ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
- }
- },
- [this, &processOutput, &output, &ofs]() {
- std::string strdata;
- processOutput.DecodeText(std::string(), strdata);
- if (!strdata.empty()) {
- output.append(strdata);
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
- cmCTestLogWrite(strdata.c_str(), strdata.size()));
- if (ofs) {
- ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
- }
+ }
+ output.append(strdata);
+ while (output.size() > (tick * tick_len)) {
+ tick++;
+ cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, "." << std::flush);
+ if (tick % tick_line_len == 0 && tick > 0) {
+ cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
+ " Size: " << int((double(output.size()) / 1024.0) + 1)
+ << "K\n " << std::flush);
}
- });
-
- bool finished = chain.Wait(static_cast<uint64_t>(timeout.count() * 1000.0));
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ cmCTestLogWrite(strdata.c_str(), strdata.size()));
+ if (ofs) {
+ ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
+ }
+ }
+ processOutput.DecodeText(std::string(), strdata);
+ if (!strdata.empty()) {
+ output.append(strdata);
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ cmCTestLogWrite(strdata.c_str(), strdata.size()));
+ if (ofs) {
+ ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
+ }
+ }
cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
" Size of output: " << int(double(output.size()) / 1024.0) << "K"
<< std::endl);
- if (finished) {
- auto const& status = chain.GetStatus(0);
- auto exception = status.GetException();
- switch (exception.first) {
- case cmUVProcessChain::ExceptionCode::None:
- *retVal = static_cast<int>(status.ExitStatus);
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
- "Command exited with the value: " << *retVal << std::endl);
- break;
- case cmUVProcessChain::ExceptionCode::Spawn:
- output += "\n*** ERROR executing: ";
- output += exception.second;
- output += "\n***The build process failed.";
- cmCTestLog(this, ERROR_MESSAGE,
- "There was an error: " << exception.second << std::endl);
- break;
- default:
- *retVal = static_cast<int>(exception.first);
- cmCTestLog(this, WARNING,
- "There was an exception: " << *retVal << std::endl);
- break;
- }
- } else {
+ cmsysProcess_WaitForExit(cp, nullptr);
+
+ int result = cmsysProcess_GetState(cp);
+
+ if (result == cmsysProcess_State_Exited) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ "Command exited with the value: " << *retVal << std::endl);
+ } else if (result == cmsysProcess_State_Exception) {
+ *retVal = cmsysProcess_GetExitException(cp);
+ cmCTestLog(this, WARNING,
+ "There was an exception: " << *retVal << std::endl);
+ } else if (result == cmsysProcess_State_Expired) {
cmCTestLog(this, WARNING, "There was a timeout" << std::endl);
+ } else if (result == cmsysProcess_State_Error) {
+ output += "\n*** ERROR executing: ";
+ output += cmsysProcess_GetErrorString(cp);
+ output += "\n***The build process failed.";
+ cmCTestLog(this, ERROR_MESSAGE,
+ "There was an error: " << cmsysProcess_GetErrorString(cp)
+ << std::endl);
}
- return true;
+ cmsysProcess_Delete(cp);
+
+ return result;
}
// ######################################################################
@@ -1196,10 +1192,9 @@ bool cmCTest::RunMakeCommand(const std::string& command, std::string& output,
// ######################################################################
// ######################################################################
-bool cmCTest::RunTest(const std::vector<std::string>& argv,
- std::string* output, int* retVal, std::ostream* log,
- cmDuration testTimeOut,
- std::vector<std::string>* environment, Encoding encoding)
+int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
+ int* retVal, std::ostream* log, cmDuration testTimeOut,
+ std::vector<std::string>* environment, Encoding encoding)
{
bool modifyEnv = (environment && !environment->empty());
@@ -1238,16 +1233,19 @@ bool cmCTest::RunTest(const std::vector<std::string>& argv,
inst.SetStreams(&oss, &oss);
std::vector<std::string> args;
- for (auto const& i : argv) {
- // make sure we pass the timeout in for any build and test
- // invocations. Since --build-generator is required this is a
- // good place to check for it, and to add the arguments in
- if (i == "--build-generator" && timeout != cmCTest::MaxDuration() &&
- timeout > cmDuration::zero()) {
- args.emplace_back("--test-timeout");
- args.push_back(std::to_string(cmDurationTo<unsigned int>(timeout)));
+ for (char const* i : argv) {
+ if (i) {
+ // make sure we pass the timeout in for any build and test
+ // invocations. Since --build-generator is required this is a
+ // good place to check for it, and to add the arguments in
+ if (strcmp(i, "--build-generator") == 0 &&
+ timeout != cmCTest::MaxDuration() &&
+ timeout > cmDuration::zero()) {
+ args.emplace_back("--test-timeout");
+ args.push_back(std::to_string(cmDurationTo<unsigned int>(timeout)));
+ }
+ args.emplace_back(i);
}
- args.emplace_back(i);
}
if (log) {
*log << "* Run internal CTest" << std::endl;
@@ -1273,7 +1271,7 @@ bool cmCTest::RunTest(const std::vector<std::string>& argv,
<< std::endl);
}
- return true;
+ return cmsysProcess_State_Exited;
}
std::vector<char> tempOutput;
if (output) {
@@ -1286,43 +1284,41 @@ bool cmCTest::RunTest(const std::vector<std::string>& argv,
cmSystemTools::AppendEnv(*environment);
}
- cmUVProcessChainBuilder builder;
- builder.AddCommand(argv).SetMergedBuiltinStreams();
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, argv.data());
cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
- auto chain = builder.Start();
+ if (cmSystemTools::GetRunCommandHideConsole()) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ }
+ cmsysProcess_SetTimeout(cp, timeout.count());
+ cmsysProcess_Execute(cp);
+
+ char* data;
+ int length;
cmProcessOutput processOutput(encoding);
- cm::uv_pipe_ptr outputStream;
- outputStream.init(chain.GetLoop(), 0);
- uv_pipe_open(outputStream, chain.OutputStream());
- auto outputHandle = cmUVStreamRead(
- outputStream,
- [this, &processOutput, &output, &tempOutput,
- &log](std::vector<char> data) {
- std::string strdata;
- processOutput.DecodeText(data.data(), data.size(), strdata);
- if (output) {
- cm::append(tempOutput, data.data(), data.data() + data.size());
- }
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
- cmCTestLogWrite(strdata.c_str(), strdata.size()));
- if (log) {
- log->write(strdata.c_str(), strdata.size());
- }
- },
- [this, &processOutput, &log]() {
- std::string strdata;
- processOutput.DecodeText(std::string(), strdata);
- if (!strdata.empty()) {
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
- cmCTestLogWrite(strdata.c_str(), strdata.size()));
- if (log) {
- log->write(strdata.c_str(), strdata.size());
- }
- }
- });
+ std::string strdata;
+ while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
+ processOutput.DecodeText(data, length, strdata);
+ if (output) {
+ cm::append(tempOutput, data, data + length);
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ cmCTestLogWrite(strdata.c_str(), strdata.size()));
+ if (log) {
+ log->write(strdata.c_str(), strdata.size());
+ }
+ }
+ processOutput.DecodeText(std::string(), strdata);
+ if (!strdata.empty()) {
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ cmCTestLogWrite(strdata.c_str(), strdata.size()));
+ if (log) {
+ log->write(strdata.c_str(), strdata.size());
+ }
+ }
- bool complete = chain.Wait(static_cast<uint64_t>(timeout.count() * 1000.0));
+ cmsysProcess_WaitForExit(cp, nullptr);
processOutput.DecodeText(tempOutput, tempOutput);
if (output && tempOutput.begin() != tempOutput.end()) {
output->append(tempOutput.data(), tempOutput.size());
@@ -1330,41 +1326,33 @@ bool cmCTest::RunTest(const std::vector<std::string>& argv,
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
"-- Process completed" << std::endl);
- bool result = false;
+ int result = cmsysProcess_GetState(cp);
- if (complete) {
- auto const& status = chain.GetStatus(0);
- auto exception = status.GetException();
- switch (exception.first) {
- case cmUVProcessChain::ExceptionCode::None:
- *retVal = static_cast<int>(status.ExitStatus);
- if (*retVal != 0 && this->Impl->OutputTestOutputOnTestFailure) {
- this->OutputTestErrors(tempOutput);
- }
- result = true;
- break;
- case cmUVProcessChain::ExceptionCode::Spawn: {
- std::string outerr =
- cmStrCat("\n*** ERROR executing: ", exception.second);
- if (output) {
- *output += outerr;
- }
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl);
- } break;
- default: {
- if (this->Impl->OutputTestOutputOnTestFailure) {
- this->OutputTestErrors(tempOutput);
- }
- *retVal = status.TermSignal;
- std::string outerr =
- cmStrCat("\n*** Exception executing: ", exception.second);
- if (output) {
- *output += outerr;
- }
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl);
- } break;
+ if (result == cmsysProcess_State_Exited) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ if (*retVal != 0 && this->Impl->OutputTestOutputOnTestFailure) {
+ this->OutputTestErrors(tempOutput);
+ }
+ } else if (result == cmsysProcess_State_Exception) {
+ if (this->Impl->OutputTestOutputOnTestFailure) {
+ this->OutputTestErrors(tempOutput);
+ }
+ *retVal = cmsysProcess_GetExitException(cp);
+ std::string outerr = cmStrCat("\n*** Exception executing: ",
+ cmsysProcess_GetExceptionString(cp));
+ if (output) {
+ *output += outerr;
+ }
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl);
+ } else if (result == cmsysProcess_State_Error) {
+ std::string outerr =
+ cmStrCat("\n*** ERROR executing: ", cmsysProcess_GetErrorString(cp));
+ if (output) {
+ *output += outerr;
}
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl);
}
+ cmsysProcess_Delete(cp);
return result;
}
@@ -3482,70 +3470,49 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
stdOut->clear();
stdErr->clear();
- cmUVProcessChainBuilder builder;
- builder.AddCommand(args)
- .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
- .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
- if (dir) {
- builder.SetWorkingDirectory(dir);
- }
- auto chain = builder.Start();
-
- cm::uv_timer_ptr timer;
- bool timedOut = false;
- if (timeout.count()) {
- timer.init(chain.GetLoop(), &timedOut);
- timer.start(
- [](uv_timer_t* t) {
- auto* timedOutPtr = static_cast<bool*>(t->data);
- *timedOutPtr = true;
- },
- static_cast<uint64_t>(timeout.count() * 1000.0), 0);
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, argv.data());
+ cmsysProcess_SetWorkingDirectory(cp, dir);
+ if (cmSystemTools::GetRunCommandHideConsole()) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
}
+ cmsysProcess_SetTimeout(cp, timeout.count());
+ cmsysProcess_Execute(cp);
std::vector<char> tempOutput;
- bool outFinished = false;
- cm::uv_pipe_ptr outStream;
std::vector<char> tempError;
- bool errFinished = false;
- cm::uv_pipe_ptr errStream;
+ char* data;
+ int length;
cmProcessOutput processOutput(encoding);
- auto startRead = [this, &chain, &processOutput](
- cm::uv_pipe_ptr& pipe, int stream,
- std::vector<char>& temp,
- bool& finished) -> std::unique_ptr<cmUVStreamReadHandle> {
- pipe.init(chain.GetLoop(), 0);
- uv_pipe_open(pipe, stream);
- return cmUVStreamRead(
- pipe,
- [this, &temp, &processOutput](std::vector<char> data) {
- cm::append(temp, data);
- if (this->Impl->ExtraVerbose) {
- std::string strdata;
- processOutput.DecodeText(data.data(), data.size(), strdata);
- cmSystemTools::Stdout(strdata);
- }
- },
- [&finished]() { finished = true; });
- };
- auto outputHandle =
- startRead(outStream, chain.OutputStream(), tempOutput, outFinished);
- auto errorHandle =
- startRead(errStream, chain.ErrorStream(), tempError, errFinished);
- while (!timedOut && !(outFinished && errFinished)) {
- uv_run(&chain.GetLoop(), UV_RUN_ONCE);
+ std::string strdata;
+ int res;
+ bool done = false;
+ while (!done) {
+ res = cmsysProcess_WaitForData(cp, &data, &length, nullptr);
+ switch (res) {
+ case cmsysProcess_Pipe_STDOUT:
+ cm::append(tempOutput, data, data + length);
+ break;
+ case cmsysProcess_Pipe_STDERR:
+ cm::append(tempError, data, data + length);
+ break;
+ default:
+ done = true;
+ }
+ if ((res == cmsysProcess_Pipe_STDOUT || res == cmsysProcess_Pipe_STDERR) &&
+ this->Impl->ExtraVerbose) {
+ processOutput.DecodeText(data, length, strdata);
+ cmSystemTools::Stdout(strdata);
+ }
}
if (this->Impl->ExtraVerbose) {
- std::string strdata;
processOutput.DecodeText(std::string(), strdata);
if (!strdata.empty()) {
cmSystemTools::Stdout(strdata);
}
}
- while (!timedOut && !chain.Finished()) {
- uv_run(&chain.GetLoop(), UV_RUN_ONCE);
- }
+ cmsysProcess_WaitForExit(cp, nullptr);
if (!tempOutput.empty()) {
processOutput.DecodeText(tempOutput, tempOutput);
stdOut->append(tempOutput.data(), tempOutput.size());
@@ -3556,32 +3523,32 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
}
bool result = true;
- if (timedOut) {
+ if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
+ if (retVal) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ } else {
+ if (cmsysProcess_GetExitValue(cp) != 0) {
+ result = false;
+ }
+ }
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) {
+ const char* exception_str = cmsysProcess_GetExceptionString(cp);
+ cmCTestLog(this, ERROR_MESSAGE, exception_str << std::endl);
+ stdErr->append(exception_str, strlen(exception_str));
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
+ const char* error_str = cmsysProcess_GetErrorString(cp);
+ cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
+ stdErr->append(error_str, strlen(error_str));
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) {
const char* error_str = "Process terminated due to timeout\n";
cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
stdErr->append(error_str, strlen(error_str));
result = false;
- } else {
- auto const& status = chain.GetStatus(0);
- auto exception = status.GetException();
- switch (exception.first) {
- case cmUVProcessChain::ExceptionCode::None:
- if (retVal) {
- *retVal = static_cast<int>(status.ExitStatus);
- } else {
- if (status.ExitStatus != 0) {
- result = false;
- }
- }
- break;
- default: {
- cmCTestLog(this, ERROR_MESSAGE, exception.second << std::endl);
- stdErr->append(exception.second);
- result = false;
- } break;
- }
}
+ cmsysProcess_Delete(cp);
return result;
}
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 1644d84..9a8d5a6 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -254,10 +254,10 @@ public:
* Run command specialized for make and configure. Returns process status
* and retVal is return value or exception.
*/
- bool RunMakeCommand(const std::string& command, std::string& output,
- int* retVal, const char* dir, cmDuration timeout,
- std::ostream& ofs,
- Encoding encoding = cmProcessOutput::Auto);
+ int RunMakeCommand(const std::string& command, std::string& output,
+ int* retVal, const char* dir, cmDuration timeout,
+ std::ostream& ofs,
+ Encoding encoding = cmProcessOutput::Auto);
/** Return the current tag */
std::string GetCurrentTag();
@@ -303,10 +303,10 @@ public:
* environment variables prior to running the test. After running the test,
* environment variables are restored to their previous values.
*/
- bool RunTest(const std::vector<std::string>& args, std::string* output,
- int* retVal, std::ostream* logfile, cmDuration testTimeOut,
- std::vector<std::string>* environment,
- Encoding encoding = cmProcessOutput::Auto);
+ int RunTest(std::vector<const char*> args, std::string* output, int* retVal,
+ std::ostream* logfile, cmDuration testTimeOut,
+ std::vector<std::string>* environment,
+ Encoding encoding = cmProcessOutput::Auto);
/**
* Get the handler object
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index 26b9424..3efd3bd 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -2,8 +2,8 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmExecuteProcessCommand.h"
+#include <algorithm>
#include <cctype> /* isspace */
-#include <cstdint>
#include <cstdio>
#include <iostream>
#include <map>
@@ -16,7 +16,7 @@
#include <cmext/algorithm>
#include <cmext/string_view>
-#include <cm3p/uv.h>
+#include "cmsys/Process.h"
#include "cmArgumentParser.h"
#include "cmExecutionStatus.h"
@@ -26,9 +26,6 @@
#include "cmProcessOutput.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
-#include "cmUVHandlePtr.h"
-#include "cmUVProcessChain.h"
-#include "cmUVStream.h"
namespace {
bool cmExecuteProcessCommandIsWhitespace(char c)
@@ -39,7 +36,7 @@ bool cmExecuteProcessCommandIsWhitespace(char c)
void cmExecuteProcessCommandFixText(std::vector<char>& output,
bool strip_trailing_whitespace);
void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data,
- std::size_t length);
+ int length);
}
// cmExecuteProcessCommand
@@ -164,68 +161,57 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
}
}
// Create a process instance.
- cmUVProcessChainBuilder builder;
+ std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp_ptr(
+ cmsysProcess_New(), cmsysProcess_Delete);
+ cmsysProcess* cp = cp_ptr.get();
// Set the command sequence.
for (std::vector<std::string> const& cmd : arguments.Commands) {
- builder.AddCommand(cmd);
+ std::vector<const char*> argv(cmd.size() + 1);
+ std::transform(cmd.begin(), cmd.end(), argv.begin(),
+ [](std::string const& s) { return s.c_str(); });
+ argv.back() = nullptr;
+ cmsysProcess_AddCommand(cp, argv.data());
}
// Set the process working directory.
if (!arguments.WorkingDirectory.empty()) {
- builder.SetWorkingDirectory(arguments.WorkingDirectory);
+ cmsysProcess_SetWorkingDirectory(cp, arguments.WorkingDirectory.c_str());
}
- // Check the output variables.
- std::unique_ptr<FILE, int (*)(FILE*)> inputFile(nullptr, fclose);
- if (!inputFilename.empty()) {
- inputFile.reset(cmsys::SystemTools::Fopen(inputFilename, "rb"));
- if (inputFile) {
- builder.SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT,
- inputFile.get());
- }
- } else {
- builder.SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT, stdin);
- }
+ // Always hide the process window.
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
- std::unique_ptr<FILE, int (*)(FILE*)> outputFile(nullptr, fclose);
- if (!outputFilename.empty()) {
- outputFile.reset(cmsys::SystemTools::Fopen(outputFilename, "wb"));
- if (outputFile) {
- builder.SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT,
- outputFile.get());
- }
- } else {
- if (arguments.OutputVariable == arguments.ErrorVariable &&
- !arguments.ErrorVariable.empty()) {
- builder.SetMergedBuiltinStreams();
+ // Check the output variables.
+ bool merge_output = false;
+ if (!arguments.InputFile.empty()) {
+ cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN,
+ arguments.InputFile.c_str());
+ }
+ if (!arguments.OutputFile.empty()) {
+ cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDOUT,
+ arguments.OutputFile.c_str());
+ }
+ if (!arguments.ErrorFile.empty()) {
+ if (arguments.ErrorFile == arguments.OutputFile) {
+ merge_output = true;
} else {
- builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
+ cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR,
+ arguments.ErrorFile.c_str());
}
}
-
- std::unique_ptr<FILE, int (*)(FILE*)> errorFile(nullptr, fclose);
- if (!errorFilename.empty()) {
- if (errorFilename == outputFilename) {
- if (outputFile) {
- builder.SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
- outputFile.get());
- }
- } else {
- errorFile.reset(cmsys::SystemTools::Fopen(errorFilename, "wb"));
- if (errorFile) {
- builder.SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
- errorFile.get());
- }
- }
- } else if (arguments.ErrorVariable.empty() ||
- (!arguments.ErrorVariable.empty() &&
- arguments.OutputVariable != arguments.ErrorVariable)) {
- builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
+ if (!arguments.OutputVariable.empty() &&
+ arguments.OutputVariable == arguments.ErrorVariable) {
+ merge_output = true;
+ }
+ if (merge_output) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_MergeOutput, 1);
}
// Set the timeout if any.
- int64_t timeoutMillis = static_cast<int64_t>(timeout * 1000.0);
+ if (timeout >= 0) {
+ cmsysProcess_SetTimeout(cp, timeout);
+ }
bool echo_stdout = false;
bool echo_stderr = false;
@@ -273,86 +259,36 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
}
}
// Start the process.
- auto chain = builder.Start();
-
- bool timedOut = false;
- cm::uv_timer_ptr timer;
-
- if (timeoutMillis >= 0) {
- timer.init(chain.GetLoop(), &timedOut);
- timer.start(
- [](uv_timer_t* handle) {
- auto* timeoutPtr = static_cast<bool*>(handle->data);
- *timeoutPtr = true;
- },
- timeoutMillis, 0);
- }
+ cmsysProcess_Execute(cp);
// Read the process output.
- struct ReadData
- {
- bool Finished = false;
- std::vector<char> Output;
- cm::uv_pipe_ptr Stream;
- };
- ReadData outputData;
- ReadData errorData;
+ std::vector<char> tempOutput;
+ std::vector<char> tempError;
+ int length;
+ char* data;
+ int p;
cmProcessOutput processOutput(
cmProcessOutput::FindEncoding(arguments.Encoding));
std::string strdata;
-
- std::unique_ptr<cmUVStreamReadHandle> outputHandle;
- if (chain.OutputStream() >= 0) {
- outputData.Stream.init(chain.GetLoop(), 0);
- uv_pipe_open(outputData.Stream, chain.OutputStream());
- outputHandle = cmUVStreamRead(
- outputData.Stream,
- [&arguments, &processOutput, &outputData,
- &strdata](std::vector<char> data) {
- if (!arguments.OutputQuiet) {
- if (arguments.OutputVariable.empty() ||
- arguments.EchoOutputVariable) {
- processOutput.DecodeText(data.data(), data.size(), strdata, 1);
- cmSystemTools::Stdout(strdata);
- }
- if (!arguments.OutputVariable.empty()) {
- cmExecuteProcessCommandAppend(outputData.Output, data.data(),
- data.size());
- }
- }
- },
- [&outputData]() { outputData.Finished = true; });
- } else {
- outputData.Finished = true;
- }
- std::unique_ptr<cmUVStreamReadHandle> errorHandle;
- if (chain.ErrorStream() >= 0 &&
- chain.ErrorStream() != chain.OutputStream()) {
- errorData.Stream.init(chain.GetLoop(), 0);
- uv_pipe_open(errorData.Stream, chain.ErrorStream());
- errorHandle = cmUVStreamRead(
- errorData.Stream,
- [&arguments, &processOutput, &errorData,
- &strdata](std::vector<char> data) {
- if (!arguments.ErrorQuiet) {
- if (arguments.ErrorVariable.empty() || arguments.EchoErrorVariable) {
- processOutput.DecodeText(data.data(), data.size(), strdata, 2);
- cmSystemTools::Stderr(strdata);
- }
- if (!arguments.ErrorVariable.empty()) {
- cmExecuteProcessCommandAppend(errorData.Output, data.data(),
- data.size());
- }
- }
- },
- [&errorData]() { errorData.Finished = true; });
- } else {
- errorData.Finished = true;
- }
-
- while (chain.Valid() && !timedOut &&
- !(chain.Finished() && outputData.Finished && errorData.Finished)) {
- uv_run(&chain.GetLoop(), UV_RUN_ONCE);
+ while ((p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) {
+ // Put the output in the right place.
+ if (p == cmsysProcess_Pipe_STDOUT && !arguments.OutputQuiet) {
+ if (arguments.OutputVariable.empty() || arguments.EchoOutputVariable) {
+ processOutput.DecodeText(data, length, strdata, 1);
+ cmSystemTools::Stdout(strdata);
+ }
+ if (!arguments.OutputVariable.empty()) {
+ cmExecuteProcessCommandAppend(tempOutput, data, length);
+ }
+ } else if (p == cmsysProcess_Pipe_STDERR && !arguments.ErrorQuiet) {
+ if (arguments.ErrorVariable.empty() || arguments.EchoErrorVariable) {
+ processOutput.DecodeText(data, length, strdata, 2);
+ cmSystemTools::Stderr(strdata);
+ }
+ if (!arguments.ErrorVariable.empty()) {
+ cmExecuteProcessCommandAppend(tempError, data, length);
+ }
+ }
}
if (!arguments.OutputQuiet &&
(arguments.OutputVariable.empty() || arguments.EchoOutputVariable)) {
@@ -369,102 +305,151 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
}
}
- // All output has been read.
- processOutput.DecodeText(outputData.Output, outputData.Output);
- processOutput.DecodeText(errorData.Output, errorData.Output);
+ // All output has been read. Wait for the process to exit.
+ cmsysProcess_WaitForExit(cp, nullptr);
+ processOutput.DecodeText(tempOutput, tempOutput);
+ processOutput.DecodeText(tempError, tempError);
// Fix the text in the output strings.
- cmExecuteProcessCommandFixText(outputData.Output,
+ cmExecuteProcessCommandFixText(tempOutput,
arguments.OutputStripTrailingWhitespace);
- cmExecuteProcessCommandFixText(errorData.Output,
+ cmExecuteProcessCommandFixText(tempError,
arguments.ErrorStripTrailingWhitespace);
// Store the output obtained.
- if (!arguments.OutputVariable.empty() && !outputData.Output.empty()) {
+ if (!arguments.OutputVariable.empty() && !tempOutput.empty()) {
status.GetMakefile().AddDefinition(arguments.OutputVariable,
- outputData.Output.data());
+ tempOutput.data());
}
- if (arguments.ErrorVariable != arguments.OutputVariable &&
- !arguments.ErrorVariable.empty() && !errorData.Output.empty()) {
+ if (!merge_output && !arguments.ErrorVariable.empty() &&
+ !tempError.empty()) {
status.GetMakefile().AddDefinition(arguments.ErrorVariable,
- errorData.Output.data());
+ tempError.data());
}
// Store the result of running the process.
if (!arguments.ResultVariable.empty()) {
- if (timedOut) {
- status.GetMakefile().AddDefinition(arguments.ResultVariable,
- "Process terminated due to timeout");
- } else {
- auto const* lastStatus = chain.GetStatus().back();
- auto exception = lastStatus->GetException();
- if (exception.first == cmUVProcessChain::ExceptionCode::None) {
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Exited: {
+ int v = cmsysProcess_GetExitValue(cp);
+ char buf[16];
+ snprintf(buf, sizeof(buf), "%d", v);
+ status.GetMakefile().AddDefinition(arguments.ResultVariable, buf);
+ } break;
+ case cmsysProcess_State_Exception:
status.GetMakefile().AddDefinition(
- arguments.ResultVariable,
- std::to_string(static_cast<int>(lastStatus->ExitStatus)));
- } else {
+ arguments.ResultVariable, cmsysProcess_GetExceptionString(cp));
+ break;
+ case cmsysProcess_State_Error:
status.GetMakefile().AddDefinition(arguments.ResultVariable,
- exception.second);
- }
+ cmsysProcess_GetErrorString(cp));
+ break;
+ case cmsysProcess_State_Expired:
+ status.GetMakefile().AddDefinition(
+ arguments.ResultVariable, "Process terminated due to timeout");
+ break;
}
}
// Store the result of running the processes.
if (!arguments.ResultsVariable.empty()) {
- if (timedOut) {
- status.GetMakefile().AddDefinition(arguments.ResultsVariable,
- "Process terminated due to timeout");
- } else {
- std::vector<std::string> res;
- for (auto const* processStatus : chain.GetStatus()) {
- auto exception = processStatus->GetException();
- if (exception.first == cmUVProcessChain::ExceptionCode::None) {
- res.emplace_back(
- std::to_string(static_cast<int>(processStatus->ExitStatus)));
- } else {
- res.emplace_back(exception.second);
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Exited: {
+ std::vector<std::string> res;
+ for (size_t i = 0; i < arguments.Commands.size(); ++i) {
+ switch (cmsysProcess_GetStateByIndex(cp, static_cast<int>(i))) {
+ case kwsysProcess_StateByIndex_Exited: {
+ int exitCode =
+ cmsysProcess_GetExitValueByIndex(cp, static_cast<int>(i));
+ char buf[16];
+ snprintf(buf, sizeof(buf), "%d", exitCode);
+ res.emplace_back(buf);
+ } break;
+ case kwsysProcess_StateByIndex_Exception:
+ res.emplace_back(cmsysProcess_GetExceptionStringByIndex(
+ cp, static_cast<int>(i)));
+ break;
+ case kwsysProcess_StateByIndex_Error:
+ default:
+ res.emplace_back("Error getting the child return code");
+ break;
+ }
}
- }
- status.GetMakefile().AddDefinition(arguments.ResultsVariable,
- cmList::to_string(res));
+ status.GetMakefile().AddDefinition(arguments.ResultsVariable,
+ cmList::to_string(res));
+ } break;
+ case cmsysProcess_State_Exception:
+ status.GetMakefile().AddDefinition(
+ arguments.ResultsVariable, cmsysProcess_GetExceptionString(cp));
+ break;
+ case cmsysProcess_State_Error:
+ status.GetMakefile().AddDefinition(arguments.ResultsVariable,
+ cmsysProcess_GetErrorString(cp));
+ break;
+ case cmsysProcess_State_Expired:
+ status.GetMakefile().AddDefinition(
+ arguments.ResultsVariable, "Process terminated due to timeout");
+ break;
}
}
- auto queryProcessStatusByIndex = [&chain](std::size_t index) -> std::string {
- auto const& processStatus = chain.GetStatus(index);
- auto exception = processStatus.GetException();
- if (exception.first == cmUVProcessChain::ExceptionCode::None) {
- if (processStatus.ExitStatus) {
- return cmStrCat("Child return code: ", processStatus.ExitStatus);
+ auto queryProcessStatusByIndex = [&cp](int index) -> std::string {
+ std::string processStatus;
+ switch (cmsysProcess_GetStateByIndex(cp, static_cast<int>(index))) {
+ case kwsysProcess_StateByIndex_Exited: {
+ int exitCode = cmsysProcess_GetExitValueByIndex(cp, index);
+ if (exitCode) {
+ processStatus = "Child return code: " + std::to_string(exitCode);
+ }
+ } break;
+ case kwsysProcess_StateByIndex_Exception: {
+ processStatus = cmStrCat(
+ "Abnormal exit with child return code: ",
+ cmsysProcess_GetExceptionStringByIndex(cp, static_cast<int>(index)));
+ break;
}
- return "";
+ case kwsysProcess_StateByIndex_Error:
+ default:
+ processStatus = "Error getting the child return code";
+ break;
}
- return cmStrCat("Abnormal exit with child return code: ",
- exception.second);
+ return processStatus;
};
if (arguments.CommandErrorIsFatal == "ANY"_s) {
bool ret = true;
- if (timedOut) {
- status.SetError("Process terminated due to timeout");
- ret = false;
- } else {
- std::map<std::size_t, std::string> failureIndices;
- auto statuses = chain.GetStatus();
- for (std::size_t i = 0; i < statuses.size(); ++i) {
- std::string processStatus = queryProcessStatusByIndex(i);
- if (!processStatus.empty()) {
- failureIndices[i] = processStatus;
- }
- }
- if (!failureIndices.empty()) {
- std::ostringstream oss;
- oss << "failed command indexes:\n";
- for (auto const& e : failureIndices) {
- oss << " " << e.first + 1 << ": \"" << e.second << "\"\n";
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Exited: {
+ std::map<int, std::string> failureIndices;
+ for (int i = 0; i < static_cast<int>(arguments.Commands.size()); ++i) {
+ std::string processStatus = queryProcessStatusByIndex(i);
+ if (!processStatus.empty()) {
+ failureIndices[i] = processStatus;
+ }
+ if (!failureIndices.empty()) {
+ std::ostringstream oss;
+ oss << "failed command indexes:\n";
+ for (auto const& e : failureIndices) {
+ oss << " " << e.first + 1 << ": \"" << e.second << "\"\n";
+ }
+ status.SetError(oss.str());
+ ret = false;
+ }
}
- status.SetError(oss.str());
+ } break;
+ case cmsysProcess_State_Exception:
+ status.SetError(
+ cmStrCat("abnormal exit: ", cmsysProcess_GetExceptionString(cp)));
ret = false;
- }
+ break;
+ case cmsysProcess_State_Error:
+ status.SetError(cmStrCat("error getting child return code: ",
+ cmsysProcess_GetErrorString(cp)));
+ ret = false;
+ break;
+ case cmsysProcess_State_Expired:
+ status.SetError("Process terminated due to timeout");
+ ret = false;
+ break;
}
if (!ret) {
@@ -475,23 +460,29 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
if (arguments.CommandErrorIsFatal == "LAST"_s) {
bool ret = true;
- if (timedOut) {
- status.SetError("Process terminated due to timeout");
- ret = false;
- } else {
- auto const& lastStatus = chain.GetStatus(arguments.Commands.size() - 1);
- auto exception = lastStatus.GetException();
- if (exception.first != cmUVProcessChain::ExceptionCode::None) {
- status.SetError(cmStrCat("Abnormal exit: ", exception.second));
- ret = false;
- } else {
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Exited: {
int lastIndex = static_cast<int>(arguments.Commands.size() - 1);
const std::string processStatus = queryProcessStatusByIndex(lastIndex);
if (!processStatus.empty()) {
status.SetError("last command failed");
ret = false;
}
- }
+ } break;
+ case cmsysProcess_State_Exception:
+ status.SetError(
+ cmStrCat("Abnormal exit: ", cmsysProcess_GetExceptionString(cp)));
+ ret = false;
+ break;
+ case cmsysProcess_State_Error:
+ status.SetError(cmStrCat("Error getting child return code: ",
+ cmsysProcess_GetErrorString(cp)));
+ ret = false;
+ break;
+ case cmsysProcess_State_Expired:
+ status.SetError("Process terminated due to timeout");
+ ret = false;
+ break;
}
if (!ret) {
cmSystemTools::SetFatalErrorOccurred();
@@ -534,7 +525,7 @@ void cmExecuteProcessCommandFixText(std::vector<char>& output,
}
void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data,
- std::size_t length)
+ int length)
{
#if defined(__APPLE__)
// HACK on Apple to work around bug with inserting at the
diff --git a/Source/cmProcessTools.cxx b/Source/cmProcessTools.cxx
index 1dd1dce..9e7854b 100644
--- a/Source/cmProcessTools.cxx
+++ b/Source/cmProcessTools.cxx
@@ -2,68 +2,48 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmProcessTools.h"
-#include <algorithm>
-#include <iterator>
#include <ostream>
-#include <cm3p/uv.h>
+#include "cmsys/Process.h"
#include "cmProcessOutput.h"
-#include "cmUVHandlePtr.h"
-#include "cmUVStream.h"
-std::vector<cmUVProcessChain::Status> cmProcessTools::RunProcess(
- cmUVProcessChainBuilder& builder, OutputParser* out, OutputParser* err,
- Encoding encoding)
+void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
+ OutputParser* err, Encoding encoding)
{
+ cmsysProcess_Execute(cp);
+ char* data = nullptr;
+ int length = 0;
+ int p;
cmProcessOutput processOutput(encoding);
-
- builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
- .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
-
- auto chain = builder.Start();
-
std::string strdata;
- cm::uv_pipe_ptr outputPipe;
- outputPipe.init(chain.GetLoop(), 0);
- uv_pipe_open(outputPipe, chain.OutputStream());
- auto outputHandle = cmUVStreamRead(
- outputPipe,
- [&out, &processOutput, &strdata](std::vector<char> data) {
- if (out) {
- processOutput.DecodeText(data.data(), data.size(), strdata, 1);
- if (!out->Process(strdata.c_str(), static_cast<int>(strdata.size()))) {
- out = nullptr;
- }
+ while ((out || err) &&
+ (p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) {
+ if (out && p == cmsysProcess_Pipe_STDOUT) {
+ processOutput.DecodeText(data, length, strdata, 1);
+ if (!out->Process(strdata.c_str(), static_cast<int>(strdata.size()))) {
+ out = nullptr;
}
- },
- [&out]() { out = nullptr; });
- cm::uv_pipe_ptr errorPipe;
- errorPipe.init(chain.GetLoop(), 0);
- uv_pipe_open(errorPipe, chain.ErrorStream());
- auto errorHandle = cmUVStreamRead(
- errorPipe,
- [&err, &processOutput, &strdata](std::vector<char> data) {
- if (err) {
- processOutput.DecodeText(data.data(), data.size(), strdata, 2);
- if (!err->Process(strdata.c_str(), static_cast<int>(strdata.size()))) {
- err = nullptr;
- }
+ } else if (err && p == cmsysProcess_Pipe_STDERR) {
+ processOutput.DecodeText(data, length, strdata, 2);
+ if (!err->Process(strdata.c_str(), static_cast<int>(strdata.size()))) {
+ err = nullptr;
}
- },
- [&err]() { err = nullptr; });
- while (out || err || !chain.Finished()) {
- uv_run(&chain.GetLoop(), UV_RUN_ONCE);
+ }
}
-
- std::vector<cmUVProcessChain::Status> result;
- auto status = chain.GetStatus();
- std::transform(
- status.begin(), status.end(), std::back_inserter(result),
- [](const cmUVProcessChain::Status* s) -> cmUVProcessChain::Status {
- return *s;
- });
- return result;
+ if (out) {
+ processOutput.DecodeText(std::string(), strdata, 1);
+ if (!strdata.empty()) {
+ out->Process(strdata.c_str(), static_cast<int>(strdata.size()));
+ }
+ }
+ if (err) {
+ processOutput.DecodeText(std::string(), strdata, 2);
+ if (!strdata.empty()) {
+ err->Process(strdata.c_str(), static_cast<int>(strdata.size()));
+ }
+ }
+ cmsysProcess_WaitForExit(cp, nullptr);
}
cmProcessTools::LineParser::LineParser(char sep, bool ignoreCR)
diff --git a/Source/cmProcessTools.h b/Source/cmProcessTools.h
index 2bdabea..74ec5e0 100644
--- a/Source/cmProcessTools.h
+++ b/Source/cmProcessTools.h
@@ -7,10 +7,8 @@
#include <cstring>
#include <iosfwd>
#include <string>
-#include <vector>
#include "cmProcessOutput.h"
-#include "cmUVProcessChain.h"
/** \class cmProcessTools
* \brief Helper classes for process output parsing
@@ -83,7 +81,7 @@ public:
};
/** Run a process and send output to given parsers. */
- static std::vector<cmUVProcessChain::Status> RunProcess(
- cmUVProcessChainBuilder& builder, OutputParser* out,
- OutputParser* err = nullptr, Encoding encoding = cmProcessOutput::Auto);
+ static void RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
+ OutputParser* err = nullptr,
+ Encoding encoding = cmProcessOutput::Auto);
};
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 1f5333f..2bdc928 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -31,9 +31,6 @@
#include "cmProcessOutput.h"
#include "cmRange.h"
#include "cmStringAlgorithms.h"
-#include "cmUVHandlePtr.h"
-#include "cmUVProcessChain.h"
-#include "cmUVStream.h"
#include "cmValue.h"
#if !defined(CMAKE_BOOTSTRAP)
@@ -62,14 +59,12 @@
#include <cassert>
#include <cctype>
#include <cerrno>
-#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <functional>
#include <iostream>
-#include <memory>
#include <sstream>
#include <utility>
#include <vector>
@@ -573,111 +568,85 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
const char* dir, OutputOption outputflag,
cmDuration timeout, Encoding encoding)
{
- cmUVProcessChainBuilder builder;
- builder.SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT, stdin)
- .AddCommand(command);
- if (dir) {
- builder.SetWorkingDirectory(dir);
+ std::vector<const char*> argv;
+ argv.reserve(command.size() + 1);
+ for (std::string const& cmd : command) {
+ argv.push_back(cmd.c_str());
+ }
+ argv.push_back(nullptr);
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, argv.data());
+ cmsysProcess_SetWorkingDirectory(cp, dir);
+ if (cmSystemTools::GetRunCommandHideConsole()) {
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
}
if (outputflag == OUTPUT_PASSTHROUGH) {
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
captureStdOut = nullptr;
captureStdErr = nullptr;
- builder.SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, stdout)
- .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, stderr);
} else if (outputflag == OUTPUT_MERGE ||
(captureStdErr && captureStdErr == captureStdOut)) {
- builder.SetMergedBuiltinStreams();
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_MergeOutput, 1);
captureStdErr = nullptr;
- } else {
- builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
- .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
}
assert(!captureStdErr || captureStdErr != captureStdOut);
- auto chain = builder.Start();
- bool timedOut = false;
- cm::uv_timer_ptr timer;
- if (timeout.count()) {
- timer.init(chain.GetLoop(), &timedOut);
- timer.start(
- [](uv_timer_t* t) {
- auto* timedOutPtr = static_cast<bool*>(t->data);
- *timedOutPtr = true;
- },
- static_cast<uint64_t>(timeout.count() * 1000.0), 0);
- }
+ cmsysProcess_SetTimeout(cp, timeout.count());
+ cmsysProcess_Execute(cp);
std::vector<char> tempStdOut;
std::vector<char> tempStdErr;
- cm::uv_pipe_ptr outStream;
- bool outFinished = true;
- cm::uv_pipe_ptr errStream;
- bool errFinished = true;
+ char* data;
+ int length;
+ int pipe;
cmProcessOutput processOutput(encoding);
- std::unique_ptr<cmUVStreamReadHandle> outputHandle;
- std::unique_ptr<cmUVStreamReadHandle> errorHandle;
+ std::string strdata;
if (outputflag != OUTPUT_PASSTHROUGH &&
(captureStdOut || captureStdErr || outputflag != OUTPUT_NONE)) {
- auto startRead =
- [&outputflag, &processOutput,
- &chain](cm::uv_pipe_ptr& pipe, int stream, std::string* captureStd,
- std::vector<char>& tempStd, int id,
- void (*outputFunc)(const std::string&),
- bool& finished) -> std::unique_ptr<cmUVStreamReadHandle> {
- if (stream < 0) {
- return nullptr;
- }
-
- pipe.init(chain.GetLoop(), 0);
- uv_pipe_open(pipe, stream);
-
- finished = false;
- return cmUVStreamRead(
- pipe,
- [outputflag, &processOutput, captureStd, &tempStd, id,
- outputFunc](std::vector<char> data) {
- // Translate NULL characters in the output into valid text.
- for (auto& c : data) {
- if (c == '\0') {
- c = ' ';
- }
- }
+ while ((pipe = cmsysProcess_WaitForData(cp, &data, &length, nullptr)) >
+ 0) {
+ // Translate NULL characters in the output into valid text.
+ for (int i = 0; i < length; ++i) {
+ if (data[i] == '\0') {
+ data[i] = ' ';
+ }
+ }
- if (outputflag != OUTPUT_NONE) {
- std::string strdata;
- processOutput.DecodeText(data.data(), data.size(), strdata, id);
- outputFunc(strdata);
- }
- if (captureStd) {
- cm::append(tempStd, data.data(), data.data() + data.size());
- }
- },
- [&finished, outputflag, &processOutput, id, outputFunc]() {
- finished = true;
- if (outputflag != OUTPUT_NONE) {
- std::string strdata;
- processOutput.DecodeText(std::string(), strdata, id);
- if (!strdata.empty()) {
- outputFunc(strdata);
- }
- }
- });
- };
+ if (pipe == cmsysProcess_Pipe_STDOUT) {
+ if (outputflag != OUTPUT_NONE) {
+ processOutput.DecodeText(data, length, strdata, 1);
+ cmSystemTools::Stdout(strdata);
+ }
+ if (captureStdOut) {
+ cm::append(tempStdOut, data, data + length);
+ }
+ } else if (pipe == cmsysProcess_Pipe_STDERR) {
+ if (outputflag != OUTPUT_NONE) {
+ processOutput.DecodeText(data, length, strdata, 2);
+ cmSystemTools::Stderr(strdata);
+ }
+ if (captureStdErr) {
+ cm::append(tempStdErr, data, data + length);
+ }
+ }
+ }
- outputHandle =
- startRead(outStream, chain.OutputStream(), captureStdOut, tempStdOut, 1,
- cmSystemTools::Stdout, outFinished);
- if (chain.OutputStream() != chain.ErrorStream()) {
- errorHandle =
- startRead(errStream, chain.ErrorStream(), captureStdErr, tempStdErr, 2,
- cmSystemTools::Stderr, errFinished);
+ if (outputflag != OUTPUT_NONE) {
+ processOutput.DecodeText(std::string(), strdata, 1);
+ if (!strdata.empty()) {
+ cmSystemTools::Stdout(strdata);
+ }
+ processOutput.DecodeText(std::string(), strdata, 2);
+ if (!strdata.empty()) {
+ cmSystemTools::Stderr(strdata);
+ }
}
}
- while (!timedOut && !(chain.Finished() && outFinished && errFinished)) {
- uv_run(&chain.GetLoop(), UV_RUN_ONCE);
- }
+ cmsysProcess_WaitForExit(cp, nullptr);
if (captureStdOut) {
captureStdOut->assign(tempStdOut.begin(), tempStdOut.end());
@@ -689,43 +658,48 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
}
bool result = true;
- if (timedOut) {
- const char* error_str = "Process terminated due to timeout\n";
+ if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
+ if (retVal) {
+ *retVal = cmsysProcess_GetExitValue(cp);
+ } else {
+ if (cmsysProcess_GetExitValue(cp) != 0) {
+ result = false;
+ }
+ }
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) {
+ const char* exception_str = cmsysProcess_GetExceptionString(cp);
+ if (outputflag != OUTPUT_NONE) {
+ std::cerr << exception_str << std::endl;
+ }
+ if (captureStdErr) {
+ captureStdErr->append(exception_str, strlen(exception_str));
+ } else if (captureStdOut) {
+ captureStdOut->append(exception_str, strlen(exception_str));
+ }
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
+ const char* error_str = cmsysProcess_GetErrorString(cp);
if (outputflag != OUTPUT_NONE) {
std::cerr << error_str << std::endl;
}
if (captureStdErr) {
captureStdErr->append(error_str, strlen(error_str));
+ } else if (captureStdOut) {
+ captureStdOut->append(error_str, strlen(error_str));
}
result = false;
- } else {
- auto const& status = chain.GetStatus(0);
- auto exception = status.GetException();
-
- switch (exception.first) {
- case cmUVProcessChain::ExceptionCode::None:
- if (retVal) {
- *retVal = static_cast<int>(status.ExitStatus);
- } else {
- if (status.ExitStatus != 0) {
- result = false;
- }
- }
- break;
- default: {
- if (outputflag != OUTPUT_NONE) {
- std::cerr << exception.second << std::endl;
- }
- if (captureStdErr) {
- captureStdErr->append(exception.second);
- } else if (captureStdOut) {
- captureStdOut->append(exception.second);
- }
- result = false;
- } break;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) {
+ const char* error_str = "Process terminated due to timeout\n";
+ if (outputflag != OUTPUT_NONE) {
+ std::cerr << error_str << std::endl;
+ }
+ if (captureStdErr) {
+ captureStdErr->append(error_str, strlen(error_str));
}
+ result = false;
}
+ cmsysProcess_Delete(cp);
return result;
}
@@ -2239,10 +2213,9 @@ bool cmSystemTools::ListTar(const std::string& outFileName,
#endif
}
-cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine(
- uv_loop_t* loop, uv_stream_t* outPipe, uv_stream_t* errPipe,
- std::string& line, cmDuration timeout, std::vector<char>& out,
- std::vector<char>& err)
+int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
+ cmDuration timeout, std::vector<char>& out,
+ std::vector<char>& err)
{
line.clear();
auto outiter = out.begin();
@@ -2264,7 +2237,7 @@ cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine(
line.append(out.data(), length);
}
out.erase(out.begin(), outiter + 1);
- return WaitForLineResult::STDOUT;
+ return cmsysProcess_Pipe_STDOUT;
}
}
@@ -2282,66 +2255,33 @@ cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine(
line.append(err.data(), length);
}
err.erase(err.begin(), erriter + 1);
- return WaitForLineResult::STDERR;
+ return cmsysProcess_Pipe_STDERR;
}
}
// No newlines found. Wait for more data from the process.
- struct ReadData
- {
- uv_stream_t* Stream;
- std::vector<char> Buffer;
- bool Read = false;
- bool Finished = false;
- };
- auto startRead =
- [](uv_stream_t* stream,
- ReadData& data) -> std::unique_ptr<cmUVStreamReadHandle> {
- data.Stream = stream;
- return cmUVStreamRead(
- stream,
- [&data](std::vector<char> buf) {
- data.Buffer = std::move(buf);
- data.Read = true;
- uv_read_stop(data.Stream);
- },
- [&data]() { data.Finished = true; });
- };
- ReadData outData;
- auto outHandle = startRead(outPipe, outData);
- ReadData errData;
- auto errHandle = startRead(errPipe, errData);
-
- cm::uv_timer_ptr timer;
- bool timedOut = false;
- timer.init(*loop, &timedOut);
- timer.start(
- [](uv_timer_t* handle) {
- auto* timedOutPtr = static_cast<bool*>(handle->data);
- *timedOutPtr = true;
- },
- static_cast<uint64_t>(timeout.count() * 1000.0), 0);
-
- uv_run(loop, UV_RUN_ONCE);
- if (timedOut) {
+ int length;
+ char* data;
+ double timeoutAsDbl = timeout.count();
+ int pipe =
+ cmsysProcess_WaitForData(process, &data, &length, &timeoutAsDbl);
+ if (pipe == cmsysProcess_Pipe_Timeout) {
// Timeout has been exceeded.
- return WaitForLineResult::Timeout;
+ return pipe;
}
- if (outData.Read) {
- processOutput.DecodeText(outData.Buffer.data(), outData.Buffer.size(),
- strdata, 1);
+ if (pipe == cmsysProcess_Pipe_STDOUT) {
+ processOutput.DecodeText(data, length, strdata, 1);
// Append to the stdout buffer.
std::vector<char>::size_type size = out.size();
cm::append(out, strdata);
outiter = out.begin() + size;
- } else if (errData.Read) {
- processOutput.DecodeText(errData.Buffer.data(), errData.Buffer.size(),
- strdata, 2);
+ } else if (pipe == cmsysProcess_Pipe_STDERR) {
+ processOutput.DecodeText(data, length, strdata, 2);
// Append to the stderr buffer.
std::vector<char>::size_type size = err.size();
cm::append(err, strdata);
erriter = err.begin() + size;
- } else if (outData.Finished && errData.Finished) {
+ } else if (pipe == cmsysProcess_Pipe_None) {
// Both stdout and stderr pipes have broken. Return leftover data.
processOutput.DecodeText(std::string(), strdata, 1);
if (!strdata.empty()) {
@@ -2358,20 +2298,14 @@ cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine(
if (!out.empty()) {
line.append(out.data(), outiter - out.begin());
out.erase(out.begin(), out.end());
- return WaitForLineResult::STDOUT;
+ return cmsysProcess_Pipe_STDOUT;
}
if (!err.empty()) {
line.append(err.data(), erriter - err.begin());
err.erase(err.begin(), err.end());
- return WaitForLineResult::STDERR;
+ return cmsysProcess_Pipe_STDERR;
}
- return WaitForLineResult::None;
- }
- if (!outData.Finished) {
- uv_read_stop(outPipe);
- }
- if (!errData.Finished) {
- uv_read_stop(errPipe);
+ return cmsysProcess_Pipe_None;
}
}
}
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 7e33e58..9563fd6 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -18,8 +18,7 @@
#include <cm/optional>
#include <cm/string_view>
-#include <cm3p/uv.h>
-
+#include "cmsys/Process.h"
#include "cmsys/Status.hxx" // IWYU pragma: export
#include "cmsys/SystemTools.hxx" // IWYU pragma: export
@@ -340,20 +339,10 @@ public:
*/
static void ReportLastSystemError(const char* m);
- enum class WaitForLineResult
- {
- None,
- STDOUT,
- STDERR,
- Timeout,
- };
-
- /** a general output handler for libuv */
- static WaitForLineResult WaitForLine(uv_loop_t* loop, uv_stream_t* outPipe,
- uv_stream_t* errPipe, std::string& line,
- cmDuration timeout,
- std::vector<char>& out,
- std::vector<char>& err);
+ /** a general output handler for cmsysProcess */
+ static int WaitForLine(cmsysProcess* process, std::string& line,
+ cmDuration timeout, std::vector<char>& out,
+ std::vector<char>& err);
static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; }
static bool GetForceUnixPaths() { return s_ForceUnixPaths; }
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 5bf8edc..9d7bf50 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -72,6 +72,7 @@
#include "cmsys/Directory.hxx"
#include "cmsys/FStream.hxx"
+#include "cmsys/Process.h"
#include "cmsys/RegularExpression.hxx"
#include "cmsys/Terminal.h"
@@ -294,8 +295,14 @@ int CLCompileAndDependencies(const std::vector<std::string>& args)
}
}
- cmUVProcessChainBuilder builder;
- builder.AddCommand(command).SetWorkingDirectory(currentBinaryDir);
+ std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp(
+ cmsysProcess_New(), cmsysProcess_Delete);
+ std::vector<const char*> argv(command.size() + 1);
+ std::transform(command.begin(), command.end(), argv.begin(),
+ [](std::string const& s) { return s.c_str(); });
+ argv.back() = nullptr;
+ cmsysProcess_SetCommand(cp.get(), argv.data());
+ cmsysProcess_SetWorkingDirectory(cp.get(), currentBinaryDir.c_str());
cmsys::ofstream fout(depFile.c_str());
if (!fout) {
@@ -306,18 +313,22 @@ int CLCompileAndDependencies(const std::vector<std::string>& args)
CLOutputLogger errLogger(std::cerr);
// Start the process.
- auto result =
- cmProcessTools::RunProcess(builder, &includeParser, &errLogger);
- auto const& subStatus = result.front();
+ cmProcessTools::RunProcess(cp.get(), &includeParser, &errLogger);
int status = 0;
// handle status of process
- if (subStatus.SpawnResult != 0) {
- status = 2;
- } else if (subStatus.TermSignal != 0) {
- status = 1;
- } else {
- status = static_cast<int>(subStatus.ExitStatus);
+ switch (cmsysProcess_GetState(cp.get())) {
+ case cmsysProcess_State_Exited:
+ status = cmsysProcess_GetExitValue(cp.get());
+ break;
+ case cmsysProcess_State_Exception:
+ status = 1;
+ break;
+ case cmsysProcess_State_Error:
+ status = 2;
+ break;
+ default:
+ break;
}
if (status != 0) {
@@ -1105,8 +1116,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
int ret = 0;
auto time_start = std::chrono::steady_clock::now();
- cmSystemTools::RunSingleCommand(command, nullptr, nullptr, &ret, nullptr,
- cmSystemTools::OUTPUT_PASSTHROUGH);
+ cmSystemTools::RunSingleCommand(command, nullptr, nullptr, &ret);
auto time_finish = std::chrono::steady_clock::now();
std::chrono::duration<double> time_elapsed = time_finish - time_start;
@@ -1880,6 +1890,21 @@ int cmcmd::ExecuteLinkScript(std::vector<std::string> const& args)
}
}
+ // Allocate a process instance.
+ cmsysProcess* cp = cmsysProcess_New();
+ if (!cp) {
+ std::cerr << "Error allocating process instance in link script."
+ << std::endl;
+ return 1;
+ }
+
+ // Children should share stdout and stderr with this process.
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
+ cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
+
+ // Run the command lines verbatim.
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);
+
// Read command lines from the script.
cmsys::ifstream fin(args[2].c_str());
if (!fin) {
@@ -1897,21 +1922,9 @@ int cmcmd::ExecuteLinkScript(std::vector<std::string> const& args)
continue;
}
- // Allocate a process instance.
- cmUVProcessChainBuilder builder;
-
- // Children should share stdout and stderr with this process.
- builder.SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, stdout)
- .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, stderr);
-
// Setup this command line.
- std::vector<std::string> args2;
-#ifdef _WIN32
- cmSystemTools::ParseWindowsCommandLine(command.c_str(), args2);
-#else
- cmSystemTools::ParseUnixCommandLine(command.c_str(), args2);
-#endif
- builder.AddCommand(args2);
+ const char* cmd[2] = { command.c_str(), nullptr };
+ cmsysProcess_SetCommand(cp, cmd);
// Report the command if verbose output is enabled.
if (verbose) {
@@ -1919,29 +1932,35 @@ int cmcmd::ExecuteLinkScript(std::vector<std::string> const& args)
}
// Run the command and wait for it to exit.
- auto chain = builder.Start();
- chain.Wait();
+ cmsysProcess_Execute(cp);
+ cmsysProcess_WaitForExit(cp, nullptr);
// Report failure if any.
- auto const& status = chain.GetStatus(0);
- auto exception = status.GetException();
- switch (exception.first) {
- case cmUVProcessChain::ExceptionCode::None:
- if (status.ExitStatus != 0) {
- result = static_cast<int>(status.ExitStatus);
+ switch (cmsysProcess_GetState(cp)) {
+ case cmsysProcess_State_Exited: {
+ int value = cmsysProcess_GetExitValue(cp);
+ if (value != 0) {
+ result = value;
}
+ } break;
+ case cmsysProcess_State_Exception:
+ std::cerr << "Error running link command: "
+ << cmsysProcess_GetExceptionString(cp) << std::endl;
+ result = 1;
break;
- case cmUVProcessChain::ExceptionCode::Spawn:
- std::cerr << "Error running link command: " << exception.second;
+ case cmsysProcess_State_Error:
+ std::cerr << "Error running link command: "
+ << cmsysProcess_GetErrorString(cp) << std::endl;
result = 2;
break;
default:
- std::cerr << "Error running link command: " << exception.second;
- result = 1;
break;
}
}
+ // Free the process instance.
+ cmsysProcess_Delete(cp);
+
// Return the final resulting return value.
return result;
}