diff options
-rw-r--r-- | Source/CTest/cmCTestScriptHandler.cxx | 84 | ||||
-rw-r--r-- | Source/cmSystemTools.cxx | 84 | ||||
-rw-r--r-- | Source/cmSystemTools.h | 20 | ||||
-rw-r--r-- | Tests/CMakeLib/testUVProcessChainHelper.cxx | 4 |
4 files changed, 123 insertions, 69 deletions
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index 461ad1a..48f8f6d 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -11,8 +11,9 @@ #include <cm/memory> +#include <cm3p/uv.h> + #include "cmsys/Directory.hxx" -#include "cmsys/Process.h" #include "cmCTest.h" #include "cmCTestBuildCommand.h" @@ -40,6 +41,8 @@ #include "cmStateSnapshot.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmUVHandlePtr.h" +#include "cmUVProcessChain.h" #include "cmValue.h" #include "cmake.h" @@ -148,66 +151,65 @@ 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 - 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(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()); std::vector<char> out; std::vector<char> err; std::string line; - int pipe = - cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, err); - while (pipe != cmsysProcess_Pipe_None) { + auto pipe = + cmSystemTools::WaitForLine(&process.GetLoop(), outPipe, errPipe, line, + std::chrono::seconds(100), out, err); + while (pipe != cmSystemTools::WaitForLineResult::None) { cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Output: " << line << "\n"); - if (pipe == cmsysProcess_Pipe_STDERR) { + if (pipe == cmSystemTools::WaitForLineResult::STDERR) { 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"); } - pipe = cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, - err); + pipe = + cmSystemTools::WaitForLine(&process.GetLoop(), outPipe, errPipe, line, + std::chrono::seconds(100), out, err); } // Properly handle output of the build command - cmsysProcess_WaitForExit(cp, nullptr); - int result = cmsysProcess_GetState(cp); + process.Wait(); + auto const& status = process.GetStatus(0); + auto result = status.GetException(); int retVal = 0; bool failed = false; - 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; + 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; } - cmsysProcess_Delete(cp); if (failed) { std::ostringstream message; message << "Error running command: ["; - message << result << "] "; + message << static_cast<int>(result.first) << "] "; for (const char* arg : argv) { if (arg) { message << arg << " "; diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 2bdc928..861ca31 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -31,6 +31,8 @@ #include "cmProcessOutput.h" #include "cmRange.h" #include "cmStringAlgorithms.h" +#include "cmUVHandlePtr.h" +#include "cmUVStream.h" #include "cmValue.h" #if !defined(CMAKE_BOOTSTRAP) @@ -59,12 +61,14 @@ #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> @@ -2213,9 +2217,10 @@ bool cmSystemTools::ListTar(const std::string& outFileName, #endif } -int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line, - cmDuration timeout, std::vector<char>& out, - std::vector<char>& err) +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) { line.clear(); auto outiter = out.begin(); @@ -2237,7 +2242,7 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line, line.append(out.data(), length); } 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); } err.erase(err.begin(), erriter + 1); - return cmsysProcess_Pipe_STDERR; + return WaitForLineResult::STDERR; } } // No newlines found. Wait for more data from the process. - int length; - char* data; - double timeoutAsDbl = timeout.count(); - int pipe = - cmsysProcess_WaitForData(process, &data, &length, &timeoutAsDbl); - if (pipe == cmsysProcess_Pipe_Timeout) { + 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) { // Timeout has been exceeded. - return pipe; + return WaitForLineResult::Timeout; } - if (pipe == cmsysProcess_Pipe_STDOUT) { - processOutput.DecodeText(data, length, strdata, 1); + if (outData.Read) { + processOutput.DecodeText(outData.Buffer.data(), outData.Buffer.size(), + 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 (pipe == cmsysProcess_Pipe_STDERR) { - processOutput.DecodeText(data, length, strdata, 2); + } else if (errData.Read) { + processOutput.DecodeText(errData.Buffer.data(), errData.Buffer.size(), + 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 (pipe == cmsysProcess_Pipe_None) { + } else if (outData.Finished && errData.Finished) { // Both stdout and stderr pipes have broken. Return leftover data. processOutput.DecodeText(std::string(), strdata, 1); if (!strdata.empty()) { @@ -2298,14 +2336,20 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line, if (!out.empty()) { line.append(out.data(), outiter - out.begin()); out.erase(out.begin(), out.end()); - return cmsysProcess_Pipe_STDOUT; + return WaitForLineResult::STDOUT; } if (!err.empty()) { line.append(err.data(), erriter - err.begin()); 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); } } } diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 9563fd6..c3b8525 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -18,6 +18,8 @@ #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 @@ -339,10 +341,20 @@ public: */ static void ReportLastSystemError(const char* m); - /** a general output handler for cmsysProcess */ - static int WaitForLine(cmsysProcess* process, std::string& line, - cmDuration timeout, std::vector<char>& out, - std::vector<char>& err); + 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); static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; } static bool GetForceUnixPaths() { return s_ForceUnixPaths; } diff --git a/Tests/CMakeLib/testUVProcessChainHelper.cxx b/Tests/CMakeLib/testUVProcessChainHelper.cxx index fcc45b0..b53cac4 100644 --- a/Tests/CMakeLib/testUVProcessChainHelper.cxx +++ b/Tests/CMakeLib/testUVProcessChainHelper.cxx @@ -7,10 +7,6 @@ #include <string> #include <thread> -#ifdef _WIN32 -# include <windows.h> -#endif - #include "cmSystemTools.h" static std::string getStdin() |