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.runBlocking(5s);
if (qmake.result() != ProcessResult::FinishedWithSuccess) {
qWarning() << qmake.exitMessage();
qWarning() << qmake.verboseExitMessage();
return QString();
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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();

View File

@@ -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 {};
}

View File

@@ -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 {};
}

View File

@@ -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 {};
}

View File

@@ -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

View File

@@ -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<Utils::Result<QList<Network>>> 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')) {

View File

@@ -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();

View File

@@ -1361,7 +1361,7 @@ Result<QPair<Utils::OsType, Utils::OsArch>> 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');

View File

@@ -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()

View File

@@ -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) {

View File

@@ -172,9 +172,8 @@ static Result<QString> 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();

View File

@@ -262,7 +262,7 @@ static QList<VisualStudioInstallation> 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<QString> 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())

View File

@@ -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);
}

View File

@@ -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 {};
}

View File

@@ -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'));
}