forked from qt-creator/qt-creator
Android: Do some cleanup
Cleanup after employing task tree... Change-Id: I79ffa385886b0a635a5fdfdbc496dcf6b042aa71 Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user