mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-25 01:28:50 -05:00
cmCTestScriptHandler: Replace cmsysProcess with cmUVProcessChain
And update cmSystemTools::WaitForLine() to use cmUVProcessChain.
This commit is contained in:
@@ -11,8 +11,9 @@
|
|||||||
|
|
||||||
#include <cm/memory>
|
#include <cm/memory>
|
||||||
|
|
||||||
|
#include <cm3p/uv.h>
|
||||||
|
|
||||||
#include "cmsys/Directory.hxx"
|
#include "cmsys/Directory.hxx"
|
||||||
#include "cmsys/Process.h"
|
|
||||||
|
|
||||||
#include "cmCTest.h"
|
#include "cmCTest.h"
|
||||||
#include "cmCTestBuildCommand.h"
|
#include "cmCTestBuildCommand.h"
|
||||||
@@ -40,6 +41,8 @@
|
|||||||
#include "cmStateSnapshot.h"
|
#include "cmStateSnapshot.h"
|
||||||
#include "cmStringAlgorithms.h"
|
#include "cmStringAlgorithms.h"
|
||||||
#include "cmSystemTools.h"
|
#include "cmSystemTools.h"
|
||||||
|
#include "cmUVHandlePtr.h"
|
||||||
|
#include "cmUVProcessChain.h"
|
||||||
#include "cmValue.h"
|
#include "cmValue.h"
|
||||||
#include "cmake.h"
|
#include "cmake.h"
|
||||||
|
|
||||||
@@ -148,66 +151,65 @@ int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
|
|||||||
// now pass through all the other arguments
|
// now pass through all the other arguments
|
||||||
std::vector<std::string>& initArgs =
|
std::vector<std::string>& initArgs =
|
||||||
this->CTest->GetInitialCommandLineArguments();
|
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
|
// Now create process object
|
||||||
cmsysProcess* cp = cmsysProcess_New();
|
cmUVProcessChainBuilder builder;
|
||||||
cmsysProcess_SetCommand(cp, argv.data());
|
builder.AddCommand(initArgs)
|
||||||
// cmsysProcess_SetWorkingDirectory(cp, dir);
|
.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
|
||||||
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
|
.SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
|
||||||
// cmsysProcess_SetTimeout(cp, timeout);
|
auto process = builder.Start();
|
||||||
cmsysProcess_Execute(cp);
|
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());
|
||||||
|
|
||||||
std::vector<char> out;
|
std::vector<char> out;
|
||||||
std::vector<char> err;
|
std::vector<char> err;
|
||||||
std::string line;
|
std::string line;
|
||||||
int pipe =
|
auto pipe =
|
||||||
cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, err);
|
cmSystemTools::WaitForLine(&process.GetLoop(), outPipe, errPipe, line,
|
||||||
while (pipe != cmsysProcess_Pipe_None) {
|
std::chrono::seconds(100), out, err);
|
||||||
|
while (pipe != cmSystemTools::WaitForLineResult::None) {
|
||||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
||||||
"Output: " << line << "\n");
|
"Output: " << line << "\n");
|
||||||
if (pipe == cmsysProcess_Pipe_STDERR) {
|
if (pipe == cmSystemTools::WaitForLineResult::STDERR) {
|
||||||
cmCTestLog(this->CTest, ERROR_MESSAGE, line << "\n");
|
cmCTestLog(this->CTest, ERROR_MESSAGE, line << "\n");
|
||||||
} else if (pipe == cmsysProcess_Pipe_STDOUT) {
|
} else if (pipe == cmSystemTools::WaitForLineResult::STDOUT) {
|
||||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n");
|
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n");
|
||||||
}
|
}
|
||||||
pipe = cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out,
|
pipe =
|
||||||
err);
|
cmSystemTools::WaitForLine(&process.GetLoop(), outPipe, errPipe, line,
|
||||||
|
std::chrono::seconds(100), out, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Properly handle output of the build command
|
// Properly handle output of the build command
|
||||||
cmsysProcess_WaitForExit(cp, nullptr);
|
process.Wait();
|
||||||
int result = cmsysProcess_GetState(cp);
|
auto const& status = process.GetStatus(0);
|
||||||
|
auto result = status.GetException();
|
||||||
int retVal = 0;
|
int retVal = 0;
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
if (result == cmsysProcess_State_Exited) {
|
switch (result.first) {
|
||||||
retVal = cmsysProcess_GetExitValue(cp);
|
case cmUVProcessChain::ExceptionCode::None:
|
||||||
} else if (result == cmsysProcess_State_Exception) {
|
retVal = static_cast<int>(status.ExitStatus);
|
||||||
retVal = cmsysProcess_GetExitException(cp);
|
break;
|
||||||
cmCTestLog(this->CTest, ERROR_MESSAGE,
|
case cmUVProcessChain::ExceptionCode::Spawn:
|
||||||
"\tThere was an exception: "
|
cmCTestLog(this->CTest, ERROR_MESSAGE,
|
||||||
<< cmsysProcess_GetExceptionString(cp) << " " << retVal
|
"\tError executing ctest: " << result.second << std::endl);
|
||||||
<< std::endl);
|
failed = true;
|
||||||
failed = true;
|
break;
|
||||||
} else if (result == cmsysProcess_State_Expired) {
|
default:
|
||||||
cmCTestLog(this->CTest, ERROR_MESSAGE,
|
retVal = status.TermSignal;
|
||||||
"\tThere was a timeout" << std::endl);
|
cmCTestLog(this->CTest, ERROR_MESSAGE,
|
||||||
failed = true;
|
"\tThere was an exception: " << result.second << " " << retVal
|
||||||
} else if (result == cmsysProcess_State_Error) {
|
<< std::endl);
|
||||||
cmCTestLog(this->CTest, ERROR_MESSAGE,
|
failed = true;
|
||||||
"\tError executing ctest: " << cmsysProcess_GetErrorString(cp)
|
|
||||||
<< std::endl);
|
|
||||||
failed = true;
|
|
||||||
}
|
}
|
||||||
cmsysProcess_Delete(cp);
|
|
||||||
if (failed) {
|
if (failed) {
|
||||||
std::ostringstream message;
|
std::ostringstream message;
|
||||||
message << "Error running command: [";
|
message << "Error running command: [";
|
||||||
message << result << "] ";
|
message << static_cast<int>(result.first) << "] ";
|
||||||
for (const char* arg : argv) {
|
for (const char* arg : argv) {
|
||||||
if (arg) {
|
if (arg) {
|
||||||
message << arg << " ";
|
message << arg << " ";
|
||||||
|
|||||||
+64
-20
@@ -31,6 +31,8 @@
|
|||||||
#include "cmProcessOutput.h"
|
#include "cmProcessOutput.h"
|
||||||
#include "cmRange.h"
|
#include "cmRange.h"
|
||||||
#include "cmStringAlgorithms.h"
|
#include "cmStringAlgorithms.h"
|
||||||
|
#include "cmUVHandlePtr.h"
|
||||||
|
#include "cmUVStream.h"
|
||||||
#include "cmValue.h"
|
#include "cmValue.h"
|
||||||
|
|
||||||
#if !defined(CMAKE_BOOTSTRAP)
|
#if !defined(CMAKE_BOOTSTRAP)
|
||||||
@@ -59,12 +61,14 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -2213,9 +2217,10 @@ bool cmSystemTools::ListTar(const std::string& outFileName,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
|
cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine(
|
||||||
cmDuration timeout, std::vector<char>& out,
|
uv_loop_t* loop, uv_stream_t* outPipe, uv_stream_t* errPipe,
|
||||||
std::vector<char>& err)
|
std::string& line, cmDuration timeout, std::vector<char>& out,
|
||||||
|
std::vector<char>& err)
|
||||||
{
|
{
|
||||||
line.clear();
|
line.clear();
|
||||||
auto outiter = out.begin();
|
auto outiter = out.begin();
|
||||||
@@ -2237,7 +2242,7 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
|
|||||||
line.append(out.data(), length);
|
line.append(out.data(), length);
|
||||||
}
|
}
|
||||||
out.erase(out.begin(), outiter + 1);
|
out.erase(out.begin(), outiter + 1);
|
||||||
return cmsysProcess_Pipe_STDOUT;
|
return WaitForLineResult::STDOUT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2255,33 +2260,66 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
|
|||||||
line.append(err.data(), length);
|
line.append(err.data(), length);
|
||||||
}
|
}
|
||||||
err.erase(err.begin(), erriter + 1);
|
err.erase(err.begin(), erriter + 1);
|
||||||
return cmsysProcess_Pipe_STDERR;
|
return WaitForLineResult::STDERR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No newlines found. Wait for more data from the process.
|
// No newlines found. Wait for more data from the process.
|
||||||
int length;
|
struct ReadData
|
||||||
char* data;
|
{
|
||||||
double timeoutAsDbl = timeout.count();
|
uv_stream_t* Stream;
|
||||||
int pipe =
|
std::vector<char> Buffer;
|
||||||
cmsysProcess_WaitForData(process, &data, &length, &timeoutAsDbl);
|
bool Read = false;
|
||||||
if (pipe == cmsysProcess_Pipe_Timeout) {
|
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) {
|
||||||
// Timeout has been exceeded.
|
// Timeout has been exceeded.
|
||||||
return pipe;
|
return WaitForLineResult::Timeout;
|
||||||
}
|
}
|
||||||
if (pipe == cmsysProcess_Pipe_STDOUT) {
|
if (outData.Read) {
|
||||||
processOutput.DecodeText(data, length, strdata, 1);
|
processOutput.DecodeText(outData.Buffer.data(), outData.Buffer.size(),
|
||||||
|
strdata, 1);
|
||||||
// Append to the stdout buffer.
|
// Append to the stdout buffer.
|
||||||
std::vector<char>::size_type size = out.size();
|
std::vector<char>::size_type size = out.size();
|
||||||
cm::append(out, strdata);
|
cm::append(out, strdata);
|
||||||
outiter = out.begin() + size;
|
outiter = out.begin() + size;
|
||||||
} else if (pipe == cmsysProcess_Pipe_STDERR) {
|
} else if (errData.Read) {
|
||||||
processOutput.DecodeText(data, length, strdata, 2);
|
processOutput.DecodeText(errData.Buffer.data(), errData.Buffer.size(),
|
||||||
|
strdata, 2);
|
||||||
// Append to the stderr buffer.
|
// Append to the stderr buffer.
|
||||||
std::vector<char>::size_type size = err.size();
|
std::vector<char>::size_type size = err.size();
|
||||||
cm::append(err, strdata);
|
cm::append(err, strdata);
|
||||||
erriter = err.begin() + size;
|
erriter = err.begin() + size;
|
||||||
} else if (pipe == cmsysProcess_Pipe_None) {
|
} else if (outData.Finished && errData.Finished) {
|
||||||
// Both stdout and stderr pipes have broken. Return leftover data.
|
// Both stdout and stderr pipes have broken. Return leftover data.
|
||||||
processOutput.DecodeText(std::string(), strdata, 1);
|
processOutput.DecodeText(std::string(), strdata, 1);
|
||||||
if (!strdata.empty()) {
|
if (!strdata.empty()) {
|
||||||
@@ -2298,14 +2336,20 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
|
|||||||
if (!out.empty()) {
|
if (!out.empty()) {
|
||||||
line.append(out.data(), outiter - out.begin());
|
line.append(out.data(), outiter - out.begin());
|
||||||
out.erase(out.begin(), out.end());
|
out.erase(out.begin(), out.end());
|
||||||
return cmsysProcess_Pipe_STDOUT;
|
return WaitForLineResult::STDOUT;
|
||||||
}
|
}
|
||||||
if (!err.empty()) {
|
if (!err.empty()) {
|
||||||
line.append(err.data(), erriter - err.begin());
|
line.append(err.data(), erriter - err.begin());
|
||||||
err.erase(err.begin(), err.end());
|
err.erase(err.begin(), err.end());
|
||||||
return cmsysProcess_Pipe_STDERR;
|
return WaitForLineResult::STDERR;
|
||||||
}
|
}
|
||||||
return cmsysProcess_Pipe_None;
|
return WaitForLineResult::None;
|
||||||
|
}
|
||||||
|
if (!outData.Finished) {
|
||||||
|
uv_read_stop(outPipe);
|
||||||
|
}
|
||||||
|
if (!errData.Finished) {
|
||||||
|
uv_read_stop(errPipe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-4
@@ -18,6 +18,8 @@
|
|||||||
#include <cm/optional>
|
#include <cm/optional>
|
||||||
#include <cm/string_view>
|
#include <cm/string_view>
|
||||||
|
|
||||||
|
#include <cm3p/uv.h>
|
||||||
|
|
||||||
#include "cmsys/Process.h"
|
#include "cmsys/Process.h"
|
||||||
#include "cmsys/Status.hxx" // IWYU pragma: export
|
#include "cmsys/Status.hxx" // IWYU pragma: export
|
||||||
#include "cmsys/SystemTools.hxx" // IWYU pragma: export
|
#include "cmsys/SystemTools.hxx" // IWYU pragma: export
|
||||||
@@ -339,10 +341,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
static void ReportLastSystemError(const char* m);
|
static void ReportLastSystemError(const char* m);
|
||||||
|
|
||||||
/** a general output handler for cmsysProcess */
|
enum class WaitForLineResult
|
||||||
static int WaitForLine(cmsysProcess* process, std::string& line,
|
{
|
||||||
cmDuration timeout, std::vector<char>& out,
|
None,
|
||||||
std::vector<char>& err);
|
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);
|
||||||
|
|
||||||
static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; }
|
static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; }
|
||||||
static bool GetForceUnixPaths() { return s_ForceUnixPaths; }
|
static bool GetForceUnixPaths() { return s_ForceUnixPaths; }
|
||||||
|
|||||||
@@ -7,10 +7,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
# include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "cmSystemTools.h"
|
#include "cmSystemTools.h"
|
||||||
|
|
||||||
static std::string getStdin()
|
static std::string getStdin()
|
||||||
|
|||||||
Reference in New Issue
Block a user