aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/android/androidsdkmanager.cpp
diff options
context:
space:
mode:
authorJarek Kobus <[email protected]>2024-05-02 17:45:32 +0200
committerJarek Kobus <[email protected]>2024-05-03 15:06:55 +0000
commitbb5cdfeb4c28d90fa6e78234813be5ce36e65fdf (patch)
tree17117a661616674c42ed6273989c6be58ecd2af2 /src/plugins/android/androidsdkmanager.cpp
parent74994b435d3c46e771c943222f249d7950739643 (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.cpp390
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"