diff --git a/src/plugins/updateinfo/updateinfoplugin.cpp b/src/plugins/updateinfo/updateinfoplugin.cpp index 87fbc33e1e9..6ad611d2e71 100644 --- a/src/plugins/updateinfo/updateinfoplugin.cpp +++ b/src/plugins/updateinfo/updateinfoplugin.cpp @@ -32,8 +32,9 @@ #include #include #include +#include +#include #include -#include #include #include #include @@ -53,6 +54,8 @@ #include #include +#include + Q_LOGGING_CATEGORY(log, "qtc.updateinfo", QtWarningMsg) const char UpdaterGroup[] = "Updater"; @@ -68,6 +71,7 @@ const char InstallUpdates[] = "UpdateInfo.InstallUpdates"; const char InstallQtUpdates[] = "UpdateInfo.InstallQtUpdates"; using namespace Core; +using namespace Utils; namespace UpdateInfo { namespace Internal { @@ -76,11 +80,11 @@ class UpdateInfoPluginPrivate { public: QString m_maintenanceTool; - QPointer m_checkUpdatesCommand; + std::unique_ptr m_maintenanceToolProcess; QPointer m_progress; - QString m_collectedOutput; + QString m_updateOutput; + QString m_packagesOutput; QTimer *m_checkUpdatesTimer = nullptr; - struct Settings { bool automaticCheck = true; @@ -125,7 +129,7 @@ void UpdateInfoPlugin::stopAutoCheckForUpdates() void UpdateInfoPlugin::doAutoCheckForUpdates() { - if (d->m_checkUpdatesCommand) + if (d->m_maintenanceToolProcess) return; // update task is still running (might have been run manually just before) if (nextCheckDate().isValid() && nextCheckDate() > QDate::currentDate()) @@ -138,51 +142,86 @@ void UpdateInfoPlugin::startCheckForUpdates() { stopCheckForUpdates(); - d->m_checkUpdatesCommand = new ShellCommand({}, Utils::Environment::systemEnvironment()); - d->m_checkUpdatesCommand->setDisplayName(tr("Checking for Updates")); - connect(d->m_checkUpdatesCommand, &ShellCommand::stdOutText, this, &UpdateInfoPlugin::collectCheckForUpdatesOutput); - connect(d->m_checkUpdatesCommand, &ShellCommand::finished, this, &UpdateInfoPlugin::checkForUpdatesFinished); - d->m_checkUpdatesCommand->addJob({Utils::FilePath::fromString(d->m_maintenanceTool), - {"ch", "-g", "*=false,ifw.package.*=true"}}, - 60 * 3, // 3 minutes timeout - /*workingDirectory=*/{}, - [](int /*exitCode*/) { - return Utils::ProcessResult::FinishedWithSuccess; - }); - if (d->m_settings.checkForQtVersions) { - d->m_checkUpdatesCommand - ->addJob({Utils::FilePath::fromString(d->m_maintenanceTool), - {"se", "qt[.]qt[0-9][.][0-9]+$", "-g", "*=false,ifw.package.*=true"}}, - 60 * 3, // 3 minutes timeout - /*workingDirectory=*/{}, - [](int /*exitCode*/) { return Utils::ProcessResult::FinishedWithSuccess; }); - } - d->m_checkUpdatesCommand->execute(); - d->m_progress = d->m_checkUpdatesCommand->futureProgress(); - if (d->m_progress) { - d->m_progress->setKeepOnFinish(FutureProgress::KeepOnFinishTillUserInteraction); - d->m_progress->setSubtitleVisibleInStatusBar(true); - } + QFutureInterface futureIf; + FutureProgress *futureProgress + = ProgressManager::addTimedTask(futureIf, + tr("Checking for Updates"), + Id("UpdateInfo.CheckingForUpdates"), + 60); + futureProgress->setKeepOnFinish(FutureProgress::KeepOnFinishTillUserInteraction); + futureProgress->setSubtitleVisibleInStatusBar(true); + connect(futureProgress, &FutureProgress::canceled, this, [this, futureIf]() mutable { + futureIf.reportCanceled(); + futureIf.reportFinished(); + stopCheckForUpdates(); + }); + + d->m_maintenanceToolProcess.reset(new QtcProcess); + d->m_maintenanceToolProcess->setCommand({Utils::FilePath::fromString(d->m_maintenanceTool), + {"ch", "-g", "*=false,ifw.package.*=true"}}); + d->m_maintenanceToolProcess->setTimeoutS(3 * 60); // 3 minutes + // TODO handle error + connect( + d->m_maintenanceToolProcess.get(), + &QtcProcess::done, + this, + [this, futureIf]() mutable { + if (d->m_maintenanceToolProcess->result() == ProcessResult::FinishedWithSuccess) { + d->m_updateOutput = d->m_maintenanceToolProcess->stdOut(); + if (d->m_settings.checkForQtVersions) { + d->m_maintenanceToolProcess.reset(new QtcProcess); + d->m_maintenanceToolProcess->setCommand( + {Utils::FilePath::fromString(d->m_maintenanceTool), + {"se", "qt[.]qt[0-9][.][0-9]+$", "-g", "*=false,ifw.package.*=true"}}); + d->m_maintenanceToolProcess->setTimeoutS(3 * 60); // 3 minutes + connect( + d->m_maintenanceToolProcess.get(), + &QtcProcess::done, + this, + [this, futureIf]() mutable { + if (d->m_maintenanceToolProcess->result() + == ProcessResult::FinishedWithSuccess) { + d->m_packagesOutput = d->m_maintenanceToolProcess->stdOut(); + d->m_maintenanceToolProcess.reset(); + futureIf.reportFinished(); + checkForUpdatesFinished(); + } else { + futureIf.reportCanceled(); // is used to indicate error + futureIf.reportFinished(); + } + }, + Qt::QueuedConnection); + d->m_maintenanceToolProcess->start(); + } else { + d->m_maintenanceToolProcess.reset(); + futureIf.reportFinished(); + checkForUpdatesFinished(); + } + } else { + futureIf.reportCanceled(); // is used to indicate error + futureIf.reportFinished(); + } + }, + Qt::QueuedConnection); + + d->m_maintenanceToolProcess->start(); + futureIf.reportStarted(); + emit checkForUpdatesRunningChanged(true); } void UpdateInfoPlugin::stopCheckForUpdates() { - if (!d->m_checkUpdatesCommand) + if (!d->m_maintenanceToolProcess) return; - d->m_collectedOutput.clear(); - d->m_checkUpdatesCommand->disconnect(); - d->m_checkUpdatesCommand->cancel(); - d->m_checkUpdatesCommand = nullptr; + d->m_maintenanceToolProcess->disconnect(); + d->m_maintenanceToolProcess.reset(); + d->m_updateOutput.clear(); + d->m_packagesOutput.clear(); emit checkForUpdatesRunningChanged(false); } -void UpdateInfoPlugin::collectCheckForUpdatesOutput(const QString &contents) -{ - d->m_collectedOutput += contents; -} - static void showUpdateInfo(const QList &updates, const std::function &startUpdater) { Utils::InfoBarEntry info(InstallUpdates, @@ -235,14 +274,15 @@ void UpdateInfoPlugin::checkForUpdatesFinished() { setLastCheckDate(QDate::currentDate()); - qCDebug(log) << "--- MaintenanceTool output (combined):"; - qCDebug(log) << qPrintable(d->m_collectedOutput); - std::unique_ptr document = documentForResponse(d->m_collectedOutput); + qCDebug(log) << "--- MaintenanceTool output (updates):"; + qCDebug(log) << qPrintable(d->m_updateOutput); + qCDebug(log) << "--- MaintenanceTool output (packages):"; + qCDebug(log) << qPrintable(d->m_packagesOutput); stopCheckForUpdates(); - const QList updates = availableUpdates(*document); - const QList qtPackages = availableQtPackages(*document); + const QList updates = availableUpdates(d->m_updateOutput); + const QList qtPackages = availableQtPackages(d->m_packagesOutput); if (log().isDebugEnabled()) { qCDebug(log) << "--- Available updates:"; for (const Update &u : updates) @@ -275,7 +315,7 @@ void UpdateInfoPlugin::checkForUpdatesFinished() bool UpdateInfoPlugin::isCheckForUpdatesRunning() const { - return d->m_checkUpdatesCommand; + return d->m_maintenanceToolProcess.get() != nullptr; } void UpdateInfoPlugin::extensionsInitialized() diff --git a/src/plugins/updateinfo/updateinfoplugin.h b/src/plugins/updateinfo/updateinfoplugin.h index 78177fee919..2dfcfe346d3 100644 --- a/src/plugins/updateinfo/updateinfoplugin.h +++ b/src/plugins/updateinfo/updateinfoplugin.h @@ -89,7 +89,6 @@ private: void startPackageManager(); void stopCheckForUpdates(); - void collectCheckForUpdatesOutput(const QString &contents); void checkForUpdatesFinished(); void loadSettings() const; diff --git a/src/plugins/updateinfo/updateinfotools.h b/src/plugins/updateinfo/updateinfotools.h index c8dd3a7fd07..0a977d344e2 100644 --- a/src/plugins/updateinfo/updateinfotools.h +++ b/src/plugins/updateinfo/updateinfotools.h @@ -34,23 +34,8 @@ #include #include -#include - Q_DECLARE_LOGGING_CATEGORY(log) -std::unique_ptr documentForResponse(const QString &response) -{ - // since the output can contain two toplevel items from the two separate MaintenanceTool runs, - // clean up any and surround with a toplevel element - QString responseWithoutHeader = response; - responseWithoutHeader.remove(QRegularExpression("<\\?xml.*\\?>")); - const QString xml = response.isEmpty() ? QString() - : ("" + responseWithoutHeader + ""); - std::unique_ptr doc(new QDomDocument); - doc->setContent(xml); - return doc; -} - struct Update { QString name; @@ -62,8 +47,10 @@ struct Update }; }; -QList availableUpdates(const QDomDocument &document) +QList availableUpdates(const QString &updateXml) { + QDomDocument document; + document.setContent(updateXml); if (document.isNull() || !document.firstChildElement().hasChildNodes()) return {}; QList result; @@ -93,8 +80,10 @@ struct QtPackage } }; -QList availableQtPackages(const QDomDocument &document) +QList availableQtPackages(const QString &packageXml) { + QDomDocument document; + document.setContent(packageXml); if (document.isNull() || !document.firstChildElement().hasChildNodes()) return {}; QList result; diff --git a/tests/auto/updateinfo/tst_updateinfo.cpp b/tests/auto/updateinfo/tst_updateinfo.cpp index 1fa1686919b..13cf71aa582 100644 --- a/tests/auto/updateinfo/tst_updateinfo.cpp +++ b/tests/auto/updateinfo/tst_updateinfo.cpp @@ -40,7 +40,8 @@ private slots: void tst_UpdateInfo::updates_data() { - QTest::addColumn("xml"); + QTest::addColumn("updateXml"); + QTest::addColumn("packageXml"); QTest::addColumn>("xupdates"); QTest::addColumn>("xpackages"); @@ -48,8 +49,8 @@ void tst_UpdateInfo::updates_data() << R"raw( - - + )raw" + << R"raw( @@ -64,14 +65,14 @@ void tst_UpdateInfo::updates_data() void tst_UpdateInfo::updates() { - QFETCH(QString, xml); + QFETCH(QString, updateXml); + QFETCH(QString, packageXml); QFETCH(QList, xupdates); QFETCH(QList, xpackages); - std::unique_ptr doc = documentForResponse(xml); - const QList updates = availableUpdates(*doc); + const QList updates = availableUpdates(updateXml); QCOMPARE(updates, xupdates); - const QList packages = availableQtPackages(*doc); + const QList packages = availableQtPackages(packageXml); QCOMPARE(packages, xpackages); }