ENH: Separate standard output and standard error for problematic commands
This commit is contained in:
parent
02f12a82be
commit
a95a4b000d
|
@ -155,6 +155,15 @@ int cmCTestCoverageHandler::ProcessHandler()
|
|||
std::string binaryDir = m_CTest->GetCTestConfiguration("BuildDirectory");
|
||||
std::string gcovCommand = m_CTest->GetCTestConfiguration("CoverageCommand");
|
||||
|
||||
cmGeneratedFileStream ofs;
|
||||
double elapsed_time_start = cmSystemTools::GetTime();
|
||||
if ( !m_CTest->OpenOutputFile("Temporary", "LastCoverage.log", ofs) )
|
||||
{
|
||||
cmCTestLog(m_CTest, ERROR_MESSAGE, "Cannot create LastCoverage.log file" << std::endl);
|
||||
}
|
||||
|
||||
ofs << "Performing coverage: " << elapsed_time_start << std::endl;
|
||||
|
||||
cmSystemTools::ConvertToUnixSlashes(sourceDir);
|
||||
cmSystemTools::ConvertToUnixSlashes(binaryDir);
|
||||
|
||||
|
@ -165,7 +174,6 @@ int cmCTestCoverageHandler::ProcessHandler()
|
|||
std::string gcovOutputRex2 = "^Creating (.*\\.gcov)\\.";
|
||||
|
||||
cmCTestLog(m_CTest, HANDLER_OUTPUT, "Performing coverage" << std::endl);
|
||||
double elapsed_time_start = cmSystemTools::GetTime();
|
||||
|
||||
std::string coverage_start_time = m_CTest->CurrentTime();
|
||||
|
||||
|
@ -204,19 +212,26 @@ int cmCTestCoverageHandler::ProcessHandler()
|
|||
std::string command = "\"" + gcovCommand + "\" -l -o \"" + fileDir + "\" \"" + *it + "\"";
|
||||
cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, command.c_str() << std::endl);
|
||||
std::string output = "";
|
||||
std::string errors = "";
|
||||
int retVal = 0;
|
||||
int res = cmSystemTools::RunSingleCommand(command.c_str(), &output,
|
||||
&retVal, tempDir.c_str(),
|
||||
false, 0 /*m_TimeOut*/);
|
||||
ofs << "* Run coverage for: " << fileDir.c_str() << std::endl;
|
||||
ofs << " Command: " << command.c_str() << std::endl;
|
||||
int res = m_CTest->RunCommand(command.c_str(), &output, &errors,
|
||||
&retVal, tempDir.c_str(), 0 /*m_TimeOut*/);
|
||||
|
||||
ofs << " Output: " << output.c_str() << std::endl;
|
||||
ofs << " Errors: " << errors.c_str() << std::endl;
|
||||
if ( ! res )
|
||||
{
|
||||
cmCTestLog(m_CTest, ERROR_MESSAGE, "Problem running coverage on file: " << it->c_str() << std::endl);
|
||||
cmCTestLog(m_CTest, ERROR_MESSAGE, "Command produced error: " << error << std::endl);
|
||||
error ++;
|
||||
continue;
|
||||
}
|
||||
if ( retVal != 0 )
|
||||
{
|
||||
cmCTestLog(m_CTest, ERROR_MESSAGE, "Coverage command returned: " << retVal << " while processing: " << it->c_str() << std::endl);
|
||||
cmCTestLog(m_CTest, ERROR_MESSAGE, "Command produced error: " << error << std::endl);
|
||||
}
|
||||
std::vector<cmStdString> lines;
|
||||
std::vector<cmStdString>::iterator line;
|
||||
|
@ -232,7 +247,8 @@ int cmCTestCoverageHandler::ProcessHandler()
|
|||
file.substr(0, sourceDir.size()) == sourceDir &&
|
||||
file[sourceDir.size()] == '/' )
|
||||
{
|
||||
cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, " produced s: " << file << std::endl);
|
||||
cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, " produced s: " << file.c_str() << std::endl);
|
||||
ofs << " produced in source dir: " << file.c_str() << std::endl;
|
||||
cfile = file;
|
||||
}
|
||||
// Binary dir?
|
||||
|
@ -240,7 +256,8 @@ int cmCTestCoverageHandler::ProcessHandler()
|
|||
file.substr(0, binaryDir.size()) == binaryDir &&
|
||||
file[binaryDir.size()] == '/' )
|
||||
{
|
||||
cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, " produce b: " << file << std::endl);
|
||||
cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, " produce b: " << file.c_str() << std::endl);
|
||||
ofs << " produced in binary dir: " << file.c_str() << std::endl;
|
||||
cfile = file;
|
||||
}
|
||||
if ( cfile.empty() )
|
||||
|
@ -249,6 +266,9 @@ int cmCTestCoverageHandler::ProcessHandler()
|
|||
cmCTestLog(m_CTest, ERROR_MESSAGE, "File: [" << file << "]" << std::endl);
|
||||
cmCTestLog(m_CTest, ERROR_MESSAGE, "s: [" << file.substr(0, sourceDir.size()) << "]" << std::endl);
|
||||
cmCTestLog(m_CTest, ERROR_MESSAGE, "b: [" << file.substr(0, binaryDir.size()) << "]" << std::endl);
|
||||
ofs << " Something went wrong. Cannot find: " << file.c_str()
|
||||
<< " in source dir: " << sourceDir.c_str()
|
||||
<< " or binary dir: " << binaryDir.c_str() << std::endl;
|
||||
}
|
||||
}
|
||||
else if ( re2.find(line->c_str() ) )
|
||||
|
@ -258,6 +278,7 @@ int cmCTestCoverageHandler::ProcessHandler()
|
|||
{
|
||||
singleFileCoverageVector* vec = &totalCoverage[cfile];
|
||||
cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, " in file: " << fname << std::endl);
|
||||
ofs << " In file: " << fname << std::endl;
|
||||
std::ifstream ifile(fname.c_str());
|
||||
if ( ! ifile )
|
||||
{
|
||||
|
@ -299,6 +320,7 @@ int cmCTestCoverageHandler::ProcessHandler()
|
|||
else
|
||||
{
|
||||
cmCTestLog(m_CTest, ERROR_MESSAGE, "Unknown line: " << line->c_str() << std::endl);
|
||||
ofs << " Unknown line: " << line->c_str() << std::endl;
|
||||
error ++;
|
||||
}
|
||||
}
|
||||
|
@ -476,6 +498,14 @@ int cmCTestCoverageHandler::ProcessHandler()
|
|||
<< std::setprecision(2)
|
||||
<< (percent_coverage) << "%" << std::endl);
|
||||
|
||||
ofs << "\tCovered LOC: " << total_tested << std::endl
|
||||
<< "\tNot covered LOC: " << total_untested << std::endl
|
||||
<< "\tTotal LOC: " << total_lines << std::endl
|
||||
<< "\tPercentage Coverage: "
|
||||
<< std::setiosflags(std::ios::fixed)
|
||||
<< std::setprecision(2)
|
||||
<< (percent_coverage) << "%" << std::endl;
|
||||
|
||||
cmSystemTools::ChangeDirectory(currentDirectory.c_str());
|
||||
|
||||
if ( error )
|
||||
|
|
|
@ -308,6 +308,7 @@ int cmCTestUpdateHandler::ProcessHandler()
|
|||
int svn_use_status = 0;
|
||||
|
||||
std::string goutput;
|
||||
std::string errors;
|
||||
int retVal = 0;
|
||||
bool res = true;
|
||||
|
||||
|
@ -320,9 +321,13 @@ int cmCTestUpdateHandler::ProcessHandler()
|
|||
cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, "* Get repository information: " << command.c_str() << std::endl);
|
||||
if ( !m_CTest->GetShowOnly() )
|
||||
{
|
||||
res = cmSystemTools::RunSingleCommand(command.c_str(), &goutput,
|
||||
&retVal, sourceDirectory,
|
||||
m_HandlerVerbose, 0 /*m_TimeOut*/);
|
||||
ofs << "* Get repository information" << std::endl;
|
||||
ofs << " Command: " << command.c_str() << std::endl;
|
||||
res = m_CTest->RunCommand(command.c_str(), &goutput, &errors,
|
||||
&retVal, sourceDirectory, 0 /*m_TimeOut*/);
|
||||
|
||||
ofs << " Output: " << goutput.c_str() << std::endl;
|
||||
ofs << " Errors: " << errors.c_str() << std::endl;
|
||||
if ( ofs )
|
||||
{
|
||||
ofs << "--- Update information ---" << std::endl;
|
||||
|
@ -373,22 +378,31 @@ int cmCTestUpdateHandler::ProcessHandler()
|
|||
case cmCTestUpdateHandler::e_CVS:
|
||||
command = updateCommand + " -z3 update " + updateOptions +
|
||||
" " + extra_update_opts;
|
||||
res = cmSystemTools::RunSingleCommand(command.c_str(), &goutput,
|
||||
&retVal, sourceDirectory,
|
||||
m_HandlerVerbose, 0 /*m_TimeOut*/);
|
||||
ofs << "* Update repository: " << std::endl;
|
||||
ofs << " Command: " << command.c_str() << std::endl;
|
||||
res = m_CTest->RunCommand(command.c_str(), &goutput, &errors,
|
||||
&retVal, sourceDirectory, 0 /*m_TimeOut*/);
|
||||
ofs << " Output: " << goutput.c_str() << std::endl;
|
||||
ofs << " Errors: " << errors.c_str() << std::endl;
|
||||
break;
|
||||
case cmCTestUpdateHandler::e_SVN:
|
||||
{
|
||||
std::string partialOutput;
|
||||
command = updateCommand + " update " + updateOptions +
|
||||
" " + extra_update_opts;
|
||||
bool res1 = cmSystemTools::RunSingleCommand(command.c_str(), &partialOutput,
|
||||
&retVal, sourceDirectory,
|
||||
m_HandlerVerbose, 0 /*m_TimeOut*/);
|
||||
ofs << "* Update repository: " << std::endl;
|
||||
ofs << " Command: " << command.c_str() << std::endl;
|
||||
bool res1 = m_CTest->RunCommand(command.c_str(), &partialOutput, &errors,
|
||||
&retVal, sourceDirectory, 0 /*m_TimeOut*/);
|
||||
ofs << " Output: " << partialOutput.c_str() << std::endl;
|
||||
ofs << " Errors: " << errors.c_str() << std::endl;
|
||||
command = updateCommand + " status";
|
||||
res = cmSystemTools::RunSingleCommand(command.c_str(), &partialOutput,
|
||||
&retVal, sourceDirectory,
|
||||
m_HandlerVerbose, 0 /*m_TimeOut*/);
|
||||
ofs << "* Status repository: " << std::endl;
|
||||
ofs << " Command: " << command.c_str() << std::endl;
|
||||
res = m_CTest->RunCommand(command.c_str(), &partialOutput, &errors,
|
||||
&retVal, sourceDirectory, 0 /*m_TimeOut*/);
|
||||
ofs << " Output: " << partialOutput.c_str() << std::endl;
|
||||
ofs << " Errors: " << errors.c_str() << std::endl;
|
||||
goutput += partialOutput;
|
||||
res = res && res1;
|
||||
}
|
||||
|
@ -505,9 +519,12 @@ int cmCTestUpdateHandler::ProcessHandler()
|
|||
}
|
||||
cmCTestLog(m_CTest, DEBUG, "Do log: " << logcommand << std::endl);
|
||||
cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, "* Get file update information: " << logcommand.c_str() << std::endl);
|
||||
res = cmSystemTools::RunSingleCommand(logcommand.c_str(), &output,
|
||||
&retVal, sourceDirectory,
|
||||
m_HandlerVerbose, 0 /*m_TimeOut*/);
|
||||
ofs << "* Get log information for file: " << file << std::endl;
|
||||
ofs << " Command: " << logcommand.c_str() << std::endl;
|
||||
res = m_CTest->RunCommand(logcommand.c_str(), &output, &errors,
|
||||
&retVal, sourceDirectory, 0 /*m_TimeOut*/);
|
||||
ofs << " Output: " << output.c_str() << std::endl;
|
||||
ofs << " Errors: " << errors.c_str() << std::endl;
|
||||
if ( ofs )
|
||||
{
|
||||
ofs << output << std::endl;
|
||||
|
|
|
@ -1786,6 +1786,113 @@ bool cmCTest::SetCTestConfigurationFromCMakeVariable(cmMakefile* mf, const char*
|
|||
return true;
|
||||
}
|
||||
|
||||
bool cmCTest::RunCommand(
|
||||
const char* command,
|
||||
std::string* stdOut,
|
||||
std::string* stdErr,
|
||||
int *retVal,
|
||||
const char* dir,
|
||||
double timeout)
|
||||
{
|
||||
std::vector<cmStdString> args = cmSystemTools::ParseArguments(command);
|
||||
|
||||
if(args.size() < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<const char*> argv;
|
||||
for(std::vector<cmStdString>::const_iterator a = args.begin();
|
||||
a != args.end(); ++a)
|
||||
{
|
||||
argv.push_back(a->c_str());
|
||||
}
|
||||
argv.push_back(0);
|
||||
|
||||
*stdOut = "";
|
||||
*stdErr = "";
|
||||
|
||||
cmsysProcess* cp = cmsysProcess_New();
|
||||
cmsysProcess_SetCommand(cp, &*argv.begin());
|
||||
cmsysProcess_SetWorkingDirectory(cp, dir);
|
||||
if(cmSystemTools::GetRunCommandHideConsole())
|
||||
{
|
||||
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
|
||||
}
|
||||
cmsysProcess_SetTimeout(cp, timeout);
|
||||
cmsysProcess_Execute(cp);
|
||||
|
||||
std::vector<char> tempOutput;
|
||||
std::vector<char> tempError;
|
||||
char* data;
|
||||
int length;
|
||||
int res;
|
||||
bool done = false;
|
||||
while(!done)
|
||||
{
|
||||
res = cmsysProcess_WaitForData(cp, &data, &length, 0);
|
||||
switch ( res )
|
||||
{
|
||||
case cmsysProcess_Pipe_STDOUT:
|
||||
tempOutput.insert(tempOutput.end(), data, data+length);
|
||||
break;
|
||||
case cmsysProcess_Pipe_STDERR:
|
||||
tempError.insert(tempError.end(), data, data+length);
|
||||
break;
|
||||
default:
|
||||
done = true;
|
||||
}
|
||||
if(m_ExtraVerbose)
|
||||
{
|
||||
cmSystemTools::Stdout(data, length);
|
||||
}
|
||||
}
|
||||
|
||||
cmsysProcess_WaitForExit(cp, 0);
|
||||
stdOut->append(&*tempOutput.begin(), tempOutput.size());
|
||||
stdErr->append(&*tempError.begin(), tempError.size());
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
cmsysProcess_Delete(cp);
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void cmCTest::SetOutputLogFileName(const char* name)
|
||||
{
|
||||
|
|
|
@ -140,7 +140,31 @@ public:
|
|||
|
||||
///! Should we only show what we would do?
|
||||
bool GetShowOnly();
|
||||
|
||||
|
||||
/**
|
||||
* Run a single executable command and put the stdout and stderr
|
||||
* in output.
|
||||
*
|
||||
* If verbose is false, no user-viewable output from the program
|
||||
* being run will be generated.
|
||||
*
|
||||
* If timeout is specified, the command will be terminated after
|
||||
* timeout expires. Timeout is specified in seconds.
|
||||
*
|
||||
* Argument retVal should be a pointer to the location where the
|
||||
* exit code will be stored. If the retVal is not specified and
|
||||
* the program exits with a code other than 0, then the this
|
||||
* function will return false.
|
||||
*
|
||||
* If the command has spaces in the path the caller MUST call
|
||||
* cmSystemTools::ConvertToRunCommandPath on the command before passing
|
||||
* it into this function or it will not work. The command must be correctly
|
||||
* escaped for this to with spaces.
|
||||
*/
|
||||
bool RunCommand(const char* command,
|
||||
std::string* stdOut, std::string* stdErr,
|
||||
int* retVal = 0, const char* dir = 0, double timeout = 0.0);
|
||||
|
||||
//! Start CTest XML output file
|
||||
void StartXML(std::ostream& ostr);
|
||||
|
||||
|
|
Loading…
Reference in New Issue