From b1f64d09980d489b365c3af26436995f28d1277c Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 15 Apr 2025 11:27:23 +0200 Subject: [PATCH] Utils: Enhance Process::exitMessage() ... with stderr/stdout data, if requested. Change-Id: Ia4aed9b342144d5358c5a91f4555bccb86b2eb7b Reviewed-by: hjk --- src/libs/utils/buildablehelperlibrary.cpp | 2 +- src/libs/utils/qtcprocess.cpp | 21 +++++++++++++++-- src/libs/utils/qtcprocess.h | 4 +++- .../android/keystorecertificatedialog.cpp | 3 +-- src/plugins/baremetal/iarewtoolchain.cpp | 2 +- src/plugins/baremetal/keiltoolchain.cpp | 2 +- src/plugins/baremetal/sdcctoolchain.cpp | 4 ++-- src/plugins/cmakeprojectmanager/cmaketool.cpp | 4 ++-- src/plugins/docker/dockerapi.cpp | 12 +++++----- src/plugins/docker/dockercontainerthread.cpp | 5 ++-- src/plugins/docker/dockerdevice.cpp | 2 +- .../projectexplorer/abstractprocessstep.cpp | 23 ++++--------------- .../customwizardscriptgenerator.cpp | 9 +++----- src/plugins/projectexplorer/gcctoolchain.cpp | 5 ++-- src/plugins/projectexplorer/msvctoolchain.cpp | 4 ++-- src/plugins/python/pipsupport.cpp | 4 ++-- src/plugins/remotelinux/linuxdevice.cpp | 2 +- .../remotelinux/publickeydeploymentdialog.cpp | 4 ++-- 18 files changed, 55 insertions(+), 57 deletions(-) diff --git a/src/libs/utils/buildablehelperlibrary.cpp b/src/libs/utils/buildablehelperlibrary.cpp index 4c5bc0cc4ea..dba8fbb8bd8 100644 --- a/src/libs/utils/buildablehelperlibrary.cpp +++ b/src/libs/utils/buildablehelperlibrary.cpp @@ -112,7 +112,7 @@ QString BuildableHelperLibrary::qtVersionForQMake(const FilePath &qmakePath) qmake.setCommand({qmakePath, {"--version"}}); qmake.runBlocking(5s); if (qmake.result() != ProcessResult::FinishedWithSuccess) { - qWarning() << qmake.exitMessage(); + qWarning() << qmake.verboseExitMessage(); return QString(); } diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index ad24720c419..1468515a1eb 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -1588,9 +1588,26 @@ QString Process::exitMessage(const CommandLine &command, ProcessResult result, 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 diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index b769cf6c1b3..0830fcc9f70 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -177,9 +177,11 @@ public: const QStringList stdOutLines() 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, 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; QString toStandaloneCommandLine() const; diff --git a/src/plugins/android/keystorecertificatedialog.cpp b/src/plugins/android/keystorecertificatedialog.cpp index 710e32fa719..cd005d81e15 100644 --- a/src/plugins/android/keystorecertificatedialog.cpp +++ b/src/plugins/android/keystorecertificatedialog.cpp @@ -315,8 +315,7 @@ void AndroidCreateKeystoreCertificate::buttonBoxAccepted() genKeyCertProc.runBlocking(15s); if (genKeyCertProc.result() != ProcessResult::FinishedWithSuccess) { - QMessageBox::critical(this, Tr::tr("Error"), - genKeyCertProc.exitMessage() + '\n' + genKeyCertProc.allOutput()); + QMessageBox::critical(this, Tr::tr("Error"), genKeyCertProc.verboseExitMessage()); return; } accept(); diff --git a/src/plugins/baremetal/iarewtoolchain.cpp b/src/plugins/baremetal/iarewtoolchain.cpp index 198af3a0203..360651412d9 100644 --- a/src/plugins/baremetal/iarewtoolchain.cpp +++ b/src/plugins/baremetal/iarewtoolchain.cpp @@ -82,7 +82,7 @@ static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList & cpp.setCommand(cmd); cpp.runBlocking(); if (cpp.result() != ProcessResult::FinishedWithSuccess) { - qWarning() << cpp.exitMessage(); + qWarning() << cpp.exitMessage(Process::FailureMessageFormat::WithStdErr); return {}; } diff --git a/src/plugins/baremetal/keiltoolchain.cpp b/src/plugins/baremetal/keiltoolchain.cpp index 44ea4f461fc..864f6c07049 100644 --- a/src/plugins/baremetal/keiltoolchain.cpp +++ b/src/plugins/baremetal/keiltoolchain.cpp @@ -250,7 +250,7 @@ static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringLis cpp.runBlocking(); if (cpp.result() != ProcessResult::FinishedWithSuccess) { - qWarning() << cpp.exitMessage(); + qWarning() << cpp.exitMessage(Process::FailureMessageFormat::WithStdErr); return {}; } diff --git a/src/plugins/baremetal/sdcctoolchain.cpp b/src/plugins/baremetal/sdcctoolchain.cpp index 82a881b8880..19ebc1cb8e3 100644 --- a/src/plugins/baremetal/sdcctoolchain.cpp +++ b/src/plugins/baremetal/sdcctoolchain.cpp @@ -64,7 +64,7 @@ static Macros dumpPredefinedMacros(const FilePath &compiler, const Environment & cpp.runBlocking(); if (cpp.result() != ProcessResult::FinishedWithSuccess) { - qWarning() << cpp.exitMessage(); + qWarning() << cpp.exitMessage(Process::FailureMessageFormat::WithStdErr); return {}; } @@ -84,7 +84,7 @@ static HeaderPaths dumpHeaderPaths(const FilePath &compiler, const Environment & cpp.runBlocking(); if (cpp.result() != ProcessResult::FinishedWithSuccess) { - qWarning() << cpp.exitMessage(); + qWarning() << cpp.exitMessage(Process::FailureMessageFormat::WithStdErr); return {}; } diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp index b9517bb9443..78ef5f2f10f 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp @@ -624,8 +624,8 @@ void CMakeTool::fetchFromCapabilities() const m_introspection->m_haveCapabilitites = true; parseFromCapabilities(cmake.cleanedStdOut()); } else { - qCCritical(cmakeToolLog) << "Fetching capabilities failed: " << cmake.commandLine() - << cmake.allOutput() << cmake.error() << cmake.errorString(); + qCCritical(cmakeToolLog) << "Fetching capabilities failed: " + << cmake.verboseExitMessage(); m_introspection->m_haveCapabilitites = false; // In the rare case when "cmake -E capabilities" crashes / fails to run diff --git a/src/plugins/docker/dockerapi.cpp b/src/plugins/docker/dockerapi.cpp index 25c62096e33..d9a0d590596 100644 --- a/src/plugins/docker/dockerapi.cpp +++ b/src/plugins/docker/dockerapi.cpp @@ -45,10 +45,12 @@ bool DockerApi::canConnect() process.runBlocking(); const bool success = process.result() == ProcessResult::FinishedWithSuccess; - if (!success) - qCWarning(dockerApiLog) << "Failed to connect to docker daemon:" << process.allOutput(); - else + if (!success) { + qCWarning(dockerApiLog) << "Failed to connect to docker daemon:" + << process.verboseExitMessage(); + } else { qCInfo(dockerApiLog) << "'docker info' result:\n" << qPrintable(process.allOutput()); + } return process.result() == ProcessResult::FinishedWithSuccess; } @@ -139,9 +141,7 @@ QFuture>> DockerApi::networks() if (process.result() != ProcessResult::FinishedWithSuccess) { return make_unexpected( - Tr::tr("Failed to retrieve docker networks. Exit code: %1. Error: %2") - .arg(process.exitCode()) - .arg(process.allOutput())); + Tr::tr("Failed to retrieve docker networks: %1").arg(process.verboseExitMessage())); } for (const auto &line : process.readAllStandardOutput().split('\n')) { diff --git a/src/plugins/docker/dockercontainerthread.cpp b/src/plugins/docker/dockercontainerthread.cpp index b061c030c94..27cc5b0ed64 100644 --- a/src/plugins/docker/dockercontainerthread.cpp +++ b/src/plugins/docker/dockercontainerthread.cpp @@ -56,9 +56,8 @@ private: if (createProcess.result() != ProcessResult::FinishedWithSuccess) { return make_unexpected( - Tr::tr("Failed creating Docker container. Exit code: %1, output: %2") - .arg(createProcess.exitCode()) - .arg(createProcess.allOutput())); + Tr::tr("Failed creating Docker container: %1") + .arg(createProcess.verboseExitMessage())); } m_containerId = createProcess.cleanedStdOut().trimmed(); diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 8c21e50d746..65ddb258bff 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -1361,7 +1361,7 @@ Result> DockerDevicePrivate::osTypeAndArch() {"image", "inspect", q->repoAndTag(), "--format", "{{.Os}}\t{{.Architecture}}"}}); proc.runBlocking(); 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 QStringList parts = out.split('\t'); diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp index 1795c062d41..752f84692e1 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.cpp +++ b/src/plugins/projectexplorer/abstractprocessstep.cpp @@ -214,25 +214,10 @@ bool AbstractProcessStep::setupProcess(Process &process) void AbstractProcessStep::handleProcessDone(const Process &process) { - const QString command = d->m_displayedParams->effectiveCommand().toUserOutput(); - if (process.result() == ProcessResult::FinishedWithSuccess) { - emit addOutput(Tr::tr("The process \"%1\" exited normally.").arg(command), - OutputFormat::NormalMessage); - } 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); - } + const OutputFormat format = process.result() == ProcessResult::FinishedWithSuccess + ? OutputFormat::NormalMessage + : OutputFormat::ErrorMessage; + emit addOutput(process.exitMessage(), format); } void AbstractProcessStep::setLowPriority() diff --git a/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp b/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp index 7c78fc17b17..fd798072b39 100644 --- a/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp +++ b/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp @@ -95,12 +95,9 @@ static Result<> using namespace std::chrono_literals; process.runBlocking(30s, EventLoopMode::On); if (process.result() != Utils::ProcessResult::FinishedWithSuccess) { - QString errorMessage = QString("Generator script failed: %1").arg(process.exitMessage()); - const QString stdErr = process.cleanedStdErr(); - if (!stdErr.isEmpty()) { - errorMessage.append(QLatin1Char('\n')); - errorMessage.append(stdErr); - } + QString errorMessage = QString("Generator script failed: %1") + .arg(process.exitMessage( + Process::FailureMessageFormat::WithStdErr)); return ResultError(errorMessage); } if (stdOut) { diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 1f4e5a359e9..f0fa8fd5481 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -172,9 +172,8 @@ static Result runGcc( cpp.setCommand({gcc, arguments}); cpp.runBlocking(); if (cpp.result() != ProcessResult::FinishedWithSuccess || cpp.exitCode() != 0) { - return make_unexpected(QString("Compiler feature detection failure.\n%1\n%2") - .arg(cpp.exitMessage()) - .arg(cpp.allOutput())); + return make_unexpected( + QString("Compiler feature detection failure.\n%1").arg(cpp.verboseExitMessage())); } return cpp.allOutput().trimmed(); diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index ce2a8156ea5..9c4ddd67f22 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -262,7 +262,7 @@ static QList detectVisualStudioFromVsWhere(const QStri {"-products", "*", "-prerelease", "-legacy", "-format", "json", "-utf8"}}); vsWhereProcess.runBlocking(5s); if (vsWhereProcess.result() != ProcessResult::FinishedWithSuccess) { - qWarning() << vsWhereProcess.exitMessage(); + qWarning() << vsWhereProcess.verboseExitMessage(); return installations; } @@ -2116,7 +2116,7 @@ std::optional MsvcToolchain::generateEnvironmentSettings(const Utils::E run.runBlocking(1min); 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; QString command = QDir::toNativeSeparators(batchFile); if (!batchArgs.isEmpty()) diff --git a/src/plugins/python/pipsupport.cpp b/src/plugins/python/pipsupport.cpp index 9fe95334a4f..b0d8dcc328d 100644 --- a/src/plugins/python/pipsupport.cpp +++ b/src/plugins/python/pipsupport.cpp @@ -130,9 +130,9 @@ void PipInstallTask::handleDone() m_future.reportFinished(); const bool success = m_process.result() == ProcessResult::FinishedWithSuccess; 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(m_process.exitCode())); + .arg(m_process.exitMessage())); } emit finished(success); } diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index b446de70793..8171be3e615 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -385,7 +385,7 @@ Environment LinuxDevicePrivate::getEnvironment() if (getEnvProc.result() != ProcessResult::FinishedWithSuccess) { qCWarning(linuxDeviceLog) << "Failed to get environment variables from device:" - << getEnvProc.exitMessage() << getEnvProc.allOutput(); + << getEnvProc.verboseExitMessage(); return {}; } diff --git a/src/plugins/remotelinux/publickeydeploymentdialog.cpp b/src/plugins/remotelinux/publickeydeploymentdialog.cpp index 4bbf24a29d2..d85c124dc30 100644 --- a/src/plugins/remotelinux/publickeydeploymentdialog.cpp +++ b/src/plugins/remotelinux/publickeydeploymentdialog.cpp @@ -59,8 +59,8 @@ PublicKeyDeploymentDialog::PublicKeyDeploymentDialog(const DeviceConstRef &devic Result<> result = ResultOk; if (!succeeded) { const QString errorString = d->m_process.errorString(); - const QString errorMessage = errorString.isEmpty() ? d->m_process.cleanedStdErr() - : errorString; + const QString errorMessage = d->m_process.exitMessage( + Process::FailureMessageFormat::WithStdErr); result = ResultError(Utils::joinStrings({Tr::tr("Key deployment failed."), Utils::trimBack(errorMessage, '\n')}, '\n')); }