summaryrefslogtreecommitdiffstats
path: root/Source/CTest
diff options
context:
space:
mode:
authorKyle Edwards <kyle.edwards@kitware.com>2023-07-26 20:58:34 (GMT)
committerKyle Edwards <kyle.edwards@kitware.com>2023-08-29 14:51:30 (GMT)
commit96b3dd329ecdecdf2110cab4bc368690a630e012 (patch)
tree31cb0510192cfce573a400b517299b56c6db6476 /Source/CTest
parentb15ad7ebb6b96630396fb54b4679075a52c5f79b (diff)
downloadCMake-96b3dd329ecdecdf2110cab4bc368690a630e012.zip
CMake-96b3dd329ecdecdf2110cab4bc368690a630e012.tar.gz
CMake-96b3dd329ecdecdf2110cab4bc368690a630e012.tar.bz2
cmCTestLaunchReporter: Replace cmsysProcess with cmUVProcessChain
And convert cmCTestLaunch and cmCTestBuildHandler too.
Diffstat (limited to 'Source/CTest')
-rw-r--r--Source/CTest/cmCTestBuildHandler.cxx291
-rw-r--r--Source/CTest/cmCTestBuildHandler.h6
-rw-r--r--Source/CTest/cmCTestLaunch.cxx126
-rw-r--r--Source/CTest/cmCTestLaunch.h5
-rw-r--r--Source/CTest/cmCTestLaunchReporter.cxx50
-rw-r--r--Source/CTest/cmCTestLaunchReporter.h4
6 files changed, 256 insertions, 226 deletions
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index 00ecf42..859798e 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -3,15 +3,17 @@
#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"
@@ -24,6 +26,9 @@
#include "cmStringAlgorithms.h"
#include "cmStringReplaceHelper.h"
#include "cmSystemTools.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVProcessChain.h"
+#include "cmUVStream.h"
#include "cmValue.h"
#include "cmXMLWriter.h"
@@ -420,7 +425,7 @@ int cmCTestBuildHandler::ProcessHandler()
cmStringReplaceHelper colorRemover("\x1b\\[[0-9;]*m", "", nullptr);
this->ColorRemover = &colorRemover;
int retVal = 0;
- int res = cmsysProcess_State_Exited;
+ bool res = true;
if (!this->CTest->GetShowOnly()) {
res = this->RunMakeCommand(makeCommand, &retVal, buildDirectory.c_str(), 0,
ofs);
@@ -475,7 +480,7 @@ int cmCTestBuildHandler::ProcessHandler()
}
this->GenerateXMLFooter(xml, elapsed_build_time);
- if (res != cmsysProcess_State_Exited || retVal || this->TotalErrors > 0) {
+ if (!res || retVal || this->TotalErrors > 0) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Error(s) when building project" << std::endl);
}
@@ -764,10 +769,10 @@ void cmCTestBuildHandler::LaunchHelper::WriteScrapeMatchers(
}
}
-int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
- int* retVal, const char* dir,
- int timeout, std::ostream& ofs,
- Encoding encoding)
+bool 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);
@@ -776,19 +781,9 @@ int 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 (char const* arg : argv) {
- if (!arg) {
- break;
- }
+ for (auto const& arg : args) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
" \"" << arg << "\"", this->Quiet);
}
@@ -800,21 +795,20 @@ int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
static_cast<void>(launchHelper);
// Now create process object
- 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);
+ cmUVProcessChainBuilder builder;
+ builder.AddCommand(args)
+ .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
+ .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
+ if (dir) {
+ builder.SetWorkingDirectory(dir);
+ }
+ auto chain = builder.Start();
// Initialize tick's
std::string::size_type tick = 0;
- const std::string::size_type tick_len = 1024;
+ static constexpr 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 "
@@ -836,39 +830,65 @@ int 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
- 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';
- }
- }
+ 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';
+ }
+ }
- // 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);
+ // 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);
}
-
this->ProcessBuffer(nullptr, 0, tick, tick_len, ofs,
&this->BuildProcessingQueue);
this->ProcessBuffer(nullptr, 0, tick, tick_len, ofs,
@@ -879,90 +899,93 @@ int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
<< std::endl,
this->Quiet);
- // 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 (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++;
}
}
- 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++;
}
- }
- }
- } 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);
+ 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 if (result == cmsysProcess_State_Expired) {
+ } else {
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);
}
- cmsysProcess_Delete(cp);
- return result;
+ return true;
}
// ######################################################################
diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h
index e33294d..90945b1 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.
- int RunMakeCommand(const std::string& command, int* retVal, const char* dir,
- int timeout, std::ostream& ofs,
- Encoding encoding = cmProcessOutput::Auto);
+ bool 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/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
index 4a33869..6b13ad1 100644
--- a/Source/CTest/cmCTestLaunch.cxx
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -2,13 +2,19 @@
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 "cm_fileno.hxx"
+
#include "cmCTestLaunchReporter.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
@@ -17,6 +23,9 @@
#include "cmStateSnapshot.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVProcessChain.h"
+#include "cmUVStream.h"
#include "cmake.h"
#ifdef _WIN32
@@ -28,8 +37,6 @@
cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
{
- this->Process = nullptr;
-
if (!this->ParseArguments(argc, argv)) {
return;
}
@@ -40,13 +47,9 @@ cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
this->ScrapeRulesLoaded = false;
this->HaveOut = false;
this->HaveErr = false;
- this->Process = cmsysProcess_New();
}
-cmCTestLaunch::~cmCTestLaunch()
-{
- cmsysProcess_Delete(this->Process);
-}
+cmCTestLaunch::~cmCTestLaunch() = default;
bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
{
@@ -113,15 +116,12 @@ bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
// Extract the real command line.
if (arg0) {
- this->RealArgC = argc - arg0;
- this->RealArgV = argv + arg0;
- for (int i = 0; i < this->RealArgC; ++i) {
- this->HandleRealArg(this->RealArgV[i]);
+ for (int i = 0; i < argc - arg0; ++i) {
+ this->RealArgV.emplace_back((argv + arg0)[i]);
+ this->HandleRealArg((argv + arg0)[i]);
}
return true;
}
- this->RealArgC = 0;
- this->RealArgV = nullptr;
std::cerr << "No launch/command separator ('--') found!\n";
return false;
}
@@ -151,17 +151,22 @@ void cmCTestLaunch::RunChild()
}
// Prepare to run the real command.
- cmsysProcess* cp = this->Process;
- cmsysProcess_SetCommand(cp, this->RealArgV);
+ cmUVProcessChainBuilder builder;
+ builder.AddCommand(this->RealArgV);
cmsys::ofstream fout;
cmsys::ofstream ferr;
if (this->Reporter.Passthru) {
// In passthru mode we just share the output pipes.
- cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
- cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
+ builder
+ .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT,
+ cm_fileno(stdout))
+ .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
+ cm_fileno(stderr));
} 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,51 +179,65 @@ void cmCTestLaunch::RunChild()
#endif
// Run the real command.
- cmsysProcess_Execute(cp);
+ auto chain = builder.Start();
// 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) {
- 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());
- }
+ 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);
}
// Wait for the real command to finish.
- cmsysProcess_WaitForExit(cp, nullptr);
- this->Reporter.ExitCode = cmsysProcess_GetExitValue(cp);
+ 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);
+ }
}
int cmCTestLaunch::Run()
{
- if (!this->Process) {
- std::cerr << "Could not allocate cmsysProcess instance!\n";
- return -1;
- }
-
this->RunChild();
if (this->CheckResults()) {
@@ -226,7 +245,6 @@ 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 c5a6476..ef21a26 100644
--- a/Source/CTest/cmCTestLaunch.h
+++ b/Source/CTest/cmCTestLaunch.h
@@ -43,15 +43,12 @@ private:
bool ParseArguments(int argc, const char* const* argv);
// The real command line appearing after launcher arguments.
- int RealArgC;
- const char* const* RealArgV;
+ std::vector<std::string> 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 149ba5d..4b4e5c5 100644
--- a/Source/CTest/cmCTestLaunchReporter.cxx
+++ b/Source/CTest/cmCTestLaunchReporter.cxx
@@ -2,8 +2,9 @@
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"
@@ -22,6 +23,7 @@
cmCTestLaunchReporter::cmCTestLaunchReporter()
{
this->Passthru = true;
+ this->Status.Finished = true;
this->ExitCode = 1;
this->CWD = cmSystemTools::GetCurrentWorkingDirectory();
@@ -231,35 +233,23 @@ void cmCTestLaunchReporter::WriteXMLResult(cmXMLElement& e2)
// ExitCondition
cmXMLElement e4(e3, "ExitCondition");
- 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;
+ 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");
}
}
diff --git a/Source/CTest/cmCTestLaunchReporter.h b/Source/CTest/cmCTestLaunchReporter.h
index 4be0d9b..2bb78f8 100644
--- a/Source/CTest/cmCTestLaunchReporter.h
+++ b/Source/CTest/cmCTestLaunchReporter.h
@@ -10,6 +10,8 @@
#include "cmsys/RegularExpression.hxx"
+#include "cmUVProcessChain.h"
+
class cmXMLElement;
/** \class cmCTestLaunchReporter
@@ -48,7 +50,7 @@ public:
void ComputeFileNames();
bool Passthru;
- struct cmsysProcess_s* Process;
+ cmUVProcessChain::Status Status;
int ExitCode;
// Temporary log files for stdout and stderr of real command.