#include "upgradelookup.h" #include "manager.h" #include "alpmdatabase.h" #include "config.h" #include #include using namespace std; namespace RepoIndex { QJsonObject UpgradeResult::json() const { QJsonObject obj; obj.insert(QStringLiteral("pkg"), package->basicInfo(true)); obj.insert(QStringLiteral("prevVersion"), previousVersion); return obj; } UpgradeLookupProcess::UpgradeLookupProcess(UpgradeLookup *upgradeLookup, const Repository *upgradeSource) : QObject(upgradeLookup), m_toCheck(upgradeLookup->toCheck()), m_upgradeSource(upgradeSource), m_reply(nullptr), m_watcher(new QFutureWatcher(this)) { connect(this, &UpgradeLookupProcess::finished, upgradeLookup, &UpgradeLookup::processFinished); switch(m_upgradeSource->requestsRequired()) { case PackageDetailAvailability::Request: m_reply = m_upgradeSource->requestPackageInfo(m_toCheck->packageNames()); break; case PackageDetailAvailability::FullRequest: m_reply = m_upgradeSource->requestFullPackageInfo(m_toCheck->packageNames()); break; case PackageDetailAvailability::Never: m_results.errors << QStringLiteral("Repository \"%1\" does not provide the required information.").arg(m_upgradeSource->name()); emit finished(); return; case PackageDetailAvailability::Immediately: break; } if(m_reply) { m_reply->setParent(this); connect(m_reply, &PackageReply::resultsAvailable, this, &UpgradeLookupProcess::sourceReady); } else { sourceReady(); } } const UpgradeLookupResults &UpgradeLookupProcess::results() const { return m_results; } void UpgradeLookupProcess::sourceReady() { // if a request was required, check whether there occured an error if(m_reply && !m_reply->error().isEmpty()) { m_results.errors << m_reply->error(); emit finished(); } else { connect(m_watcher, &QFutureWatcher::finished, this, &UpgradeLookupProcess::finished); m_watcher->setFuture(QtConcurrent::run(this, &UpgradeLookupProcess::checkUpgrades)); } } void UpgradeLookupProcess::checkUpgrades() { m_toCheck->checkForUpgrades(m_results, QList() << m_upgradeSource); } UpgradeLookup::UpgradeLookup(const Manager &manager, const QJsonObject &request, QObject *parent) : QObject(parent), m_request(request), m_toCheck(nullptr), m_remainingProcesses(0), m_firstFinished(false) { const auto toCheckName = request.value(QStringLiteral("db")).toString(); if((m_toCheck = manager.repositoryByName(toCheckName))) { // construct upgrade lookup processes const auto syncDbsArray = request.value(QStringLiteral("syncdbs")).toArray(); if(syncDbsArray.isEmpty()) { for(const auto *src : m_toCheck->upgradeSources()) { new UpgradeLookupProcess(this, src); ++m_remainingProcesses; } } else { for(const auto &syncDbValue : syncDbsArray) { const auto syncDbName = syncDbValue.toString(); if(const auto *src = manager.repositoryByName(syncDbName)) { new UpgradeLookupProcess(this, src); ++m_remainingProcesses; } else { m_warningsArray << QStringLiteral("The specified upgrade source \"%1\" can not be found.").arg(syncDbName); } } } // check whether any processes could be constructed if(!m_remainingProcesses) { m_errorsArray << QStringLiteral("No upgrade sources associated for repository \"%1\".").arg(m_toCheck->name()); } else { return; // no errors so far } } else { m_errorsArray << QStringLiteral("Repository \"%1\" can not be found.").arg(toCheckName); } // there are errors QJsonObject results; results.insert(QStringLiteral("errors"), m_errorsArray); emit resultsAvailable(request.value(QStringLiteral("what")), request.value(QStringLiteral("id")), results); deleteLater(); } void UpgradeLookup::processFinished() { assert(m_remainingProcesses); // add results const auto &results = static_cast(sender())->results(); for(const auto pkg : results.newVersions) { m_softwareUpdatesArray << pkg.json(); } for(const auto pkg : results.newReleases) { m_packageOnlyUpdatesArray << pkg.json(); } for(const auto pkg : results.downgrades) { m_downgradesArray << pkg.json(); } for(const auto &warning : results.warnings) { m_warningsArray << warning; } for(const auto &error : results.errors) { m_errorsArray << error; } if(m_firstFinished) { m_orphanedPackages = m_orphanedPackages.intersect(results.orphaned); } else { m_firstFinished = true; m_orphanedPackages = results.orphaned; } // check whether all processes are finished if(--m_remainingProcesses == 0) { // finally make info for orphanded packages for(const auto *pkg : m_orphanedPackages) { m_orphanedPackagesArray << pkg->basicInfo(true); } // add results to results QJsonObject QJsonObject results; results.insert(QStringLiteral("softwareUpdates"), m_softwareUpdatesArray); results.insert(QStringLiteral("packageOnlyUpdates"), m_packageOnlyUpdatesArray); results.insert(QStringLiteral("downgrades"), m_downgradesArray); results.insert(QStringLiteral("orphanedPackages"), m_orphanedPackagesArray); if(!m_warningsArray.isEmpty()) { results.insert(QStringLiteral("warnings"), m_warningsArray); } if(!m_errorsArray.isEmpty()) { results.insert(QStringLiteral("errors"), m_errorsArray); } emit resultsAvailable(m_request.value(QStringLiteral("what")), m_request.value(QStringLiteral("id")), results); // lookup done, delete this helper object deleteLater(); } } } // namespace PackageManagement