repoindex/alpm/repository.cpp

299 lines
8.8 KiB
C++

#include "repository.h"
#include "upgradelookup.h"
#include "utilities.h"
#include <QJsonObject>
#include <QNetworkReply>
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<alpm_db_usage_t>(0)),
m_sigLevel(static_cast<alpm_siglevel_t>(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<const Package *> Repository::packagesProviding(const Dependency &dependency) const
{
QList<const Package *> 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<Package *> Repository::packageByFilter(std::function<bool (const Package *)> pred)
{
QList<Package *> 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<const Repository *> &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