repoindex/alpm/updatelookup.cpp

186 lines
7.3 KiB
C++

#include "updatelookup.h"
#include "manager.h"
#include "database.h"
#include "config.h"
#include <QNetworkReply>
#include <QtConcurrent/QtConcurrent>
#include <initializer_list>
using namespace std;
namespace PackageManagement {
UpdateLookup::UpdateLookup(const Manager &manager, const QJsonObject &request, const UpdateLookupCallback callback, QObject *parent) :
QObject(parent),
m_manager(manager),
m_request(request),
m_callback(callback),
m_db(nullptr),
m_syncDbsWatcher(new QFutureWatcher<UpdateLookupResults<AlpmPackage> >(this)),
m_aurWatcher(new QFutureWatcher<UpdateLookupResults<AurPackage> >(this)),
m_aurReply(nullptr),
m_sourcesAvailable(false)
{
QJsonArray errors;
const auto dbName = request.value(QStringLiteral("db")).toString();
try {
m_db = &manager.dataBaseByName(dbName);
} catch (const out_of_range &) {
errors << QStringLiteral("Database \"%1\" can not be found.").arg(dbName);
}
if(errors.isEmpty()) {
// invoke syncdb lookup
connect(m_syncDbsWatcher, &QFutureWatcher<UpdateLookupResults<AlpmPackage> >::finished, this, &UpdateLookup::lookupDone);
m_syncDbsWatcher->setFuture(QtConcurrent::run(this, &UpdateLookup::checkSyncDbs, request.value(QStringLiteral("syncdbs"))));
// invoke AUR lookup
if(m_db->upgradeSources().contains(QStringLiteral("aur"), Qt::CaseInsensitive) || request.value(QStringLiteral("aur")).toBool(false)) {
if(manager.config().isAurEnabled()) {
connect(&m_manager.aurQuery(), &AurQuery::packageInfoAvailable, this, &UpdateLookup::aurPackageInfoAvailable);
connect(m_aurWatcher, &QFutureWatcher<UpdateLookupResults<AurPackage> >::finished, this, &UpdateLookup::lookupDone);
if(!(m_aurReply = m_manager.aurQuery().requestPackageInfo(m_db->packageNames()))) {
aurPackageInfoAvailable(nullptr);
}
} else {
errors << QStringLiteral("The AUR is configured as upgrade source for the database \"%1\" but AUR queries are not enabled.").arg(dbName);
}
}
} else {
QJsonObject results;
results.insert(QStringLiteral("errors"), errors);
callback(move(results));
deleteLater();
}
}
UpdateLookupResults<AlpmPackage> UpdateLookup::checkSyncDbs(const QJsonValue &syncDbsValue)
{
UpdateLookupResults<AlpmPackage> results;
const auto &syncDbs = m_manager.syncDataBases();
QList<const AlpmDataBase *> syncDbSel;
if(syncDbsValue.type() == QJsonValue::Array) {
for(const auto &syncDbVal : syncDbsValue.toArray()) {
const auto syncDbName = syncDbVal.toString();
if(syncDbName == QLatin1String("local")) {
syncDbSel << &(m_manager.localDataBase());
} else if(syncDbName == QLatin1String("aur")) {
continue; // the AUR is checked separately
} else {
try {
syncDbSel << &(syncDbs.at(syncDbName));
} catch(out_of_range &) {
results.warnings << QStringLiteral("The specified sync database \"%1\" can not be found.").arg(syncDbName);
}
}
}
} else {
for(const auto &syncDbName : m_db->upgradeSources()) {
if(syncDbName == QLatin1String("local")) {
syncDbSel << &(m_manager.localDataBase());
} else if(syncDbName == QLatin1String("aur")) {
continue; // the AUR is checked separately
} else {
try {
syncDbSel << &(syncDbs.at(syncDbName));
} catch(out_of_range &) {
results.warnings << QStringLiteral("The associated upgrade database \"%1\" can not be found.").arg(syncDbName);
}
}
}
}
m_db->checkForUpgrades(syncDbSel, results);
return results;
}
void UpdateLookup::aurPackageInfoAvailable(const QNetworkReply *reply)
{
// check whether the package info requested by THIS INSTANCE is available
if(m_aurReply == reply) {
m_aurWatcher->setFuture(QtConcurrent::run(this, &UpdateLookup::checkAur));
}
}
UpdateLookupResults<AurPackage> UpdateLookup::checkAur()
{
UpdateLookupResults<AurPackage> results;
m_db->checkForUpgrades(m_manager.aurQuery().packages(), results);
return results;
}
void UpdateLookup::lookupDone()
{
const auto *sender = this->sender();
if(sender == static_cast<QObject *>(m_syncDbsWatcher)) {
// add results from syncdb lookup
m_syncDbsResults = m_syncDbsWatcher->result();
if(!m_syncDbsResults.noSources) {
m_sourcesAvailable = true;
for(const auto pkg : m_syncDbsResults.newVersions) {
m_softwareUpdates << pkg.json();
}
for(const auto pkg : m_syncDbsResults.newReleases) {
m_packageOnlyUpdates << pkg.json();
}
for(const auto pkg : m_syncDbsResults.downgrades) {
m_downgrades << pkg.json();
}
for(const auto &warning : m_syncDbsResults.warnings) {
m_warnings << warning;
}
for(const auto &error : m_syncDbsResults.errors) {
m_errors << error;
}
}
} else if(sender == static_cast<QObject *>(m_aurWatcher)) {
// add results from AUR lookup
m_aurResults = m_aurWatcher->result();
if(!m_aurResults.noSources) {
m_sourcesAvailable = true;
for(const auto pkg : m_aurResults.newVersions) {
m_softwareUpdates << pkg.json();
}
for(const auto pkg : m_aurResults.newReleases) {
m_packageOnlyUpdates << pkg.json();
}
for(const auto pkg : m_aurResults.downgrades) {
m_downgrades << pkg.json();
}
for(const auto &warning : m_aurResults.warnings) {
m_warnings << warning;
}
for(const auto &error : m_aurResults.errors) {
m_errors << error;
}
}
}
// check whether everything is done
if(m_syncDbsWatcher->isFinished() && (!m_aurReply || m_aurWatcher->isFinished())) {
QJsonObject results;
// determine orphaned packages
for(const auto pkg : m_aurReply ? m_aurResults.orphaned.intersect(m_syncDbsResults.orphaned) : m_syncDbsResults.orphaned) {
m_orphanedPackages << pkg.basicInfo(true);
}
// add results to results QJsonObject
results.insert(QStringLiteral("softwareUpdates"), m_softwareUpdates);
results.insert(QStringLiteral("packageOnlyUpdates"), m_packageOnlyUpdates);
results.insert(QStringLiteral("downgrades"), m_downgrades);
results.insert(QStringLiteral("orphanedPackages"), m_orphanedPackages);
if(!m_sourcesAvailable) {
m_errors << QStringLiteral("No update sources associated for database \"%1\".").arg(QString::fromLocal8Bit(m_db->name()));
}
if(!m_warnings.isEmpty()) {
results.insert(QStringLiteral("warnings"), m_warnings);
}
if(!m_errors.isEmpty()) {
results.insert(QStringLiteral("errors"), m_errors);
}
m_callback(move(results));
// lookup done, delete this helper object
deleteLater();
}
}
} // namespace PackageManagement