iOS: Extract basic devicectl output processing

Put creating the JSON document and error parsing into a separate
function.

Change-Id: I257f82249a07220467c33220c6b8e4650266b8d9
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Eike Ziller
2024-01-15 14:05:29 +01:00
parent c475cdf42d
commit 0ecab7e0d8
4 changed files with 78 additions and 39 deletions

View File

@@ -3,6 +3,8 @@ add_qtc_plugin(Ios
PLUGIN_DEPENDS Core Debugger ProjectExplorer QmakeProjectManager CMakeProjectManager
SOURCES
createsimulatordialog.cpp createsimulatordialog.h
devicectlutils.cpp
devicectlutils.h
ios.qrc
iosbuildconfiguration.cpp iosbuildconfiguration.h
iosbuildstep.cpp iosbuildstep.h

View File

@@ -0,0 +1,47 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "devicectlutils.h"
#include "iostr.h"
#include <QJsonDocument>
Utils::expected_str<QJsonValue> Ios::Internal::parseDevicectlResult(const QByteArray &rawOutput)
{
// there can be crap (progress info) at front and/or end
const int firstCurly = rawOutput.indexOf('{');
const int start = std::max(firstCurly, 0);
const int lastCurly = rawOutput.lastIndexOf('}');
const int end = lastCurly >= 0 ? lastCurly : rawOutput.size() - 1;
QJsonParseError parseError;
auto jsonOutput = QJsonDocument::fromJson(rawOutput.sliced(start, end - start + 1), &parseError);
if (jsonOutput.isNull()) {
// parse error
return Utils::make_unexpected(
Tr::tr("Failed to parse devicectl output: %1.").arg(parseError.errorString()));
}
const QJsonValue errorValue = jsonOutput["error"];
if (!errorValue.isUndefined()) {
// error
QString error
= Tr::tr("Operation failed: %1.")
.arg(errorValue["userInfo"]["NSLocalizedDescription"]["string"].toString());
const QJsonValue userInfo
= errorValue["userInfo"]["NSUnderlyingError"]["error"]["userInfo"];
const QList<QJsonValue> moreInfo{userInfo["NSLocalizedDescription"]["string"],
userInfo["NSLocalizedFailureReason"]["string"],
userInfo["NSLocalizedRecoverySuggestion"]["string"]};
for (const QJsonValue &v : moreInfo) {
if (!v.isUndefined())
error += "\n" + v.toString();
}
return Utils::make_unexpected(error);
}
const QJsonValue resultValue = jsonOutput["result"];
if (resultValue.isUndefined()) {
return Utils::make_unexpected(
Tr::tr("Failed to parse devicectl output: 'result' is missing"));
}
return resultValue;
}

View File

@@ -0,0 +1,14 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <utils/expected.h>
#include <QJsonValue>
namespace Ios::Internal {
Utils::expected_str<QJsonValue> parseDevicectlResult(const QByteArray &rawOutput);
} // namespace Ios::Internal

View File

@@ -3,6 +3,7 @@
#include "iosdeploystep.h"
#include "devicectlutils.h"
#include "iosconstants.h"
#include "iosdevice.h"
#include "iosrunconfiguration.h"
@@ -141,48 +142,23 @@ GroupItem createDeviceCtlDeployTask(
Task::Error);
return DoneResult::Error;
}
const QByteArray rawOutput = process.rawStdOut();
// there can be crap (progress info) at front and/or end
const int firstCurly = rawOutput.indexOf('{');
const int start = std::max(firstCurly, 0);
const int lastCurly = rawOutput.lastIndexOf('}');
const int end = lastCurly >= 0 ? lastCurly : rawOutput.size() - 1;
QJsonParseError parseError;
auto jsonOutput = QJsonDocument::fromJson(rawOutput.sliced(start, end - start + 1),
&parseError);
if (jsonOutput.isNull()) {
// parse error
errorHandler(Tr::tr("Failed to parse devicectl output: %1.")
.arg(parseError.errorString()),
Task::Error);
return DoneResult::Error;
}
const QJsonValue errorValue = jsonOutput["error"];
if (!errorValue.isUndefined()) {
// error
QString error
= Tr::tr("Deployment failed: %1.")
.arg(errorValue["userInfo"]["NSLocalizedDescription"]["string"].toString());
const QJsonValue userInfo
= errorValue["userInfo"]["NSUnderlyingError"]["error"]["userInfo"];
const QList<QJsonValue> moreInfo{userInfo["NSLocalizedDescription"]["string"],
userInfo["NSLocalizedFailureReason"]["string"],
userInfo["NSLocalizedRecoverySuggestion"]["string"]};
for (const QJsonValue &v : moreInfo) {
if (!v.isUndefined())
error += "\n" + v.toString();
const Utils::expected_str<QJsonValue> resultValue = parseDevicectlResult(
process.rawStdOut());
if (resultValue) {
// success
if ((*resultValue)["installedApplications"].isUndefined()) {
// something unexpected happened ...
errorHandler(
Tr::tr(
"devicectl returned unexpected output ... deployment might have failed."),
Task::Error);
// ... proceed anyway
}
errorHandler(error, Task::Error);
return DoneResult::Error;
}
if (jsonOutput["result"]["installedApplications"].isUndefined()) {
// something unexpected happened ... proceed anyway
errorHandler(
Tr::tr("devicectl returned unexpected output ... deployment might have failed."),
Task::Error);
return DoneResult::Success;
}
return DoneResult::Success;
// failure
errorHandler(resultValue.error(), Task::Error);
return DoneResult::Error;
};
return ProcessTask(onSetup, onDone);
}