From 0ecab7e0d8fa19dc094e06bacdf115489959385e Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 15 Jan 2024 14:05:29 +0100 Subject: [PATCH] iOS: Extract basic devicectl output processing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Put creating the JSON document and error parsing into a separate function. Change-Id: I257f82249a07220467c33220c6b8e4650266b8d9 Reviewed-by: Tor Arne Vestbø Reviewed-by: Qt CI Bot --- src/plugins/ios/CMakeLists.txt | 2 ++ src/plugins/ios/devicectlutils.cpp | 47 ++++++++++++++++++++++++++ src/plugins/ios/devicectlutils.h | 14 ++++++++ src/plugins/ios/iosdeploystep.cpp | 54 +++++++++--------------------- 4 files changed, 78 insertions(+), 39 deletions(-) create mode 100644 src/plugins/ios/devicectlutils.cpp create mode 100644 src/plugins/ios/devicectlutils.h diff --git a/src/plugins/ios/CMakeLists.txt b/src/plugins/ios/CMakeLists.txt index 8cddada7aa1..e6ec1665b2c 100644 --- a/src/plugins/ios/CMakeLists.txt +++ b/src/plugins/ios/CMakeLists.txt @@ -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 diff --git a/src/plugins/ios/devicectlutils.cpp b/src/plugins/ios/devicectlutils.cpp new file mode 100644 index 00000000000..03b581cad1c --- /dev/null +++ b/src/plugins/ios/devicectlutils.cpp @@ -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 + +Utils::expected_str 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 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; +} diff --git a/src/plugins/ios/devicectlutils.h b/src/plugins/ios/devicectlutils.h new file mode 100644 index 00000000000..b3f879aea72 --- /dev/null +++ b/src/plugins/ios/devicectlutils.h @@ -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 + +#include + +namespace Ios::Internal { + +Utils::expected_str parseDevicectlResult(const QByteArray &rawOutput); + +} // namespace Ios::Internal diff --git a/src/plugins/ios/iosdeploystep.cpp b/src/plugins/ios/iosdeploystep.cpp index c56937b1cc0..3b137a52877 100644 --- a/src/plugins/ios/iosdeploystep.cpp +++ b/src/plugins/ios/iosdeploystep.cpp @@ -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 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 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); }