diff options
author | Jarek Kobus <[email protected]> | 2024-05-02 17:45:32 +0200 |
---|---|---|
committer | Jarek Kobus <[email protected]> | 2024-05-03 15:06:55 +0000 |
commit | bb5cdfeb4c28d90fa6e78234813be5ce36e65fdf (patch) | |
tree | 17117a661616674c42ed6273989c6be58ecd2af2 /src/plugins/android/androidsdkmanager.cpp | |
parent | 74994b435d3c46e771c943222f249d7950739643 (diff) |
Android: Do some cleanup
Cleanup after employing task tree...
Change-Id: I79ffa385886b0a635a5fdfdbc496dcf6b042aa71
Reviewed-by: Alessandro Portale <[email protected]>
Diffstat (limited to 'src/plugins/android/androidsdkmanager.cpp')
-rw-r--r-- | src/plugins/android/androidsdkmanager.cpp | 390 |
1 files changed, 14 insertions, 376 deletions
diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index 181cdec183e..191ba4d5df0 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -15,16 +15,13 @@ #include <utils/layoutbuilder.h> #include <utils/outputformatter.h> #include <utils/qtcprocess.h> -#include <utils/qtcassert.h> -#include <utils/stringutils.h> -#include <QFutureWatcher> #include <QDialogButtonBox> +#include <QLabel> #include <QLoggingCategory> #include <QMessageBox> #include <QPlainTextEdit> #include <QProgressBar> -#include <QReadWriteLock> #include <QRegularExpression> #include <QTextCodec> @@ -39,8 +36,7 @@ using namespace Utils; using namespace std::chrono; using namespace std::chrono_literals; -namespace Android { -namespace Internal { +namespace Android::Internal { class QuestionProgressDialog : public QDialog { @@ -124,7 +120,7 @@ static QString sdkRootArg(const AndroidConfig &config) return "--sdk_root=" + config.sdkLocation().toString(); } -static const QRegularExpression &assertionRegExp() +const QRegularExpression &assertionRegExp() { static const QRegularExpression theRegExp (R"((\(\s*y\s*[\/\\]\s*n\s*\)\s*)(?<mark>[\:\?]))", // (y/N)? @@ -329,49 +325,11 @@ static GroupItem updateRecipe(const Storage<DialogStorage> &dialogStorage) return ProcessTask(onUpdateSetup, onDone); } -const int sdkManagerCmdTimeoutS = 60; -const int sdkManagerOperationTimeoutS = 600; - -using SdkCmdPromise = QPromise<AndroidSdkManager::OperationOutput>; - -int parseProgress(const QString &out, bool &foundAssertion) -{ - int progress = -1; - if (out.isEmpty()) - return progress; - static const QRegularExpression reg("(?<progress>\\d*)%"); - static const QRegularExpression regEndOfLine("[\\n\\r]"); - const QStringList lines = out.split(regEndOfLine, Qt::SkipEmptyParts); - for (const QString &line : lines) { - QRegularExpressionMatch match = reg.match(line); - if (match.hasMatch()) { - progress = match.captured("progress").toInt(); - if (progress < 0 || progress > 100) - progress = -1; - } - if (!foundAssertion) - foundAssertion = assertionRegExp().match(line).hasMatch(); - } - return progress; -} - -void watcherDeleter(QFutureWatcher<void> *watcher) -{ - if (!watcher->isFinished() && !watcher->isCanceled()) - watcher->cancel(); - - if (!watcher->isFinished()) - watcher->waitForFinished(); - - delete watcher; -} - /*! Runs the \c sdkmanger tool with arguments \a args. Returns \c true if the command is successfully executed. Output is copied into \a output. The function blocks the calling thread. */ -static bool sdkManagerCommand(const AndroidConfig &config, const QStringList &args, - QString *output, int timeout = sdkManagerCmdTimeoutS) +static bool sdkManagerCommand(const AndroidConfig &config, const QStringList &args, QString *output) { QStringList newArgs = args; newArgs.append(sdkRootArg(config)); @@ -382,60 +340,12 @@ static bool sdkManagerCommand(const AndroidConfig &config, const QStringList &ar proc.setEnvironment(config.toolsEnvironment()); proc.setTimeOutMessageBoxEnabled(true); proc.setCommand({config.sdkManagerToolPath(), newArgs}); - proc.runBlocking(seconds(timeout), EventLoopMode::On); + proc.runBlocking(60s, EventLoopMode::On); if (output) *output = proc.allOutput(); return proc.result() == ProcessResult::FinishedWithSuccess; } -/*! - Runs the \c sdkmanger tool with arguments \a args. The operation command progress is updated in - to the future interface \a fi and \a output is populated with command output. The command listens - to cancel signal emmitted by \a sdkManager and kill the commands. The command is also killed - after the lapse of \a timeout seconds. The function blocks the calling thread. - */ -static void sdkManagerCommand(const AndroidConfig &config, const QStringList &args, - AndroidSdkManager &sdkManager, SdkCmdPromise &promise, - AndroidSdkManager::OperationOutput &output, double progressQuota, - bool interruptible = true, int timeout = sdkManagerOperationTimeoutS) -{ - QStringList newArgs = args; - newArgs.append(sdkRootArg(config)); - qCDebug(sdkManagerLog).noquote() << "Running SDK Manager command (async):" - << CommandLine(config.sdkManagerToolPath(), newArgs) - .toUserOutput(); - int offset = promise.future().progressValue(); - Process proc; - proc.setEnvironment(config.toolsEnvironment()); - bool assertionFound = false; - proc.setStdOutCallback([offset, progressQuota, &proc, &assertionFound, &promise](const QString &out) { - int progressPercent = parseProgress(out, assertionFound); - if (assertionFound) - proc.stop(); - if (progressPercent != -1) - promise.setProgressValue(offset + qRound((progressPercent / 100.0) * progressQuota)); - }); - proc.setStdErrCallback([&output](const QString &err) { - output.stdError = err; - }); - if (interruptible) { - QObject::connect(&sdkManager, &AndroidSdkManager::cancelActiveOperations, &proc, [&proc] { - proc.stop(); - proc.waitForFinished(); - }); - } - proc.setCommand({config.sdkManagerToolPath(), newArgs}); - proc.runBlocking(seconds(timeout), EventLoopMode::On); - if (assertionFound) { - output.success = false; - output.stdOutput = proc.cleanedStdOut(); - output.stdError = Tr::tr("The operation requires user interaction. " - "Use the \"sdkmanager\" command-line tool."); - } else { - output.success = proc.result() == ProcessResult::FinishedWithSuccess; - } -} - class AndroidSdkManagerPrivate { public: @@ -453,20 +363,8 @@ public: const AndroidSdkPackageList &allPackages(); void parseCommonArguments(QPromise<QString> &promise); - void updateInstalled(SdkCmdPromise &fi); - void updatePackages(SdkCmdPromise &fi, const InstallationChange &change); - void licenseCheck(SdkCmdPromise &fi); - void licenseWorkflow(SdkCmdPromise &fi); - - void addWatcher(const QFuture<AndroidSdkManager::OperationOutput> &future); - void setLicenseInput(bool acceptLicense); - std::unique_ptr<QFutureWatcher<void>, decltype(&watcherDeleter)> m_activeOperation; - - QByteArray getUserInput() const; - void clearUserInput(); void reloadSdkPackages(); - void clearPackages(); void runDialogRecipe(const Storage<DialogStorage> &dialogStorage, const GroupItem &licenseRecipe, const GroupItem &continuationRecipe); @@ -474,21 +372,13 @@ public: AndroidSdkManager &m_sdkManager; AndroidSdkPackageList m_allPackages; FilePath lastSdkManagerPath; - QByteArray m_licenseUserInput; - mutable QReadWriteLock m_licenseInputLock; bool m_packageListingSuccessful = false; TaskTreeRunner m_taskTreeRunner; }; -AndroidSdkManager::AndroidSdkManager() - : m_d(new AndroidSdkManagerPrivate(*this)) -{ -} +AndroidSdkManager::AndroidSdkManager() : m_d(new AndroidSdkManagerPrivate(*this)) {} -AndroidSdkManager::~AndroidSdkManager() -{ - cancelOperatons(); -} +AndroidSdkManager::~AndroidSdkManager() = default; SdkPlatformList AndroidSdkManager::installedSdkPlatforms() { @@ -537,14 +427,12 @@ SystemImageList AndroidSdkManager::installedSystemImages() { const AndroidSdkPackageList list = m_d->filteredPackages(AndroidSdkPackage::AnyValidState, AndroidSdkPackage::SdkPlatformPackage); - QList<SdkPlatform *> platforms = Utils::static_container_cast<SdkPlatform *>(list); - + const QList<SdkPlatform *> platforms = Utils::static_container_cast<SdkPlatform *>(list); SystemImageList result; for (SdkPlatform *platform : platforms) { if (platform->systemImages().size() > 0) result.append(platform->systemImages()); } - return result; } @@ -573,7 +461,6 @@ SdkPlatformList AndroidSdkManager::filteredSdkPlatforms(int minApiLevel, { const AndroidSdkPackageList list = m_d->filteredPackages(state, AndroidSdkPackage::SdkPlatformPackage); - SdkPlatformList result; for (AndroidSdkPackage *p : list) { auto platform = static_cast<SdkPlatform *>(p); @@ -608,11 +495,6 @@ void AndroidSdkManager::reloadPackages() m_d->reloadSdkPackages(); } -bool AndroidSdkManager::isBusy() const -{ - return m_d->m_activeOperation && !m_d->m_activeOperation->isFinished(); -} - bool AndroidSdkManager::packageListingSuccessful() const { return m_d->m_packageListingSuccessful; @@ -623,62 +505,13 @@ QFuture<QString> AndroidSdkManager::availableArguments() const return Utils::asyncRun(&AndroidSdkManagerPrivate::parseCommonArguments, m_d.get()); } -QFuture<AndroidSdkManager::OperationOutput> AndroidSdkManager::updateInstalled() -{ - if (isBusy()) { - return QFuture<AndroidSdkManager::OperationOutput>(); - } - auto future = Utils::asyncRun(&AndroidSdkManagerPrivate::updateInstalled, m_d.get()); - m_d->addWatcher(future); - return future; -} - -QFuture<AndroidSdkManager::OperationOutput> AndroidSdkManager::updatePackages(const InstallationChange &change) -{ - if (isBusy()) - return QFuture<AndroidSdkManager::OperationOutput>(); - auto future = Utils::asyncRun(&AndroidSdkManagerPrivate::updatePackages, m_d.get(), change); - m_d->addWatcher(future); - return future; -} - -QFuture<AndroidSdkManager::OperationOutput> AndroidSdkManager::licenseCheck() -{ - if (isBusy()) - return QFuture<AndroidSdkManager::OperationOutput>(); - auto future = Utils::asyncRun(&AndroidSdkManagerPrivate::licenseCheck, m_d.get()); - m_d->addWatcher(future); - return future; -} - -QFuture<AndroidSdkManager::OperationOutput> AndroidSdkManager::licenseWorkflow() -{ - if (isBusy()) - return QFuture<AndroidSdkManager::OperationOutput>(); - auto future = Utils::asyncRun(&AndroidSdkManagerPrivate::licenseWorkflow, m_d.get()); - m_d->addWatcher(future); - return future; -} - -void AndroidSdkManager::cancelOperatons() -{ - emit cancelActiveOperations(); - m_d->m_activeOperation.reset(); -} - -void AndroidSdkManager::acceptSdkLicense(bool accept) -{ - m_d->setLicenseInput(accept); -} - -AndroidSdkManagerPrivate::AndroidSdkManagerPrivate(AndroidSdkManager &sdkManager): - m_activeOperation(nullptr, watcherDeleter), - m_sdkManager(sdkManager) +AndroidSdkManagerPrivate::AndroidSdkManagerPrivate(AndroidSdkManager &sdkManager) + : m_sdkManager(sdkManager) {} AndroidSdkManagerPrivate::~AndroidSdkManagerPrivate() { - clearPackages(); + qDeleteAll(m_allPackages); } const AndroidSdkPackageList &AndroidSdkManagerPrivate::allPackages() @@ -690,7 +523,8 @@ const AndroidSdkPackageList &AndroidSdkManagerPrivate::allPackages() void AndroidSdkManagerPrivate::reloadSdkPackages() { emit m_sdkManager.packageReloadBegin(); - clearPackages(); + qDeleteAll(m_allPackages); + m_allPackages.clear(); lastSdkManagerPath = androidConfig().sdkManagerToolPath(); m_packageListingSuccessful = false; @@ -715,194 +549,6 @@ void AndroidSdkManagerPrivate::reloadSdkPackages() emit m_sdkManager.packageReloadFinished(); } -void AndroidSdkManagerPrivate::updateInstalled(SdkCmdPromise &promise) -{ - promise.setProgressRange(0, 100); - promise.setProgressValue(0); - AndroidSdkManager::OperationOutput result; - result.type = AndroidSdkManager::UpdateInstalled; - result.stdOutput = Tr::tr("Updating installed packages."); - promise.addResult(result); - QStringList args("--update"); - args << androidConfig().sdkManagerToolArgs(); - if (!promise.isCanceled()) - sdkManagerCommand(androidConfig(), args, m_sdkManager, promise, result, 100); - else - qCDebug(sdkManagerLog) << "Update: Operation cancelled before start"; - - if (result.stdError.isEmpty() && !result.success) - result.stdError = Tr::tr("Failed."); - result.stdOutput = Tr::tr("Done") + "\n\n"; - promise.addResult(result); - promise.setProgressValue(100); -} - -void AndroidSdkManagerPrivate::updatePackages(SdkCmdPromise &fi, const InstallationChange &change) -{ - fi.setProgressRange(0, 100); - fi.setProgressValue(0); - double progressQuota = 100.0 / change.count(); - int currentProgress = 0; - - QString installTag = Tr::tr("Installing"); - QString uninstallTag = Tr::tr("Uninstalling"); - - auto doOperation = [&](const QString& packagePath, const QStringList& args, - bool isInstall) { - AndroidSdkManager::OperationOutput result; - result.type = AndroidSdkManager::UpdatePackages; - result.stdOutput = QString("%1 %2").arg(isInstall ? installTag : uninstallTag) - .arg(packagePath); - fi.addResult(result); - if (fi.isCanceled()) - qCDebug(sdkManagerLog) << args << "Update: Operation cancelled before start"; - else - sdkManagerCommand(androidConfig(), args, m_sdkManager, fi, result, progressQuota, isInstall); - currentProgress += progressQuota; - fi.setProgressValue(currentProgress); - if (result.stdError.isEmpty() && !result.success) - result.stdError = Tr::tr("Failed"); - result.stdOutput = Tr::tr("Done") + "\n\n"; - fi.addResult(result); - return fi.isCanceled(); - }; - - - // Uninstall packages - for (const QString &sdkStylePath : change.toUninstall) { - // Uninstall operations are not interptible. We don't want to leave half uninstalled. - QStringList args; - args << "--uninstall" << sdkStylePath << androidConfig().sdkManagerToolArgs(); - if (doOperation(sdkStylePath, args, false)) - break; - } - - // Install packages - for (const QString &sdkStylePath : change.toInstall) { - QStringList args(sdkStylePath); - args << androidConfig().sdkManagerToolArgs(); - if (doOperation(sdkStylePath, args, true)) - break; - } - fi.setProgressValue(100); -} - -void AndroidSdkManagerPrivate::licenseCheck(SdkCmdPromise &fi) -{ - fi.setProgressRange(0, 100); - fi.setProgressValue(0); - AndroidSdkManager::OperationOutput result; - result.type = AndroidSdkManager::LicenseCheck; - if (!fi.isCanceled()) { - const int timeOutS = 4; // Short timeout as workaround for QTCREATORBUG-25667 - sdkManagerCommand(androidConfig(), {"--licenses"}, m_sdkManager, fi, result, 100.0, true, - timeOutS); - } else { - qCDebug(sdkManagerLog) << "Update: Operation cancelled before start"; - } - - fi.addResult(result); - fi.setProgressValue(100); -} - -void AndroidSdkManagerPrivate::licenseWorkflow(SdkCmdPromise &fi) -{ - fi.setProgressRange(0, 100); - fi.setProgressValue(0); - - AndroidSdkManager::OperationOutput result; - result.type = AndroidSdkManager::LicenseWorkflow; - - Process licenseCommand; - licenseCommand.setProcessMode(ProcessMode::Writer); - licenseCommand.setEnvironment(androidConfig().toolsEnvironment()); - bool reviewingLicenses = false; - licenseCommand.setCommand(CommandLine(androidConfig().sdkManagerToolPath(), - {"--licenses", sdkRootArg(androidConfig())})); - licenseCommand.setUseCtrlCStub(true); - licenseCommand.start(); - QTextCodec *codec = QTextCodec::codecForLocale(); - int inputCounter = 0, steps = -1; - QString licenseTextCache; - while (!licenseCommand.waitForFinished(200ms)) { - const QString stdOut = codec->toUnicode(licenseCommand.readAllRawStandardOutput()); - bool assertion = false; - if (!stdOut.isEmpty()) { - licenseTextCache.append(stdOut); - assertion = assertionRegExp().match(licenseTextCache).hasMatch(); - if (assertion) { - if (reviewingLicenses) { - result.stdOutput = licenseTextCache; - fi.addResult(result); - } - licenseTextCache.clear(); - } - } - - if (reviewingLicenses) { - // Check user input - QByteArray userInput = getUserInput(); - if (!userInput.isEmpty()) { - clearUserInput(); - licenseCommand.writeRaw(userInput); - ++inputCounter; - if (steps != -1) - fi.setProgressValue(qRound((inputCounter / (double)steps) * 100)); - } - } else if (assertion) { - // The first assertion is to start reviewing licenses. Always accept. - reviewingLicenses = true; - static const QRegularExpression reg(R"((\d+\sof\s)(?<steps>\d+))"); - QRegularExpressionMatch match = reg.match(stdOut); - if (match.hasMatch()) - steps = match.captured("steps").toInt(); - licenseCommand.write("Y\n"); - } - - if (fi.isCanceled()) { - licenseCommand.terminate(); - if (!licenseCommand.waitForFinished(300ms)) { - licenseCommand.kill(); - licenseCommand.waitForFinished(200ms); - } - } - if (licenseCommand.state() == QProcess::NotRunning) - break; - } - - result.success = licenseCommand.exitStatus() == QProcess::NormalExit; - if (!result.success) - result.stdError = Tr::tr("License command failed.") + "\n\n"; - fi.addResult(result); - fi.setProgressValue(100); -} - -void AndroidSdkManagerPrivate::setLicenseInput(bool acceptLicense) -{ - QWriteLocker locker(&m_licenseInputLock); - m_licenseUserInput = acceptLicense ? "Y\n" : "n\n"; -} - -QByteArray AndroidSdkManagerPrivate::getUserInput() const -{ - QReadLocker locker(&m_licenseInputLock); - return m_licenseUserInput; -} - -void AndroidSdkManagerPrivate::clearUserInput() -{ - QWriteLocker locker(&m_licenseInputLock); - m_licenseUserInput.clear(); -} - -void AndroidSdkManagerPrivate::addWatcher(const QFuture<AndroidSdkManager::OperationOutput> &future) -{ - if (future.isFinished()) - return; - m_activeOperation.reset(new QFutureWatcher<void>()); - m_activeOperation->setFuture(QFuture<void>(future)); -} - void AndroidSdkManagerPrivate::parseCommonArguments(QPromise<QString> &promise) { QString argumentDetails; @@ -923,13 +569,6 @@ void AndroidSdkManagerPrivate::parseCommonArguments(QPromise<QString> &promise) promise.addResult(argumentDetails); } -void AndroidSdkManagerPrivate::clearPackages() -{ - for (AndroidSdkPackage *p : std::as_const(m_allPackages)) - delete p; - m_allPackages.clear(); -} - void AndroidSdkManagerPrivate::runDialogRecipe(const Storage<DialogStorage> &dialogStorage, const GroupItem &licensesRecipe, const GroupItem &continuationRecipe) @@ -991,7 +630,6 @@ void AndroidSdkManager::runUpdate() m_d->runDialogRecipe(dialogStorage, licensesRecipe(dialogStorage), updateRecipe(dialogStorage)); } -} // namespace Internal -} // namespace Android +} // namespace Android::Internal #include "androidsdkmanager.moc" |