#include "repository.h" #include "upgradelookup.h" #include "utilities.h" #include #include using namespace std; namespace PackageManagement { /*! * \brief Constructs a new reply. */ Reply::Reply(QNetworkReply *networkReply) : m_networkReply(networkReply) { networkReply->setParent(this); connect(networkReply, &QNetworkReply::finished, this, &Reply::processData); } /*! * \fn PackageSource::type() * \brief Returns the type of the package source. */ /*! * \brief Returns a list of all package names. */ const QStringList PackageManagement::Repository::packageNames() const { QStringList names; names.reserve(m_packages.size()); for(const auto &entry : m_packages) { names << entry.first; } return names; } /*! * \brief Requests suggestions for the specified search phrase. * \returns Returns a reply object used for the request. The reply must be destroyed by the caller * using destroyLater() after resultsAvailable() has been emitted. */ SuggestionsReply *Repository::requestSuggestions(const QString &) const { return nullptr; } /*! * \class Repository * \brief The Repository class represents a repository (binary repositories as well as source-only repos). */ /*! * \brief Constructs a new repository (protected since this is a pure virtual class). */ Repository::Repository(const QString &name, QObject *parent) : QObject(parent), m_name(name), m_usage(static_cast(0)), m_sigLevel(static_cast(ALPM_SIGSTATUS_INVALID)) {} /*! * \brief Destroys the package source. */ Repository::~Repository() {} /*! * \brief Returns whether the repository only has sources but no binary packages. */ bool Repository::isSourceOnly() const { return true; } /*! * \brief Returns whether requests are required. * * AlpmDataBase instances load all available packages in the cache * at the beginning and hence do not require explicit requests. * * UserRepository instances on the other hand have an empty package * cache at the beginning so packages must be requested explicitely * using the requestPackageInfo() method. */ bool Repository::requestsRequired() const { return false; } /*! * \brief Requests package information for the specified package. * \returns Returns a reply object used for the request. The reply must be destroyed by the caller * using destroyLater() after resultsAvailable() has been emitted. * \remarks * If \a forceUpdate is true, package information which has already been retrieved * and is still cached is requested again. Otherwise these packages will not be * requested again. If it turns out, that all packages are already cached, nullptr * is returned in this case. */ PackageReply *Repository::requestPackageInfo(const QStringList &, bool ) const { return nullptr; } /*! * \brief Requests full package information for the specified package. * \returns Returns a reply object used for the request. The reply must be destroyed by the caller * using destroyLater() after resultsAvailable() has been emitted. * \remarks * If \a forceUpdate is true, package information which has already been retrieved * and is still cached is requested again. Otherwise these packages will not be * requested again. If it turns out, that all packages are already cached, nullptr * is returned in this case. */ PackageReply *Repository::requestFullPackageInfo(const QString &, bool ) const { return nullptr; } /*! * \brief Returns the first package providing the specified \a dependency. * \remarks Returns nullptr if no packages provides the \a dependency. */ const Package *Repository::packageProviding(const Dependency &dependency) const { for(const auto &entry : m_packages) { if(entry.second->matches(dependency)) { // check whether package matches "directly" return entry.second.get(); } else { // check whether at least one of the provides matches for(const auto &provide : entry.second->provides()) { if(Package::matches(provide.name, provide.version, dependency)) { return entry.second.get(); } } } } return nullptr; } /*! * \brief Returns all packages providing the specified \a dependency. */ QList Repository::packagesProviding(const Dependency &dependency) const { QList res; for(const auto &entry : m_packages) { if(entry.second->matches(dependency)) { // check whether package matches "directly" res << entry.second.get(); } else { // check whether at least one of the provides matches for(const auto &provide : entry.second->provides()) { if(Package::matches(provide.name, provide.version, dependency)) { res << entry.second.get(); break; } } } } return res; } /*! * \brief Returns all packages matching the specified predicate. */ QList Repository::packageByFilter(std::function pred) { QList packages; for(const auto &entry : m_packages) { if(pred(entry.second.get())) { packages << entry.second.get(); } } return packages; } QJsonArray Repository::upgradeSourcesJsonArray() const { QJsonArray sources; for(const auto *source : upgradeSources()) { sources << source->name(); } return sources; } void Repository::checkForUpgrades(UpgradeLookupResults &results, const QList &upgradeSources) const { if(upgradeSources.isEmpty()) { results.noSources = true; } else { for(const auto &pkgEntry : packages()) { bool orphaned = true; for(const auto *src : upgradeSources) { if(const auto *syncPkg = src->packageByName(pkgEntry.first)) { switch(pkgEntry.second->compareVersion(syncPkg)) { case PackageVersionComparsion::Equal: break; // ignore equal packages case PackageVersionComparsion::SoftwareUpgrade: results.newVersions << UpgradeResult(syncPkg, pkgEntry.second->version()); break; case PackageVersionComparsion::PackageUpgradeOnly: results.newReleases << UpgradeResult(syncPkg, pkgEntry.second->version()); break; case PackageVersionComparsion::NewerThenSyncVersion: results.downgrades << UpgradeResult(syncPkg, pkgEntry.second->version()); } orphaned = false; } } if(orphaned) { results.orphaned << pkgEntry.second.get(); } } } } /*! * \brief Returns all package names as JSON array. */ QJsonArray Repository::packageNamesJsonArray() const { QJsonArray names; for(const auto &entry : m_packages) { names << entry.first; } return names; } /*! * \cond */ inline void put(QJsonObject &obj, const QString &key, const QJsonValue &value) { if(!value.isNull()) { obj.insert(key, value); } } inline void put(QJsonObject &obj, const QString &key, const QStringList &values) { if(!values.isEmpty()) { put(obj, key, QJsonArray::fromStringList(values)); } } /*! * \endcond */ /*! * \brief Returns basic information about the repository. */ QJsonObject Repository::basicInfo() const { QJsonObject info; put(info, QStringLiteral("name"), name()); put(info, QStringLiteral("desc"), description()); put(info, QStringLiteral("servers"), serverUrls()); put(info, QStringLiteral("usage"), Utilities::usageStrings(usage())); put(info, QStringLiteral("sigLevel"), Utilities::sigLevelStrings(sigLevel())); put(info, QStringLiteral("upgradeSources"), upgradeSourcesJsonArray()); put(info, QStringLiteral("packages"), packageNamesJsonArray()); put(info, QStringLiteral("requestRequired"), requestsRequired()); put(info, QStringLiteral("srcOnly"), isSourceOnly()); return info; } /*! * \brief Returns group information as JSON object. */ QJsonObject Repository::groupInfo() const { QJsonObject info; put(info, QStringLiteral("repo"), name()); QJsonArray groupsArray; for(const auto &groupEntry : groups()) { QJsonObject info; put(info, QStringLiteral("name"), groupEntry.first); QJsonArray pkgNames; for(const auto *pkg : groupEntry.second) { pkgNames << pkg->name(); } put(info, QStringLiteral("pkgs"), pkgNames); groupsArray << info; } info.insert(QStringLiteral("groups"), groupsArray); return info; } } // namespace PackageManagement