cmCTest: Replace cmsysProcess with cmUVProcessChain
This commit is contained in:
parent
50a6e78a82
commit
b15ad7ebb6
@ -7,8 +7,6 @@
|
||||
#include <cstring>
|
||||
#include <ratio>
|
||||
|
||||
#include "cmsys/Process.h"
|
||||
|
||||
#include "cmBuildOptions.h"
|
||||
#include "cmCTest.h"
|
||||
#include "cmCTestTestHandler.h"
|
||||
@ -308,12 +306,11 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<const char*> testCommand;
|
||||
testCommand.push_back(fullPath.c_str());
|
||||
std::vector<std::string> testCommand;
|
||||
testCommand.push_back(fullPath);
|
||||
for (std::string const& testCommandArg : this->TestCommandArgs) {
|
||||
testCommand.push_back(testCommandArg.c_str());
|
||||
testCommand.push_back(testCommandArg);
|
||||
}
|
||||
testCommand.push_back(nullptr);
|
||||
std::string outs;
|
||||
int retval = 0;
|
||||
// run the test from the this->BuildRunDir if set
|
||||
@ -349,10 +346,10 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
|
||||
}
|
||||
}
|
||||
|
||||
int runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr,
|
||||
remainingTime, nullptr);
|
||||
bool runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr,
|
||||
remainingTime, nullptr);
|
||||
|
||||
if (runTestRes != cmsysProcess_State_Exited || retval != 0) {
|
||||
if (!runTestRes || retval != 0) {
|
||||
out << "Test command failed: " << testCommand[0] << "\n";
|
||||
retval = 1;
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ int cmCTestConfigureHandler::ProcessHandler()
|
||||
auto elapsed_time_start = std::chrono::steady_clock::now();
|
||||
std::string output;
|
||||
int retVal = 0;
|
||||
int res = 0;
|
||||
bool res = false;
|
||||
if (!this->CTest->GetShowOnly()) {
|
||||
cmGeneratedFileStream os;
|
||||
if (!this->StartResultingXML(cmCTest::PartConfigure, "Configure", os)) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@ -24,13 +25,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)
|
||||
@ -64,6 +65,9 @@
|
||||
#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"
|
||||
@ -1074,9 +1078,9 @@ int cmCTest::GetTestModelFromString(const std::string& str)
|
||||
// ######################################################################
|
||||
// ######################################################################
|
||||
|
||||
int cmCTest::RunMakeCommand(const std::string& command, std::string& output,
|
||||
int* retVal, const char* dir, cmDuration timeout,
|
||||
std::ostream& ofs, Encoding encoding)
|
||||
bool 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);
|
||||
@ -1085,107 +1089,107 @@ int 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 (char const* arg : argv) {
|
||||
if (!arg) {
|
||||
break;
|
||||
}
|
||||
for (auto const& arg : args) {
|
||||
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, " \"" << arg << "\"");
|
||||
}
|
||||
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, std::endl);
|
||||
|
||||
// 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.count());
|
||||
cmsysProcess_Execute(cp);
|
||||
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());
|
||||
|
||||
// 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);
|
||||
while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
|
||||
processOutput.DecodeText(data, length, strdata);
|
||||
for (char& cc : strdata) {
|
||||
if (cc == 0) {
|
||||
cc = '\n';
|
||||
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';
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
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());
|
||||
}
|
||||
}
|
||||
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_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());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
bool finished = chain.Wait(static_cast<uint64_t>(timeout.count() * 1000.0));
|
||||
cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
|
||||
" Size of output: " << int(double(output.size()) / 1024.0) << "K"
|
||||
<< std::endl);
|
||||
|
||||
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) {
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
||||
cmsysProcess_Delete(cp);
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
@ -1193,9 +1197,10 @@ int cmCTest::RunMakeCommand(const std::string& command, std::string& output,
|
||||
// ######################################################################
|
||||
// ######################################################################
|
||||
|
||||
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 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)
|
||||
{
|
||||
bool modifyEnv = (environment && !environment->empty());
|
||||
|
||||
@ -1234,19 +1239,16 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
|
||||
inst.SetStreams(&oss, &oss);
|
||||
|
||||
std::vector<std::string> args;
|
||||
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);
|
||||
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)));
|
||||
}
|
||||
args.emplace_back(i);
|
||||
}
|
||||
if (log) {
|
||||
*log << "* Run internal CTest" << std::endl;
|
||||
@ -1272,7 +1274,7 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
|
||||
<< std::endl);
|
||||
}
|
||||
|
||||
return cmsysProcess_State_Exited;
|
||||
return true;
|
||||
}
|
||||
std::vector<char> tempOutput;
|
||||
if (output) {
|
||||
@ -1285,41 +1287,43 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
|
||||
cmSystemTools::AppendEnv(*environment);
|
||||
}
|
||||
|
||||
cmsysProcess* cp = cmsysProcess_New();
|
||||
cmsysProcess_SetCommand(cp, argv.data());
|
||||
cmUVProcessChainBuilder builder;
|
||||
builder.AddCommand(argv).SetMergedBuiltinStreams();
|
||||
cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
|
||||
if (cmSystemTools::GetRunCommandHideConsole()) {
|
||||
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
|
||||
}
|
||||
auto chain = builder.Start();
|
||||
|
||||
cmsysProcess_SetTimeout(cp, timeout.count());
|
||||
cmsysProcess_Execute(cp);
|
||||
|
||||
char* data;
|
||||
int length;
|
||||
cmProcessOutput processOutput(encoding);
|
||||
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());
|
||||
}
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cmsysProcess_WaitForExit(cp, nullptr);
|
||||
bool complete = chain.Wait(static_cast<uint64_t>(timeout.count() * 1000.0));
|
||||
processOutput.DecodeText(tempOutput, tempOutput);
|
||||
if (output && tempOutput.begin() != tempOutput.end()) {
|
||||
output->append(tempOutput.data(), tempOutput.size());
|
||||
@ -1327,33 +1331,41 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
|
||||
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
|
||||
"-- Process completed" << std::endl);
|
||||
|
||||
int result = cmsysProcess_GetState(cp);
|
||||
bool result = false;
|
||||
|
||||
if (result == cmsysProcess_State_Exited) {
|
||||
*retVal = cmsysProcess_GetExitValue(cp);
|
||||
if (*retVal != 0 && this->Impl->OutputTestOutputOnTestFailure) {
|
||||
this->OutputTestErrors(tempOutput);
|
||||
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;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
@ -3471,49 +3483,70 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
|
||||
stdOut->clear();
|
||||
stdErr->clear();
|
||||
|
||||
cmsysProcess* cp = cmsysProcess_New();
|
||||
cmsysProcess_SetCommand(cp, argv.data());
|
||||
cmsysProcess_SetWorkingDirectory(cp, dir);
|
||||
if (cmSystemTools::GetRunCommandHideConsole()) {
|
||||
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
|
||||
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_SetTimeout(cp, timeout.count());
|
||||
cmsysProcess_Execute(cp);
|
||||
|
||||
std::vector<char> tempOutput;
|
||||
bool outFinished = false;
|
||||
cm::uv_pipe_ptr outStream;
|
||||
std::vector<char> tempError;
|
||||
char* data;
|
||||
int length;
|
||||
bool errFinished = false;
|
||||
cm::uv_pipe_ptr errStream;
|
||||
cmProcessOutput processOutput(encoding);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (this->Impl->ExtraVerbose) {
|
||||
std::string strdata;
|
||||
processOutput.DecodeText(std::string(), strdata);
|
||||
if (!strdata.empty()) {
|
||||
cmSystemTools::Stdout(strdata);
|
||||
}
|
||||
}
|
||||
|
||||
cmsysProcess_WaitForExit(cp, nullptr);
|
||||
while (!timedOut && !chain.Finished()) {
|
||||
uv_run(&chain.GetLoop(), UV_RUN_ONCE);
|
||||
}
|
||||
if (!tempOutput.empty()) {
|
||||
processOutput.DecodeText(tempOutput, tempOutput);
|
||||
stdOut->append(tempOutput.data(), tempOutput.size());
|
||||
@ -3524,32 +3557,32 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
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) {
|
||||
if (timedOut) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -254,10 +254,10 @@ public:
|
||||
* Run command specialized for make and configure. Returns process status
|
||||
* and retVal is return value or exception.
|
||||
*/
|
||||
int RunMakeCommand(const std::string& command, std::string& output,
|
||||
int* retVal, const char* dir, cmDuration timeout,
|
||||
std::ostream& ofs,
|
||||
Encoding encoding = cmProcessOutput::Auto);
|
||||
bool 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.
|
||||
*/
|
||||
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);
|
||||
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);
|
||||
|
||||
/**
|
||||
* Get the handler object
|
||||
|
Loading…
Reference in New Issue
Block a user