Utils: Enhance Process::exitMessage()

... with stderr/stdout data, if requested.

Change-Id: Ia4aed9b342144d5358c5a91f4555bccb86b2eb7b
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Christian Kandeler
2025-04-15 11:27:23 +02:00
parent 523145f600
commit b1f64d0998
18 changed files with 55 additions and 57 deletions

View File

@@ -112,7 +112,7 @@ QString BuildableHelperLibrary::qtVersionForQMake(const FilePath &qmakePath)
qmake.setCommand({qmakePath, {"--version"}}); qmake.setCommand({qmakePath, {"--version"}});
qmake.runBlocking(5s); qmake.runBlocking(5s);
if (qmake.result() != ProcessResult::FinishedWithSuccess) { if (qmake.result() != ProcessResult::FinishedWithSuccess) {
qWarning() << qmake.exitMessage(); qWarning() << qmake.verboseExitMessage();
return QString(); return QString();
} }

View File

@@ -1588,9 +1588,26 @@ QString Process::exitMessage(const CommandLine &command, ProcessResult result,
return {}; return {};
} }
QString Process::exitMessage() const QString Process::exitMessage(FailureMessageFormat format) const
{ {
return exitMessage(commandLine(), result(), exitCode(), processDuration()); QString msg = exitMessage(commandLine(), result(), exitCode(), processDuration());
if (format == FailureMessageFormat::Plain || result() == ProcessResult::FinishedWithSuccess)
return msg;
if (format == FailureMessageFormat::WithStdErr
|| format == FailureMessageFormat::WithAllOutput) {
const QString stdErr = cleanedStdErr();
if (!stdErr.isEmpty()) {
msg.append('\n').append(Tr::tr("Standard error output was:")).append('\n')
.append(stdErr);
}
}
if (format == FailureMessageFormat::WithStdOut
|| format == FailureMessageFormat::WithAllOutput) {
const QString stdOut = cleanedStdOut();
if (!stdOut.isEmpty())
msg.append('\n').append(Tr::tr("Standard output was:")).append('\n').append(stdOut);
}
return msg;
} }
milliseconds Process::processDuration() const milliseconds Process::processDuration() const

View File

@@ -177,9 +177,11 @@ public:
const QStringList stdOutLines() const; // split, CR removed const QStringList stdOutLines() const; // split, CR removed
const QStringList stdErrLines() const; // split, CR removed const QStringList stdErrLines() const; // split, CR removed
enum class FailureMessageFormat { Plain, WithStdErr, WithStdOut, WithAllOutput };
static QString exitMessage(const CommandLine &command, ProcessResult result, int exitCode, static QString exitMessage(const CommandLine &command, ProcessResult result, int exitCode,
std::chrono::milliseconds duration); std::chrono::milliseconds duration);
QString exitMessage() const; QString exitMessage(FailureMessageFormat format = FailureMessageFormat::Plain) const;
QString verboseExitMessage() const { return exitMessage(FailureMessageFormat::WithAllOutput); }
std::chrono::milliseconds processDuration() const; std::chrono::milliseconds processDuration() const;
QString toStandaloneCommandLine() const; QString toStandaloneCommandLine() const;

View File

@@ -315,8 +315,7 @@ void AndroidCreateKeystoreCertificate::buttonBoxAccepted()
genKeyCertProc.runBlocking(15s); genKeyCertProc.runBlocking(15s);
if (genKeyCertProc.result() != ProcessResult::FinishedWithSuccess) { if (genKeyCertProc.result() != ProcessResult::FinishedWithSuccess) {
QMessageBox::critical(this, Tr::tr("Error"), QMessageBox::critical(this, Tr::tr("Error"), genKeyCertProc.verboseExitMessage());
genKeyCertProc.exitMessage() + '\n' + genKeyCertProc.allOutput());
return; return;
} }
accept(); accept();

View File

@@ -82,7 +82,7 @@ static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList &
cpp.setCommand(cmd); cpp.setCommand(cmd);
cpp.runBlocking(); cpp.runBlocking();
if (cpp.result() != ProcessResult::FinishedWithSuccess) { if (cpp.result() != ProcessResult::FinishedWithSuccess) {
qWarning() << cpp.exitMessage(); qWarning() << cpp.exitMessage(Process::FailureMessageFormat::WithStdErr);
return {}; return {};
} }

View File

@@ -250,7 +250,7 @@ static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringLis
cpp.runBlocking(); cpp.runBlocking();
if (cpp.result() != ProcessResult::FinishedWithSuccess) { if (cpp.result() != ProcessResult::FinishedWithSuccess) {
qWarning() << cpp.exitMessage(); qWarning() << cpp.exitMessage(Process::FailureMessageFormat::WithStdErr);
return {}; return {};
} }

View File

@@ -64,7 +64,7 @@ static Macros dumpPredefinedMacros(const FilePath &compiler, const Environment &
cpp.runBlocking(); cpp.runBlocking();
if (cpp.result() != ProcessResult::FinishedWithSuccess) { if (cpp.result() != ProcessResult::FinishedWithSuccess) {
qWarning() << cpp.exitMessage(); qWarning() << cpp.exitMessage(Process::FailureMessageFormat::WithStdErr);
return {}; return {};
} }
@@ -84,7 +84,7 @@ static HeaderPaths dumpHeaderPaths(const FilePath &compiler, const Environment &
cpp.runBlocking(); cpp.runBlocking();
if (cpp.result() != ProcessResult::FinishedWithSuccess) { if (cpp.result() != ProcessResult::FinishedWithSuccess) {
qWarning() << cpp.exitMessage(); qWarning() << cpp.exitMessage(Process::FailureMessageFormat::WithStdErr);
return {}; return {};
} }

View File

@@ -624,8 +624,8 @@ void CMakeTool::fetchFromCapabilities() const
m_introspection->m_haveCapabilitites = true; m_introspection->m_haveCapabilitites = true;
parseFromCapabilities(cmake.cleanedStdOut()); parseFromCapabilities(cmake.cleanedStdOut());
} else { } else {
qCCritical(cmakeToolLog) << "Fetching capabilities failed: " << cmake.commandLine() qCCritical(cmakeToolLog) << "Fetching capabilities failed: "
<< cmake.allOutput() << cmake.error() << cmake.errorString(); << cmake.verboseExitMessage();
m_introspection->m_haveCapabilitites = false; m_introspection->m_haveCapabilitites = false;
// In the rare case when "cmake -E capabilities" crashes / fails to run // In the rare case when "cmake -E capabilities" crashes / fails to run

View File

@@ -45,10 +45,12 @@ bool DockerApi::canConnect()
process.runBlocking(); process.runBlocking();
const bool success = process.result() == ProcessResult::FinishedWithSuccess; const bool success = process.result() == ProcessResult::FinishedWithSuccess;
if (!success) if (!success) {
qCWarning(dockerApiLog) << "Failed to connect to docker daemon:" << process.allOutput(); qCWarning(dockerApiLog) << "Failed to connect to docker daemon:"
else << process.verboseExitMessage();
} else {
qCInfo(dockerApiLog) << "'docker info' result:\n" << qPrintable(process.allOutput()); qCInfo(dockerApiLog) << "'docker info' result:\n" << qPrintable(process.allOutput());
}
return process.result() == ProcessResult::FinishedWithSuccess; return process.result() == ProcessResult::FinishedWithSuccess;
} }
@@ -139,9 +141,7 @@ QFuture<Utils::Result<QList<Network>>> DockerApi::networks()
if (process.result() != ProcessResult::FinishedWithSuccess) { if (process.result() != ProcessResult::FinishedWithSuccess) {
return make_unexpected( return make_unexpected(
Tr::tr("Failed to retrieve docker networks. Exit code: %1. Error: %2") Tr::tr("Failed to retrieve docker networks: %1").arg(process.verboseExitMessage()));
.arg(process.exitCode())
.arg(process.allOutput()));
} }
for (const auto &line : process.readAllStandardOutput().split('\n')) { for (const auto &line : process.readAllStandardOutput().split('\n')) {

View File

@@ -56,9 +56,8 @@ private:
if (createProcess.result() != ProcessResult::FinishedWithSuccess) { if (createProcess.result() != ProcessResult::FinishedWithSuccess) {
return make_unexpected( return make_unexpected(
Tr::tr("Failed creating Docker container. Exit code: %1, output: %2") Tr::tr("Failed creating Docker container: %1")
.arg(createProcess.exitCode()) .arg(createProcess.verboseExitMessage()));
.arg(createProcess.allOutput()));
} }
m_containerId = createProcess.cleanedStdOut().trimmed(); m_containerId = createProcess.cleanedStdOut().trimmed();

View File

@@ -1361,7 +1361,7 @@ Result<QPair<Utils::OsType, Utils::OsArch>> DockerDevicePrivate::osTypeAndArch()
{"image", "inspect", q->repoAndTag(), "--format", "{{.Os}}\t{{.Architecture}}"}}); {"image", "inspect", q->repoAndTag(), "--format", "{{.Os}}\t{{.Architecture}}"}});
proc.runBlocking(); proc.runBlocking();
if (proc.result() != ProcessResult::FinishedWithSuccess) if (proc.result() != ProcessResult::FinishedWithSuccess)
return make_unexpected(Tr::tr("Failed to inspect image: %1").arg(proc.allOutput())); return make_unexpected(Tr::tr("Failed to inspect image: %1").arg(proc.verboseExitMessage()));
const QString out = proc.cleanedStdOut().trimmed(); const QString out = proc.cleanedStdOut().trimmed();
const QStringList parts = out.split('\t'); const QStringList parts = out.split('\t');

View File

@@ -214,25 +214,10 @@ bool AbstractProcessStep::setupProcess(Process &process)
void AbstractProcessStep::handleProcessDone(const Process &process) void AbstractProcessStep::handleProcessDone(const Process &process)
{ {
const QString command = d->m_displayedParams->effectiveCommand().toUserOutput(); const OutputFormat format = process.result() == ProcessResult::FinishedWithSuccess
if (process.result() == ProcessResult::FinishedWithSuccess) { ? OutputFormat::NormalMessage
emit addOutput(Tr::tr("The process \"%1\" exited normally.").arg(command), : OutputFormat::ErrorMessage;
OutputFormat::NormalMessage); emit addOutput(process.exitMessage(), format);
} else if (process.result() == ProcessResult::FinishedWithError) {
emit addOutput(Tr::tr("The process \"%1\" exited with code %2.")
.arg(command, QString::number(process.exitCode())),
OutputFormat::ErrorMessage);
} else if (process.result() == ProcessResult::StartFailed) {
emit addOutput(Tr::tr("Could not start process \"%1\" %2.")
.arg(command, d->m_displayedParams->prettyArguments()),
OutputFormat::ErrorMessage);
const QString errorString = process.errorString();
if (!errorString.isEmpty())
emit addOutput(errorString, OutputFormat::ErrorMessage);
} else {
emit addOutput(Tr::tr("The process \"%1\" crashed.").arg(command),
OutputFormat::ErrorMessage);
}
} }
void AbstractProcessStep::setLowPriority() void AbstractProcessStep::setLowPriority()

View File

@@ -95,12 +95,9 @@ static Result<>
using namespace std::chrono_literals; using namespace std::chrono_literals;
process.runBlocking(30s, EventLoopMode::On); process.runBlocking(30s, EventLoopMode::On);
if (process.result() != Utils::ProcessResult::FinishedWithSuccess) { if (process.result() != Utils::ProcessResult::FinishedWithSuccess) {
QString errorMessage = QString("Generator script failed: %1").arg(process.exitMessage()); QString errorMessage = QString("Generator script failed: %1")
const QString stdErr = process.cleanedStdErr(); .arg(process.exitMessage(
if (!stdErr.isEmpty()) { Process::FailureMessageFormat::WithStdErr));
errorMessage.append(QLatin1Char('\n'));
errorMessage.append(stdErr);
}
return ResultError(errorMessage); return ResultError(errorMessage);
} }
if (stdOut) { if (stdOut) {

View File

@@ -172,9 +172,8 @@ static Result<QString> runGcc(
cpp.setCommand({gcc, arguments}); cpp.setCommand({gcc, arguments});
cpp.runBlocking(); cpp.runBlocking();
if (cpp.result() != ProcessResult::FinishedWithSuccess || cpp.exitCode() != 0) { if (cpp.result() != ProcessResult::FinishedWithSuccess || cpp.exitCode() != 0) {
return make_unexpected(QString("Compiler feature detection failure.\n%1\n%2") return make_unexpected(
.arg(cpp.exitMessage()) QString("Compiler feature detection failure.\n%1").arg(cpp.verboseExitMessage()));
.arg(cpp.allOutput()));
} }
return cpp.allOutput().trimmed(); return cpp.allOutput().trimmed();

View File

@@ -262,7 +262,7 @@ static QList<VisualStudioInstallation> detectVisualStudioFromVsWhere(const QStri
{"-products", "*", "-prerelease", "-legacy", "-format", "json", "-utf8"}}); {"-products", "*", "-prerelease", "-legacy", "-format", "json", "-utf8"}});
vsWhereProcess.runBlocking(5s); vsWhereProcess.runBlocking(5s);
if (vsWhereProcess.result() != ProcessResult::FinishedWithSuccess) { if (vsWhereProcess.result() != ProcessResult::FinishedWithSuccess) {
qWarning() << vsWhereProcess.exitMessage(); qWarning() << vsWhereProcess.verboseExitMessage();
return installations; return installations;
} }
@@ -2116,7 +2116,7 @@ std::optional<QString> MsvcToolchain::generateEnvironmentSettings(const Utils::E
run.runBlocking(1min); run.runBlocking(1min);
if (run.result() != ProcessResult::FinishedWithSuccess) { if (run.result() != ProcessResult::FinishedWithSuccess) {
const QString message = !run.cleanedStdErr().isEmpty() ? run.cleanedStdErr() : run.exitMessage(); const QString message = run.exitMessage(Process::FailureMessageFormat::WithStdErr);
qWarning().noquote() << message; qWarning().noquote() << message;
QString command = QDir::toNativeSeparators(batchFile); QString command = QDir::toNativeSeparators(batchFile);
if (!batchArgs.isEmpty()) if (!batchArgs.isEmpty())

View File

@@ -130,9 +130,9 @@ void PipInstallTask::handleDone()
m_future.reportFinished(); m_future.reportFinished();
const bool success = m_process.result() == ProcessResult::FinishedWithSuccess; const bool success = m_process.result() == ProcessResult::FinishedWithSuccess;
if (!success) { if (!success) {
Core::MessageManager::writeFlashing(Tr::tr("Installing \"%1\" failed with exit code %2.") Core::MessageManager::writeFlashing(Tr::tr("Installing \"%1\" failed:")
.arg(packagesDisplayName()) .arg(packagesDisplayName())
.arg(m_process.exitCode())); .arg(m_process.exitMessage()));
} }
emit finished(success); emit finished(success);
} }

View File

@@ -385,7 +385,7 @@ Environment LinuxDevicePrivate::getEnvironment()
if (getEnvProc.result() != ProcessResult::FinishedWithSuccess) { if (getEnvProc.result() != ProcessResult::FinishedWithSuccess) {
qCWarning(linuxDeviceLog) << "Failed to get environment variables from device:" qCWarning(linuxDeviceLog) << "Failed to get environment variables from device:"
<< getEnvProc.exitMessage() << getEnvProc.allOutput(); << getEnvProc.verboseExitMessage();
return {}; return {};
} }

View File

@@ -59,8 +59,8 @@ PublicKeyDeploymentDialog::PublicKeyDeploymentDialog(const DeviceConstRef &devic
Result<> result = ResultOk; Result<> result = ResultOk;
if (!succeeded) { if (!succeeded) {
const QString errorString = d->m_process.errorString(); const QString errorString = d->m_process.errorString();
const QString errorMessage = errorString.isEmpty() ? d->m_process.cleanedStdErr() const QString errorMessage = d->m_process.exitMessage(
: errorString; Process::FailureMessageFormat::WithStdErr);
result = ResultError(Utils::joinStrings({Tr::tr("Key deployment failed."), result = ResultError(Utils::joinStrings({Tr::tr("Key deployment failed."),
Utils::trimBack(errorMessage, '\n')}, '\n')); Utils::trimBack(errorMessage, '\n')}, '\n'));
} }