Przeglądaj źródła

cmCTestLaunchReporter: Replace cmsysProcess with cmUVProcessChain

And convert cmCTestLaunch and cmCTestBuildHandler too.
Kyle Edwards 2 lat temu
rodzic
commit
96b3dd329e

+ 157 - 134
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;
 }
 
 // ######################################################################

+ 3 - 3
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
   {

+ 72 - 54
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;

+ 1 - 4
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;

+ 20 - 30
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");
   }
 }
 

+ 3 - 1
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.