iOS: Unify error output handling for all simctl commands

If simctl fails, always include its stderr output in the error, if any.

Change-Id: I7a5643ac81befc9d0595e9c3bd4fa009057ff85b
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
Eike Ziller
2024-07-23 13:51:54 +02:00
parent f91af7106a
commit 5cd35e33b3

View File

@@ -51,7 +51,6 @@ const char buildVersionTag[] = "buildversion";
static expected_str<void> runCommand( static expected_str<void> runCommand(
const CommandLine &command, const CommandLine &command,
QString *stdOutput, QString *stdOutput,
QString *allOutput = nullptr,
std::function<bool()> shouldStop = [] { return false; }) std::function<bool()> shouldStop = [] { return false; })
{ {
Process p; Process p;
@@ -76,11 +75,15 @@ static expected_str<void> runCommand(
if (stdOutput) if (stdOutput)
*stdOutput = p.cleanedStdOut(); *stdOutput = p.cleanedStdOut();
if (allOutput)
*allOutput = p.allOutput();
if (p.result() != ProcessResult::FinishedWithSuccess) if (p.result() != ProcessResult::FinishedWithSuccess) {
return make_unexpected(p.errorString()); QStringList error;
if (const QString procError = p.errorString(); !procError.isEmpty())
error << procError;
if (const QString stdError = p.cleanedStdErr(); !stdError.isEmpty())
error << stdError;
return make_unexpected(error.join('\n'));
}
return {}; return {};
} }
@@ -88,7 +91,6 @@ static expected_str<void> runCommand(
static expected_str<void> runSimCtlCommand( static expected_str<void> runSimCtlCommand(
const QStringList &args, const QStringList &args,
QString *output, QString *output,
QString *allOutput = nullptr,
std::function<bool()> shouldStop = [] { return false; }) std::function<bool()> shouldStop = [] { return false; })
{ {
// Cache xcrun's path, as this function will be called often. // Cache xcrun's path, as this function will be called often.
@@ -97,7 +99,7 @@ static expected_str<void> runSimCtlCommand(
return make_unexpected(Tr::tr("Cannot find xcrun.")); return make_unexpected(Tr::tr("Cannot find xcrun."));
else if (!xcrun.isExecutableFile()) else if (!xcrun.isExecutableFile())
return make_unexpected(Tr::tr("xcrun is not executable.")); return make_unexpected(Tr::tr("xcrun is not executable."));
return runCommand({xcrun, {"simctl", args}}, output, allOutput, shouldStop); return runCommand({xcrun, {"simctl", args}}, output, shouldStop);
} }
static expected_str<void> launchSimulator(const QString &simUdid, std::function<bool()> shouldStop) static expected_str<void> launchSimulator(const QString &simUdid, std::function<bool()> shouldStop)
@@ -109,14 +111,13 @@ static expected_str<void> launchSimulator(const QString &simUdid, std::function<
if (IosConfigurations::xcodeVersion() >= QVersionNumber(9)) { if (IosConfigurations::xcodeVersion() >= QVersionNumber(9)) {
// For XCode 9 boot the second device instead of launching simulator app twice. // For XCode 9 boot the second device instead of launching simulator app twice.
QString psOutput; QString psOutput;
expected_str<void> result expected_str<void> result = runCommand({"ps", {"-A", "-o", "comm"}}, &psOutput, shouldStop);
= runCommand({"ps", {"-A", "-o", "comm"}}, &psOutput, nullptr, shouldStop);
if (!result) if (!result)
return result; return result;
for (const QString &comm : psOutput.split('\n')) { for (const QString &comm : psOutput.split('\n')) {
if (comm == simulatorAppPath.toString()) if (comm == simulatorAppPath.toString())
return runSimCtlCommand({"boot", simUdid}, nullptr, nullptr, shouldStop); return runSimCtlCommand({"boot", simUdid}, nullptr, shouldStop);
} }
} }
const bool started = Process::startDetached( const bool started = Process::startDetached(
@@ -480,15 +481,12 @@ void installApp(QPromise<SimulatorControl::Response> &promise,
return; return;
} }
QString allOutput; expected_str<void> result
expected_str<void> result = runSimCtlCommand( = runSimCtlCommand({"install", simUdid, bundlePath.toString()}, nullptr, [&promise] {
{"install", simUdid, bundlePath.toString()}, nullptr, &allOutput, [&promise] {
return promise.isCanceled(); return promise.isCanceled();
}); });
if (!result) { if (!result) {
const QString error = result.error().isEmpty() ? allOutput promise.addResult(make_unexpected(result.error()));
: (result.error() + "\n" + allOutput);
promise.addResult(make_unexpected(error));
} else { } else {
promise.addResult(response); promise.addResult(response);
} }
@@ -527,7 +525,7 @@ void launchApp(QPromise<SimulatorControl::Response> &promise,
} }
QString stdOutput; QString stdOutput;
expected_str<void> result = runSimCtlCommand(args, &stdOutput, nullptr, [&promise] { expected_str<void> result = runSimCtlCommand(args, &stdOutput, [&promise] {
return promise.isCanceled(); return promise.isCanceled();
}); });
@@ -552,7 +550,7 @@ void launchApp(QPromise<SimulatorControl::Response> &promise,
void deleteSimulator(QPromise<SimulatorControl::Response> &promise, const QString &simUdid) void deleteSimulator(QPromise<SimulatorControl::Response> &promise, const QString &simUdid)
{ {
SimulatorControl::ResponseData response(simUdid); SimulatorControl::ResponseData response(simUdid);
expected_str<void> result = runSimCtlCommand({"delete", simUdid}, nullptr, nullptr, [&promise] { expected_str<void> result = runSimCtlCommand({"delete", simUdid}, nullptr, [&promise] {
return promise.isCanceled(); return promise.isCanceled();
}); });
@@ -565,7 +563,7 @@ void deleteSimulator(QPromise<SimulatorControl::Response> &promise, const QStrin
void resetSimulator(QPromise<SimulatorControl::Response> &promise, const QString &simUdid) void resetSimulator(QPromise<SimulatorControl::Response> &promise, const QString &simUdid)
{ {
SimulatorControl::ResponseData response(simUdid); SimulatorControl::ResponseData response(simUdid);
expected_str<void> result = runSimCtlCommand({"erase", simUdid}, nullptr, nullptr, [&promise] { expected_str<void> result = runSimCtlCommand({"erase", simUdid}, nullptr, [&promise] {
return promise.isCanceled(); return promise.isCanceled();
}); });
@@ -580,8 +578,7 @@ void renameSimulator(QPromise<SimulatorControl::Response> &promise,
const QString &newName) const QString &newName)
{ {
SimulatorControl::ResponseData response(simUdid); SimulatorControl::ResponseData response(simUdid);
expected_str<void> result expected_str<void> result = runSimCtlCommand({"rename", simUdid, newName}, nullptr, [&promise] {
= runSimCtlCommand({"rename", simUdid, newName}, nullptr, nullptr, [&promise] {
return promise.isCanceled(); return promise.isCanceled();
}); });
if (!result) if (!result)
@@ -604,10 +601,9 @@ void createSimulator(QPromise<SimulatorControl::Response> &promise,
QString stdOutput; QString stdOutput;
expected_str<void> result = runSimCtlCommand( expected_str<void> result = runSimCtlCommand(
{"create", name, deviceType.identifier, runtime.identifier}, {"create", name, deviceType.identifier, runtime.identifier}, &stdOutput, [&promise] {
&stdOutput, return promise.isCanceled();
nullptr, });
[&promise] { return promise.isCanceled(); });
if (result) if (result)
response.simUdid = stdOutput.trimmed(); response.simUdid = stdOutput.trimmed();
@@ -624,7 +620,7 @@ void takeSceenshot(QPromise<SimulatorControl::Response> &promise,
{ {
SimulatorControl::ResponseData response(simUdid); SimulatorControl::ResponseData response(simUdid);
expected_str<void> result expected_str<void> result
= runSimCtlCommand({"io", simUdid, "screenshot", filePath}, nullptr, nullptr, [&promise] { = runSimCtlCommand({"io", simUdid, "screenshot", filePath}, nullptr, [&promise] {
return promise.isCanceled(); return promise.isCanceled();
}); });