cmake/Source/CTest/cmProcess.cxx

243 lines
7.1 KiB
C++
Raw Normal View History

2016-10-30 18:24:19 +01:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmProcess.h"
2016-07-09 11:21:54 +02:00
2017-07-20 19:35:53 +02:00
#include "cmConfigure.h"
#include "cmProcessOutput.h"
#include "cmSystemTools.h"
2016-10-30 18:24:19 +01:00
#include <iostream>
2009-10-04 10:30:41 +03:00
cmProcess::cmProcess()
{
2016-10-30 18:24:19 +01:00
this->Process = CM_NULLPTR;
2009-10-04 10:30:41 +03:00
this->Timeout = 0;
this->TotalTime = 0;
this->ExitValue = 0;
this->Id = 0;
this->StartTime = 0;
}
cmProcess::~cmProcess()
{
cmsysProcess_Delete(this->Process);
}
void cmProcess::SetCommand(const char* command)
{
this->Command = command;
}
void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
{
this->Arguments = args;
}
bool cmProcess::StartProcess()
{
2016-07-09 11:21:54 +02:00
if (this->Command.empty()) {
2009-10-04 10:30:41 +03:00
return false;
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
this->StartTime = cmSystemTools::GetTime();
this->ProcessArgs.clear();
// put the command as arg0
this->ProcessArgs.push_back(this->Command.c_str());
// now put the command arguments in
2016-07-09 11:21:54 +02:00
for (std::vector<std::string>::iterator i = this->Arguments.begin();
i != this->Arguments.end(); ++i) {
2009-10-04 10:30:41 +03:00
this->ProcessArgs.push_back(i->c_str());
2016-07-09 11:21:54 +02:00
}
2016-10-30 18:24:19 +01:00
this->ProcessArgs.push_back(CM_NULLPTR); // null terminate the list
2009-10-04 10:30:41 +03:00
this->Process = cmsysProcess_New();
cmsysProcess_SetCommand(this->Process, &*this->ProcessArgs.begin());
2016-07-09 11:21:54 +02:00
if (!this->WorkingDirectory.empty()) {
2009-10-04 10:30:41 +03:00
cmsysProcess_SetWorkingDirectory(this->Process,
this->WorkingDirectory.c_str());
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
cmsysProcess_SetTimeout(this->Process, this->Timeout);
2015-11-17 17:22:37 +01:00
cmsysProcess_SetOption(this->Process, cmsysProcess_Option_MergeOutput, 1);
2009-10-04 10:30:41 +03:00
cmsysProcess_Execute(this->Process);
2016-07-09 11:21:54 +02:00
return (cmsysProcess_GetState(this->Process) ==
cmsysProcess_State_Executing);
2009-10-04 10:30:41 +03:00
}
bool cmProcess::Buffer::GetLine(std::string& line)
{
// Scan for the next newline.
2016-07-09 11:21:54 +02:00
for (size_type sz = this->size(); this->Last != sz; ++this->Last) {
if ((*this)[this->Last] == '\n' || (*this)[this->Last] == '\0') {
2009-10-04 10:30:41 +03:00
// Extract the range first..last as a line.
const char* text = &*this->begin() + this->First;
size_type length = this->Last - this->First;
2016-07-09 11:21:54 +02:00
while (length && text[length - 1] == '\r') {
length--;
}
2009-10-04 10:30:41 +03:00
line.assign(text, length);
// Start a new range for the next line.
++this->Last;
this->First = Last;
// Return the line extracted.
return true;
}
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
// Available data have been exhausted without a newline.
2016-07-09 11:21:54 +02:00
if (this->First != 0) {
2009-10-04 10:30:41 +03:00
// Move the partial line to the beginning of the buffer.
this->erase(this->begin(), this->begin() + this->First);
this->First = 0;
this->Last = this->size();
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
return false;
}
bool cmProcess::Buffer::GetLast(std::string& line)
{
// Return the partial last line, if any.
2016-07-09 11:21:54 +02:00
if (!this->empty()) {
2009-10-04 10:30:41 +03:00
line.assign(&*this->begin(), this->size());
this->First = this->Last = 0;
this->clear();
return true;
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
return false;
}
int cmProcess::GetNextOutputLine(std::string& line, double timeout)
{
2017-04-14 19:02:05 +02:00
cmProcessOutput processOutput(cmProcessOutput::UTF8);
std::string strdata;
2016-07-09 11:21:54 +02:00
for (;;) {
2009-10-04 10:30:41 +03:00
// Look for lines already buffered.
2016-07-09 11:21:54 +02:00
if (this->Output.GetLine(line)) {
2009-10-04 10:30:41 +03:00
return cmsysProcess_Pipe_STDOUT;
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
// Check for more data from the process.
char* data;
int length;
int p = cmsysProcess_WaitForData(this->Process, &data, &length, &timeout);
2016-07-09 11:21:54 +02:00
if (p == cmsysProcess_Pipe_Timeout) {
2009-10-04 10:30:41 +03:00
return cmsysProcess_Pipe_Timeout;
2016-10-30 18:24:19 +01:00
}
if (p == cmsysProcess_Pipe_STDOUT) {
2017-04-14 19:02:05 +02:00
processOutput.DecodeText(data, length, strdata);
this->Output.insert(this->Output.end(), strdata.begin(), strdata.end());
2016-10-30 18:24:19 +01:00
} else { // p == cmsysProcess_Pipe_None
2009-10-04 10:30:41 +03:00
// The process will provide no more data.
break;
}
2016-07-09 11:21:54 +02:00
}
2017-04-14 19:02:05 +02:00
processOutput.DecodeText(std::string(), strdata);
if (!strdata.empty()) {
this->Output.insert(this->Output.end(), strdata.begin(), strdata.end());
}
2009-10-04 10:30:41 +03:00
// Look for partial last lines.
2016-07-09 11:21:54 +02:00
if (this->Output.GetLast(line)) {
2009-10-04 10:30:41 +03:00
return cmsysProcess_Pipe_STDOUT;
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
// No more data. Wait for process exit.
2016-07-09 11:21:54 +02:00
if (!cmsysProcess_WaitForExit(this->Process, &timeout)) {
2009-10-04 10:30:41 +03:00
return cmsysProcess_Pipe_Timeout;
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
// Record exit information.
this->ExitValue = cmsysProcess_GetExitValue(this->Process);
this->TotalTime = cmSystemTools::GetTime() - this->StartTime;
2013-11-03 12:27:13 +02:00
// Because of a processor clock scew the runtime may become slightly
// negative. If someone changed the system clock while the process was
// running this may be even more. Make sure not to report a negative
// duration here.
2016-07-09 11:21:54 +02:00
if (this->TotalTime <= 0.0) {
2013-11-03 12:27:13 +02:00
this->TotalTime = 0.0;
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
// std::cerr << "Time to run: " << this->TotalTime << "\n";
return cmsysProcess_Pipe_None;
}
// return the process status
int cmProcess::GetProcessStatus()
{
2016-07-09 11:21:54 +02:00
if (!this->Process) {
2009-10-04 10:30:41 +03:00
return cmsysProcess_State_Exited;
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
return cmsysProcess_GetState(this->Process);
}
int cmProcess::ReportStatus()
{
int result = 1;
2016-07-09 11:21:54 +02:00
switch (cmsysProcess_GetState(this->Process)) {
case cmsysProcess_State_Starting: {
std::cerr << "cmProcess: Never started " << this->Command
<< " process.\n";
} break;
case cmsysProcess_State_Error: {
2013-03-16 19:13:01 +02:00
std::cerr << "cmProcess: Error executing " << this->Command
2016-07-09 11:21:54 +02:00
<< " process: " << cmsysProcess_GetErrorString(this->Process)
2009-10-04 10:30:41 +03:00
<< "\n";
2016-07-09 11:21:54 +02:00
} break;
case cmsysProcess_State_Exception: {
2009-10-04 10:30:41 +03:00
std::cerr << "cmProcess: " << this->Command
2016-07-09 11:21:54 +02:00
<< " process exited with an exception: ";
switch (cmsysProcess_GetExitException(this->Process)) {
case cmsysProcess_Exception_None: {
2009-10-04 10:30:41 +03:00
std::cerr << "None";
2016-07-09 11:21:54 +02:00
} break;
case cmsysProcess_Exception_Fault: {
2009-10-04 10:30:41 +03:00
std::cerr << "Segmentation fault";
2016-07-09 11:21:54 +02:00
} break;
case cmsysProcess_Exception_Illegal: {
2009-10-04 10:30:41 +03:00
std::cerr << "Illegal instruction";
2016-07-09 11:21:54 +02:00
} break;
case cmsysProcess_Exception_Interrupt: {
2009-10-04 10:30:41 +03:00
std::cerr << "Interrupted by user";
2016-07-09 11:21:54 +02:00
} break;
case cmsysProcess_Exception_Numerical: {
2009-10-04 10:30:41 +03:00
std::cerr << "Numerical exception";
2016-07-09 11:21:54 +02:00
} break;
case cmsysProcess_Exception_Other: {
2009-10-04 10:30:41 +03:00
std::cerr << "Unknown";
2016-07-09 11:21:54 +02:00
} break;
}
2009-10-04 10:30:41 +03:00
std::cerr << "\n";
2016-07-09 11:21:54 +02:00
} break;
case cmsysProcess_State_Executing: {
std::cerr << "cmProcess: Never terminated " << this->Command
<< " process.\n";
} break;
case cmsysProcess_State_Exited: {
2009-10-04 10:30:41 +03:00
result = cmsysProcess_GetExitValue(this->Process);
2013-03-16 19:13:01 +02:00
std::cerr << "cmProcess: " << this->Command
2016-07-09 11:21:54 +02:00
<< " process exited with code " << result << "\n";
} break;
case cmsysProcess_State_Expired: {
2013-03-16 19:13:01 +02:00
std::cerr << "cmProcess: killed " << this->Command
2009-10-04 10:30:41 +03:00
<< " process due to timeout.\n";
2016-07-09 11:21:54 +02:00
} break;
case cmsysProcess_State_Killed: {
2009-10-04 10:30:41 +03:00
std::cerr << "cmProcess: killed " << this->Command << " process.\n";
2016-07-09 11:21:54 +02:00
} break;
}
2009-10-04 10:30:41 +03:00
return result;
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
2016-07-09 11:21:54 +02:00
void cmProcess::ChangeTimeout(double t)
{
this->Timeout = t;
cmsysProcess_SetTimeout(this->Process, this->Timeout);
2009-10-04 10:30:41 +03:00
}
2010-06-28 22:39:51 +03:00
2016-07-09 11:21:54 +02:00
void cmProcess::ResetStartTime()
{
cmsysProcess_ResetStartTime(this->Process);
2017-04-14 19:02:05 +02:00
this->StartTime = cmSystemTools::GetTime();
2016-07-09 11:21:54 +02:00
}
2010-06-28 22:39:51 +03:00
int cmProcess::GetExitException()
{
return cmsysProcess_GetExitException(this->Process);
}