cmCTest: Replace cmsysProcess with cmUVProcessChain
This commit is contained in:
parent
50a6e78a82
commit
b15ad7ebb6
@ -7,8 +7,6 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <ratio>
|
#include <ratio>
|
||||||
|
|
||||||
#include "cmsys/Process.h"
|
|
||||||
|
|
||||||
#include "cmBuildOptions.h"
|
#include "cmBuildOptions.h"
|
||||||
#include "cmCTest.h"
|
#include "cmCTest.h"
|
||||||
#include "cmCTestTestHandler.h"
|
#include "cmCTestTestHandler.h"
|
||||||
@ -308,12 +306,11 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const char*> testCommand;
|
std::vector<std::string> testCommand;
|
||||||
testCommand.push_back(fullPath.c_str());
|
testCommand.push_back(fullPath);
|
||||||
for (std::string const& testCommandArg : this->TestCommandArgs) {
|
for (std::string const& testCommandArg : this->TestCommandArgs) {
|
||||||
testCommand.push_back(testCommandArg.c_str());
|
testCommand.push_back(testCommandArg);
|
||||||
}
|
}
|
||||||
testCommand.push_back(nullptr);
|
|
||||||
std::string outs;
|
std::string outs;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
// run the test from the this->BuildRunDir if set
|
// 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,
|
bool runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr,
|
||||||
remainingTime, nullptr);
|
remainingTime, nullptr);
|
||||||
|
|
||||||
if (runTestRes != cmsysProcess_State_Exited || retval != 0) {
|
if (!runTestRes || retval != 0) {
|
||||||
out << "Test command failed: " << testCommand[0] << "\n";
|
out << "Test command failed: " << testCommand[0] << "\n";
|
||||||
retval = 1;
|
retval = 1;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ int cmCTestConfigureHandler::ProcessHandler()
|
|||||||
auto elapsed_time_start = std::chrono::steady_clock::now();
|
auto elapsed_time_start = std::chrono::steady_clock::now();
|
||||||
std::string output;
|
std::string output;
|
||||||
int retVal = 0;
|
int retVal = 0;
|
||||||
int res = 0;
|
bool res = false;
|
||||||
if (!this->CTest->GetShowOnly()) {
|
if (!this->CTest->GetShowOnly()) {
|
||||||
cmGeneratedFileStream os;
|
cmGeneratedFileStream os;
|
||||||
if (!this->StartResultingXML(cmCTest::PartConfigure, "Configure", os)) {
|
if (!this->StartResultingXML(cmCTest::PartConfigure, "Configure", os)) {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@ -24,13 +25,13 @@
|
|||||||
#include <cmext/string_view>
|
#include <cmext/string_view>
|
||||||
|
|
||||||
#include <cm3p/curl/curl.h>
|
#include <cm3p/curl/curl.h>
|
||||||
|
#include <cm3p/uv.h>
|
||||||
#include <cm3p/zlib.h>
|
#include <cm3p/zlib.h>
|
||||||
|
|
||||||
#include "cmsys/Base64.h"
|
#include "cmsys/Base64.h"
|
||||||
#include "cmsys/Directory.hxx"
|
#include "cmsys/Directory.hxx"
|
||||||
#include "cmsys/FStream.hxx"
|
#include "cmsys/FStream.hxx"
|
||||||
#include "cmsys/Glob.hxx"
|
#include "cmsys/Glob.hxx"
|
||||||
#include "cmsys/Process.h"
|
|
||||||
#include "cmsys/RegularExpression.hxx"
|
#include "cmsys/RegularExpression.hxx"
|
||||||
#include "cmsys/SystemInformation.hxx"
|
#include "cmsys/SystemInformation.hxx"
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@ -64,6 +65,9 @@
|
|||||||
#include "cmStateTypes.h"
|
#include "cmStateTypes.h"
|
||||||
#include "cmStringAlgorithms.h"
|
#include "cmStringAlgorithms.h"
|
||||||
#include "cmSystemTools.h"
|
#include "cmSystemTools.h"
|
||||||
|
#include "cmUVHandlePtr.h"
|
||||||
|
#include "cmUVProcessChain.h"
|
||||||
|
#include "cmUVStream.h"
|
||||||
#include "cmValue.h"
|
#include "cmValue.h"
|
||||||
#include "cmVersion.h"
|
#include "cmVersion.h"
|
||||||
#include "cmVersionConfig.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,
|
bool cmCTest::RunMakeCommand(const std::string& command, std::string& output,
|
||||||
int* retVal, const char* dir, cmDuration timeout,
|
int* retVal, const char* dir, cmDuration timeout,
|
||||||
std::ostream& ofs, Encoding encoding)
|
std::ostream& ofs, Encoding encoding)
|
||||||
{
|
{
|
||||||
// First generate the command and arguments
|
// First generate the command and arguments
|
||||||
std::vector<std::string> args = cmSystemTools::ParseArguments(command);
|
std::vector<std::string> args = cmSystemTools::ParseArguments(command);
|
||||||
@ -1085,107 +1089,107 @@ int cmCTest::RunMakeCommand(const std::string& command, std::string& output,
|
|||||||
return false;
|
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();
|
output.clear();
|
||||||
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Run command:");
|
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Run command:");
|
||||||
for (char const* arg : argv) {
|
for (auto const& arg : args) {
|
||||||
if (!arg) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, " \"" << arg << "\"");
|
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, " \"" << arg << "\"");
|
||||||
}
|
}
|
||||||
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, std::endl);
|
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, std::endl);
|
||||||
|
|
||||||
// Now create process object
|
// Now create process object
|
||||||
cmsysProcess* cp = cmsysProcess_New();
|
cmUVProcessChainBuilder builder;
|
||||||
cmsysProcess_SetCommand(cp, argv.data());
|
builder.AddCommand(args).SetMergedBuiltinStreams();
|
||||||
cmsysProcess_SetWorkingDirectory(cp, dir);
|
if (dir) {
|
||||||
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
|
builder.SetWorkingDirectory(dir);
|
||||||
cmsysProcess_SetTimeout(cp, timeout.count());
|
}
|
||||||
cmsysProcess_Execute(cp);
|
auto chain = builder.Start();
|
||||||
|
cm::uv_pipe_ptr outputStream;
|
||||||
|
outputStream.init(chain.GetLoop(), 0);
|
||||||
|
uv_pipe_open(outputStream, chain.OutputStream());
|
||||||
|
|
||||||
// Initialize tick's
|
// Initialize tick's
|
||||||
std::string::size_type tick = 0;
|
std::string::size_type tick = 0;
|
||||||
std::string::size_type tick_len = 1024;
|
std::string::size_type tick_len = 1024;
|
||||||
std::string::size_type tick_line_len = 50;
|
std::string::size_type tick_line_len = 50;
|
||||||
|
|
||||||
char* data;
|
|
||||||
int length;
|
|
||||||
cmProcessOutput processOutput(encoding);
|
cmProcessOutput processOutput(encoding);
|
||||||
std::string strdata;
|
|
||||||
cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
|
cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
|
||||||
" Each . represents " << tick_len
|
" Each . represents " << tick_len
|
||||||
<< " bytes of output\n"
|
<< " bytes of output\n"
|
||||||
" "
|
" "
|
||||||
<< std::flush);
|
<< std::flush);
|
||||||
while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
|
auto outputHandle = cmUVStreamRead(
|
||||||
processOutput.DecodeText(data, length, strdata);
|
outputStream,
|
||||||
for (char& cc : strdata) {
|
[this, &processOutput, &output, &tick, &tick_len, &tick_line_len,
|
||||||
if (cc == 0) {
|
&ofs](std::vector<char> data) {
|
||||||
cc = '\n';
|
std::string strdata;
|
||||||
|
processOutput.DecodeText(data.data(), data.size(), strdata);
|
||||||
|
for (char& cc : strdata) {
|
||||||
|
if (cc == 0) {
|
||||||
|
cc = '\n';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
output.append(strdata);
|
||||||
output.append(strdata);
|
while (output.size() > (tick * tick_len)) {
|
||||||
while (output.size() > (tick * tick_len)) {
|
tick++;
|
||||||
tick++;
|
cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, "." << std::flush);
|
||||||
cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, "." << std::flush);
|
if (tick % tick_line_len == 0 && tick > 0) {
|
||||||
if (tick % tick_line_len == 0 && tick > 0) {
|
cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
|
||||||
cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
|
" Size: " << int((double(output.size()) / 1024.0) + 1)
|
||||||
" Size: " << int((double(output.size()) / 1024.0) + 1)
|
<< "K\n " << std::flush);
|
||||||
<< "K\n " << std::flush);
|
}
|
||||||
}
|
}
|
||||||
}
|
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
|
||||||
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
|
cmCTestLogWrite(strdata.c_str(), strdata.size()));
|
||||||
cmCTestLogWrite(strdata.c_str(), strdata.size()));
|
if (ofs) {
|
||||||
if (ofs) {
|
ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
|
||||||
ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
|
}
|
||||||
}
|
},
|
||||||
}
|
[this, &processOutput, &output, &ofs]() {
|
||||||
processOutput.DecodeText(std::string(), strdata);
|
std::string strdata;
|
||||||
if (!strdata.empty()) {
|
processOutput.DecodeText(std::string(), strdata);
|
||||||
output.append(strdata);
|
if (!strdata.empty()) {
|
||||||
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
|
output.append(strdata);
|
||||||
cmCTestLogWrite(strdata.c_str(), strdata.size()));
|
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
|
||||||
if (ofs) {
|
cmCTestLogWrite(strdata.c_str(), strdata.size()));
|
||||||
ofs << 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,
|
cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
|
||||||
" Size of output: " << int(double(output.size()) / 1024.0) << "K"
|
" Size of output: " << int(double(output.size()) / 1024.0) << "K"
|
||||||
<< std::endl);
|
<< std::endl);
|
||||||
|
|
||||||
cmsysProcess_WaitForExit(cp, nullptr);
|
if (finished) {
|
||||||
|
auto const& status = chain.GetStatus(0);
|
||||||
int result = cmsysProcess_GetState(cp);
|
auto exception = status.GetException();
|
||||||
|
switch (exception.first) {
|
||||||
if (result == cmsysProcess_State_Exited) {
|
case cmUVProcessChain::ExceptionCode::None:
|
||||||
*retVal = cmsysProcess_GetExitValue(cp);
|
*retVal = static_cast<int>(status.ExitStatus);
|
||||||
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
|
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
|
||||||
"Command exited with the value: " << *retVal << std::endl);
|
"Command exited with the value: " << *retVal << std::endl);
|
||||||
} else if (result == cmsysProcess_State_Exception) {
|
break;
|
||||||
*retVal = cmsysProcess_GetExitException(cp);
|
case cmUVProcessChain::ExceptionCode::Spawn:
|
||||||
cmCTestLog(this, WARNING,
|
output += "\n*** ERROR executing: ";
|
||||||
"There was an exception: " << *retVal << std::endl);
|
output += exception.second;
|
||||||
} else if (result == cmsysProcess_State_Expired) {
|
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);
|
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 true;
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
@ -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,
|
bool cmCTest::RunTest(const std::vector<std::string>& argv,
|
||||||
int* retVal, std::ostream* log, cmDuration testTimeOut,
|
std::string* output, int* retVal, std::ostream* log,
|
||||||
std::vector<std::string>* environment, Encoding encoding)
|
cmDuration testTimeOut,
|
||||||
|
std::vector<std::string>* environment, Encoding encoding)
|
||||||
{
|
{
|
||||||
bool modifyEnv = (environment && !environment->empty());
|
bool modifyEnv = (environment && !environment->empty());
|
||||||
|
|
||||||
@ -1234,19 +1239,16 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
|
|||||||
inst.SetStreams(&oss, &oss);
|
inst.SetStreams(&oss, &oss);
|
||||||
|
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
for (char const* i : argv) {
|
for (auto const& i : argv) {
|
||||||
if (i) {
|
// make sure we pass the timeout in for any build and test
|
||||||
// make sure we pass the timeout in for any build and test
|
// invocations. Since --build-generator is required this is a
|
||||||
// invocations. Since --build-generator is required this is a
|
// good place to check for it, and to add the arguments in
|
||||||
// good place to check for it, and to add the arguments in
|
if (i == "--build-generator" && timeout != cmCTest::MaxDuration() &&
|
||||||
if (strcmp(i, "--build-generator") == 0 &&
|
timeout > cmDuration::zero()) {
|
||||||
timeout != cmCTest::MaxDuration() &&
|
args.emplace_back("--test-timeout");
|
||||||
timeout > cmDuration::zero()) {
|
args.push_back(std::to_string(cmDurationTo<unsigned int>(timeout)));
|
||||||
args.emplace_back("--test-timeout");
|
|
||||||
args.push_back(std::to_string(cmDurationTo<unsigned int>(timeout)));
|
|
||||||
}
|
|
||||||
args.emplace_back(i);
|
|
||||||
}
|
}
|
||||||
|
args.emplace_back(i);
|
||||||
}
|
}
|
||||||
if (log) {
|
if (log) {
|
||||||
*log << "* Run internal CTest" << std::endl;
|
*log << "* Run internal CTest" << std::endl;
|
||||||
@ -1272,7 +1274,7 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
|
|||||||
<< std::endl);
|
<< std::endl);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmsysProcess_State_Exited;
|
return true;
|
||||||
}
|
}
|
||||||
std::vector<char> tempOutput;
|
std::vector<char> tempOutput;
|
||||||
if (output) {
|
if (output) {
|
||||||
@ -1285,41 +1287,43 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
|
|||||||
cmSystemTools::AppendEnv(*environment);
|
cmSystemTools::AppendEnv(*environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmsysProcess* cp = cmsysProcess_New();
|
cmUVProcessChainBuilder builder;
|
||||||
cmsysProcess_SetCommand(cp, argv.data());
|
builder.AddCommand(argv).SetMergedBuiltinStreams();
|
||||||
cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
|
cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
|
||||||
if (cmSystemTools::GetRunCommandHideConsole()) {
|
auto chain = builder.Start();
|
||||||
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
cmsysProcess_SetTimeout(cp, timeout.count());
|
|
||||||
cmsysProcess_Execute(cp);
|
|
||||||
|
|
||||||
char* data;
|
|
||||||
int length;
|
|
||||||
cmProcessOutput processOutput(encoding);
|
cmProcessOutput processOutput(encoding);
|
||||||
std::string strdata;
|
cm::uv_pipe_ptr outputStream;
|
||||||
while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
|
outputStream.init(chain.GetLoop(), 0);
|
||||||
processOutput.DecodeText(data, length, strdata);
|
uv_pipe_open(outputStream, chain.OutputStream());
|
||||||
if (output) {
|
auto outputHandle = cmUVStreamRead(
|
||||||
cm::append(tempOutput, data, data + length);
|
outputStream,
|
||||||
}
|
[this, &processOutput, &output, &tempOutput,
|
||||||
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
|
&log](std::vector<char> data) {
|
||||||
cmCTestLogWrite(strdata.c_str(), strdata.size()));
|
std::string strdata;
|
||||||
if (log) {
|
processOutput.DecodeText(data.data(), data.size(), strdata);
|
||||||
log->write(strdata.c_str(), strdata.size());
|
if (output) {
|
||||||
}
|
cm::append(tempOutput, data.data(), data.data() + data.size());
|
||||||
}
|
}
|
||||||
processOutput.DecodeText(std::string(), strdata);
|
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
|
||||||
if (!strdata.empty()) {
|
cmCTestLogWrite(strdata.c_str(), strdata.size()));
|
||||||
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
|
if (log) {
|
||||||
cmCTestLogWrite(strdata.c_str(), strdata.size()));
|
log->write(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);
|
processOutput.DecodeText(tempOutput, tempOutput);
|
||||||
if (output && tempOutput.begin() != tempOutput.end()) {
|
if (output && tempOutput.begin() != tempOutput.end()) {
|
||||||
output->append(tempOutput.data(), tempOutput.size());
|
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,
|
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
|
||||||
"-- Process completed" << std::endl);
|
"-- Process completed" << std::endl);
|
||||||
|
|
||||||
int result = cmsysProcess_GetState(cp);
|
bool result = false;
|
||||||
|
|
||||||
if (result == cmsysProcess_State_Exited) {
|
if (complete) {
|
||||||
*retVal = cmsysProcess_GetExitValue(cp);
|
auto const& status = chain.GetStatus(0);
|
||||||
if (*retVal != 0 && this->Impl->OutputTestOutputOnTestFailure) {
|
auto exception = status.GetException();
|
||||||
this->OutputTestErrors(tempOutput);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
@ -3471,49 +3483,70 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
|
|||||||
stdOut->clear();
|
stdOut->clear();
|
||||||
stdErr->clear();
|
stdErr->clear();
|
||||||
|
|
||||||
cmsysProcess* cp = cmsysProcess_New();
|
cmUVProcessChainBuilder builder;
|
||||||
cmsysProcess_SetCommand(cp, argv.data());
|
builder.AddCommand(args)
|
||||||
cmsysProcess_SetWorkingDirectory(cp, dir);
|
.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
|
||||||
if (cmSystemTools::GetRunCommandHideConsole()) {
|
.SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
|
||||||
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
|
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;
|
std::vector<char> tempOutput;
|
||||||
|
bool outFinished = false;
|
||||||
|
cm::uv_pipe_ptr outStream;
|
||||||
std::vector<char> tempError;
|
std::vector<char> tempError;
|
||||||
char* data;
|
bool errFinished = false;
|
||||||
int length;
|
cm::uv_pipe_ptr errStream;
|
||||||
cmProcessOutput processOutput(encoding);
|
cmProcessOutput processOutput(encoding);
|
||||||
std::string strdata;
|
auto startRead = [this, &chain, &processOutput](
|
||||||
int res;
|
cm::uv_pipe_ptr& pipe, int stream,
|
||||||
bool done = false;
|
std::vector<char>& temp,
|
||||||
while (!done) {
|
bool& finished) -> std::unique_ptr<cmUVStreamReadHandle> {
|
||||||
res = cmsysProcess_WaitForData(cp, &data, &length, nullptr);
|
pipe.init(chain.GetLoop(), 0);
|
||||||
switch (res) {
|
uv_pipe_open(pipe, stream);
|
||||||
case cmsysProcess_Pipe_STDOUT:
|
return cmUVStreamRead(
|
||||||
cm::append(tempOutput, data, data + length);
|
pipe,
|
||||||
break;
|
[this, &temp, &processOutput](std::vector<char> data) {
|
||||||
case cmsysProcess_Pipe_STDERR:
|
cm::append(temp, data);
|
||||||
cm::append(tempError, data, data + length);
|
if (this->Impl->ExtraVerbose) {
|
||||||
break;
|
std::string strdata;
|
||||||
default:
|
processOutput.DecodeText(data.data(), data.size(), strdata);
|
||||||
done = true;
|
cmSystemTools::Stdout(strdata);
|
||||||
}
|
}
|
||||||
if ((res == cmsysProcess_Pipe_STDOUT || res == cmsysProcess_Pipe_STDERR) &&
|
},
|
||||||
this->Impl->ExtraVerbose) {
|
[&finished]() { finished = true; });
|
||||||
processOutput.DecodeText(data, length, strdata);
|
};
|
||||||
cmSystemTools::Stdout(strdata);
|
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) {
|
if (this->Impl->ExtraVerbose) {
|
||||||
|
std::string strdata;
|
||||||
processOutput.DecodeText(std::string(), strdata);
|
processOutput.DecodeText(std::string(), strdata);
|
||||||
if (!strdata.empty()) {
|
if (!strdata.empty()) {
|
||||||
cmSystemTools::Stdout(strdata);
|
cmSystemTools::Stdout(strdata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmsysProcess_WaitForExit(cp, nullptr);
|
while (!timedOut && !chain.Finished()) {
|
||||||
|
uv_run(&chain.GetLoop(), UV_RUN_ONCE);
|
||||||
|
}
|
||||||
if (!tempOutput.empty()) {
|
if (!tempOutput.empty()) {
|
||||||
processOutput.DecodeText(tempOutput, tempOutput);
|
processOutput.DecodeText(tempOutput, tempOutput);
|
||||||
stdOut->append(tempOutput.data(), tempOutput.size());
|
stdOut->append(tempOutput.data(), tempOutput.size());
|
||||||
@ -3524,32 +3557,32 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
|
if (timedOut) {
|
||||||
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) {
|
|
||||||
const char* error_str = "Process terminated due to timeout\n";
|
const char* error_str = "Process terminated due to timeout\n";
|
||||||
cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
|
cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
|
||||||
stdErr->append(error_str, strlen(error_str));
|
stdErr->append(error_str, strlen(error_str));
|
||||||
result = false;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,10 +254,10 @@ public:
|
|||||||
* Run command specialized for make and configure. Returns process status
|
* Run command specialized for make and configure. Returns process status
|
||||||
* and retVal is return value or exception.
|
* and retVal is return value or exception.
|
||||||
*/
|
*/
|
||||||
int RunMakeCommand(const std::string& command, std::string& output,
|
bool RunMakeCommand(const std::string& command, std::string& output,
|
||||||
int* retVal, const char* dir, cmDuration timeout,
|
int* retVal, const char* dir, cmDuration timeout,
|
||||||
std::ostream& ofs,
|
std::ostream& ofs,
|
||||||
Encoding encoding = cmProcessOutput::Auto);
|
Encoding encoding = cmProcessOutput::Auto);
|
||||||
|
|
||||||
/** Return the current tag */
|
/** Return the current tag */
|
||||||
std::string GetCurrentTag();
|
std::string GetCurrentTag();
|
||||||
@ -303,10 +303,10 @@ public:
|
|||||||
* environment variables prior to running the test. After running the test,
|
* environment variables prior to running the test. After running the test,
|
||||||
* environment variables are restored to their previous values.
|
* environment variables are restored to their previous values.
|
||||||
*/
|
*/
|
||||||
int RunTest(std::vector<const char*> args, std::string* output, int* retVal,
|
bool RunTest(const std::vector<std::string>& args, std::string* output,
|
||||||
std::ostream* logfile, cmDuration testTimeOut,
|
int* retVal, std::ostream* logfile, cmDuration testTimeOut,
|
||||||
std::vector<std::string>* environment,
|
std::vector<std::string>* environment,
|
||||||
Encoding encoding = cmProcessOutput::Auto);
|
Encoding encoding = cmProcessOutput::Auto);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the handler object
|
* Get the handler object
|
||||||
|
Loading…
Reference in New Issue
Block a user