restructured a lot of classes

This commit is contained in:
Martchus 2015-09-04 14:37:01 +02:00
parent 8f32dd0da0
commit c6d3ea2d8e
44 changed files with 2951 additions and 1852 deletions

90
alpm/alpmdatabase.cpp Normal file
View File

@ -0,0 +1,90 @@
#include "alpmdatabase.h"
#include "group.h"
#include "upgradelookup.h"
#include "alpmpackage.h"
#include "utilities.h"
#include <c++utilities/misc/memory.h>
#include <QList>
#include <QJsonObject>
using namespace std;
namespace PackageManagement {
using namespace Utilities;
/*!
* \brief The AlpmDataBase class wraps an ALPM data base struct and holds additional meta information.
*
* All packages returned by the AlpmDataBase class are AlpmPackage instances.
*/
/*!
* \brief Creates a new instance wrapping the specified database struct.
*/
PackageManagement::AlpmDataBase::AlpmDataBase(alpm_db_t *dataBase, const QString &dbPath, QObject *parent) :
Repository(QString::fromLocal8Bit(alpm_db_get_name(dataBase)), parent),
m_ptr(dataBase),
m_dbFile(QStringLiteral("%1/sync/%2").arg(dbPath, m_name))
{
if(alpm_db_get_usage(dataBase, &m_usage)) {
m_usage = static_cast<decltype(m_usage)>(ALPM_DB_USAGE_ALL);
}
if(m_name.compare(QLatin1String("local"), Qt::CaseInsensitive) == 0) {
m_description = QStringLiteral("The local database");
} else {
if((m_usage & ALPM_DB_USAGE_SYNC) || (m_usage & ALPM_DB_USAGE_INSTALL) || (m_usage & ALPM_DB_USAGE_UPGRADE)) {
m_description = QStringLiteral("Sync database »%1«").arg(m_name);
} else {
m_description = QStringLiteral("Database »%1«").arg(m_name);
}
}
for(auto *nativePkg : PackageList(alpm_db_get_pkgcache(m_ptr))) {
auto pkg = make_unique<AlpmPackage>(nativePkg, this);
QString pkgName = pkg->name();
for(const auto &grpName : pkg->groups()) {
m_groups[grpName] << pkg.get();
}
m_packages.emplace(pkgName, move(pkg));
}
for(const char *str : servers()) {
m_serverUrls << qstr(str);
}
m_sigLevel = alpm_db_get_siglevel(m_ptr);
}
//AlpmDataBase::AlpmDataBase(const QString &dataBaseFile, QObject *parent) :
// PackageSource(parent),
// m_ptr(nullptr)
//{}
RepositoryType AlpmDataBase::type() const
{
return RepositoryType::AlpmDataBase;
}
bool AlpmDataBase::isSourceOnly() const
{
return false;
}
/*!
* \brief Adds the specified server URLs.
*/
bool AlpmDataBase::addServerUrls(const QStringList &urls)
{
bool res = true;
for(const auto &url : urls) {
if(alpm_db_add_server(m_ptr, url.toLocal8Bit().data()) != 0) {
res = false;
} else {
m_serverUrls << url;
}
}
return res;
}
} // namespace Alpm

97
alpm/alpmdatabase.h Normal file
View File

@ -0,0 +1,97 @@
#ifndef ALPM_DATABASE_H
#define ALPM_DATABASE_H
#include "repository.h"
#include "list.h"
#include <alpm.h>
#include <QJsonArray>
namespace PackageManagement {
class AlpmDataBase : public Repository
{
public:
explicit AlpmDataBase(alpm_db_t *dataBase, const QString &dbPath, QObject *parent = nullptr);
// explicit AlpmDataBase(const QString &dataBaseFile, QObject *parent = nullptr);
RepositoryType type() const;
bool isSourceOnly() const;
// operators
bool operator ==(const AlpmDataBase &other) const;
bool operator !=(const AlpmDataBase &other) const;
// database meta data
alpm_db_t *ptr();
const QString &dataBaseFile() const;
StringList servers() const;
bool setServers(StringList servers);
bool addServerUrls(const QStringList &urls);
PackageList search(StringList terms) const;
private:
alpm_db_t *m_ptr;
QString m_dbFile;
};
/*!
* \brief Checks whether the specified ALPM database is equal the current instance.
*/
inline bool AlpmDataBase::operator ==(const AlpmDataBase &other) const
{
return m_ptr == other.m_ptr;
}
/*!
* \brief Checks whether the specified ALPM database is not equal to the current instance.
*/
inline bool AlpmDataBase::operator !=(const AlpmDataBase &other) const
{
return m_ptr != other.m_ptr;
}
/*!
* \brief Returns the pointer to the underlying database struct.
*/
inline alpm_db_t *AlpmDataBase::ptr()
{
return m_ptr;
}
/*!
* \brief Returns the path of the data base file.
*/
inline const QString &AlpmDataBase::dataBaseFile() const
{
return m_dbFile;
}
/*!
* \brief Returns the servers of the database.
*/
inline StringList AlpmDataBase::servers() const
{
return alpm_db_get_servers(m_ptr);
}
/*!
* \brief Sets the servers of the database.
*/
inline bool AlpmDataBase::setServers(StringList servers)
{
return alpm_db_set_servers(m_ptr, servers.begin().ptr()) == 0;
}
/*!
* \brief Performs a search using the build in ALPM function.
*/
inline PackageList AlpmDataBase::search(StringList terms) const
{
return alpm_db_search(m_ptr, terms.begin().ptr());
}
} // namespace Alpm
#endif // ALPM_DATABASE_H

92
alpm/alpmpackage.cpp Normal file
View File

@ -0,0 +1,92 @@
#include "alpmpackage.h"
#include "alpmdatabase.h"
#include "utilities.h"
#include <QJsonObject>
using namespace ChronoUtilities;
namespace PackageManagement {
/*!
* \cond
*/
namespace Utilities {
inline QList<Dependency> depinfos(DependencyList list)
{
QList<Dependency> infos;
for(const auto *dep : list) {
infos << Dependency(qstr(dep->name), qstr(dep->version), dep->mod);
}
return infos;
}
}
/*!
* \endcond
*/
using namespace Utilities;
/*!
* \brief The AlpmPackage class wraps an ALPM package struct and holds additional meta information.
*/
/*!
* \brief Constructs a new package instance for the specified ALPM \a package.
*/
AlpmPackage::AlpmPackage(alpm_pkg_t *package, AlpmDataBase *source) :
Package(QString::fromLocal8Bit(alpm_pkg_get_name(package)), source),
m_ptr(package)
{
m_origin = static_cast<PackageOrigin>(alpm_pkg_get_origin(package));
m_hasGeneralInfo = m_hasBuildRelatedMetaData = m_hasInstallRelatedMetaData = true;
m_version = qstr(alpm_pkg_get_version(package));
m_description = qstr(alpm_pkg_get_desc(package));
m_upstreamUrl = qstr(alpm_pkg_get_url(package));
m_licenses = qstrlist(alpm_pkg_get_licenses(package));
m_groups = qstrlist(alpm_pkg_get_groups(package));
m_dependencies = depinfos(alpm_pkg_get_depends(package));
m_optionalDependencies = depinfos(alpm_pkg_get_optdepends(package));
m_conflicts = depinfos(alpm_pkg_get_conflicts(package));
m_provides = depinfos(alpm_pkg_get_provides(package));
m_replaces = depinfos(alpm_pkg_get_replaces(package));
alpm_list_t *tmp;
m_requiredBy = qstrlist(tmp = alpm_pkg_compute_requiredby(package));
FREELIST(tmp);
m_optionalFor = qstrlist(tmp = alpm_pkg_compute_optionalfor(package));
FREELIST(tmp);
m_hasInstallScript = alpm_pkg_has_scriptlet(package);
m_fileName = qstr(alpm_pkg_get_filename(package));
m_buildDate = DateTime::fromTimeStamp(alpm_pkg_get_builddate(package));
m_packer = qstr(alpm_pkg_get_packager(package));
m_md5 = qstr(alpm_pkg_get_md5sum(package));
m_sha256 = qstr(alpm_pkg_get_sha256sum(package));
m_buildArchitecture = qstr(alpm_pkg_get_arch(package));
m_packageSize = alpm_pkg_get_size(package);
m_installDate = DateTime::fromTimeStamp(alpm_pkg_get_installdate(package));
m_installedSize = alpm_pkg_get_isize(package);
for(const auto *backupEntry : BackupList(alpm_pkg_get_backup(package))) {
m_backupFiles << qstr(backupEntry->name);
}
m_validationMethods = alpm_pkg_get_validation(package);
m_installReason = alpm_pkg_get_reason(package);
alpm_filelist_t *fileList = alpm_pkg_get_files(package);
for(alpm_file_t *file = fileList->files, *end = fileList->files + fileList->count; file != end; ++file) {
QJsonObject fileInfo;
fileInfo.insert(QStringLiteral("name"), qstr(file->name));
if(file->mode) {
fileInfo.insert(QStringLiteral("mode"), static_cast<int>(file->mode));
}
if(file->size) {
fileInfo.insert(QStringLiteral("size"), static_cast<int>(file->size));
}
m_files << fileInfo;
}
}
} // namespace PackageManagement

108
alpm/alpmpackage.h Normal file
View File

@ -0,0 +1,108 @@
#ifndef PACKAGEMANAGEMENT_ALPMPACKAGE_H
#define PACKAGEMANAGEMENT_ALPMPACKAGE_H
#include "package.h"
namespace PackageManagement {
class AlpmDataBase;
class AlpmPackage : public Package
{
public:
AlpmPackage(alpm_pkg_t *package, AlpmDataBase *source = nullptr);
// ALPM specific meta data
const alpm_pkg_t *ptr() const;
alpm_pkg_t *ptr();
const char *base64Signature() const;
void *openChangelog() const;
size_t readChangelog(void *changelog, void *buffer, size_t bufferSize);
bool closeChangelog(void *changelog);
protected:
alpm_pkg_t *m_ptr;
};
inline uint qHash(const AlpmPackage &key)
{
return qHash(key.ptr());
}
/*!
* \brief Returns a pointer to the underlying alpm_pkg_t.
*/
inline const alpm_pkg_t *AlpmPackage::ptr() const
{
return m_ptr;
}
/*!
* \brief Returns a pointer to the underlying alpm_pkg_t.
*/
inline alpm_pkg_t *AlpmPackage::ptr()
{
return m_ptr;
}
inline const char *AlpmPackage::base64Signature() const
{
return alpm_pkg_get_base64_sig(m_ptr);
}
inline void *AlpmPackage::openChangelog() const
{
return alpm_pkg_changelog_open(m_ptr);
}
inline size_t AlpmPackage::readChangelog(void *changelog, void *buffer, size_t bufferSize)
{
return alpm_pkg_changelog_read(buffer, bufferSize, m_ptr, changelog);
}
inline bool AlpmPackage::closeChangelog(void *changelog)
{
return alpm_pkg_changelog_close(m_ptr, changelog);
}
class AlpmOwnershipPackage : public AlpmPackage
{
public:
// constructor, destructor
AlpmOwnershipPackage(alpm_pkg_t *package);
AlpmOwnershipPackage(const AlpmOwnershipPackage &other) = delete;
AlpmOwnershipPackage(AlpmOwnershipPackage &&other);
~AlpmOwnershipPackage();
// assignment operator
AlpmOwnershipPackage &operator =(const AlpmOwnershipPackage &other) = delete;
AlpmOwnershipPackage &operator =(AlpmOwnershipPackage &&other);
};
inline AlpmOwnershipPackage::AlpmOwnershipPackage(alpm_pkg_t *package) :
AlpmPackage(package)
{}
inline AlpmOwnershipPackage::AlpmOwnershipPackage(AlpmOwnershipPackage &&other) :
AlpmPackage(other.m_ptr)
{
other.m_ptr = nullptr;
}
inline AlpmOwnershipPackage &AlpmOwnershipPackage::operator =(AlpmOwnershipPackage &&other)
{
if(this != &other) {
m_ptr = other.m_ptr;
other.m_ptr = nullptr;
}
return *this;
}
inline AlpmOwnershipPackage::~AlpmOwnershipPackage()
{
alpm_pkg_free(ptr());
}
} // namespace PackageManagement
#endif // PACKAGEMANAGEMENT_ALPMPACKAGE_H

41
alpm/aurpackage.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "aurpackage.h"
#include "network/userrepository.h"
#include <QJsonObject>
using namespace ChronoUtilities;
namespace PackageManagement {
/*!
* \brief The AurPackage class holds information about AUR packages. It allows to convert the information
* to JSON objects used by the network classes and the web interface.
*/
/*!
* \brief Creates a new instance from the specified "AurJson value".
*/
AurPackage::AurPackage(const QJsonValue &aurJsonValue, UserRepository *source) :
Package(QString(), source)
{
m_origin = PackageOrigin::Aur;
QJsonObject obj = aurJsonValue.toObject();
m_name = obj.value(QStringLiteral("Name")).toString();
m_hasGeneralInfo = true;
m_id = obj.value(QStringLiteral("ID")).toInt(-1);
m_categoryId = obj.value(QStringLiteral("CategoryID")).toInt(-1);
m_version = obj.value(QStringLiteral("Version")).toString();
m_description = obj.value(QStringLiteral("Description")).toString();
m_upstreamUrl = obj.value(QStringLiteral("URL")).toString();
m_votes = obj.value(QStringLiteral("NumVotes")).toInt(0);
m_outOfDate = DateTime::fromTimeStamp(obj.value(QStringLiteral("OutOfDate")).toInt());
m_maintainer = obj.value(QStringLiteral("Maintainer")).toString();
m_firstSubmitted = DateTime::fromTimeStamp(obj.value(QStringLiteral("FirstSubmitted")).toInt());
m_lastModified = DateTime::fromTimeStamp(obj.value(QStringLiteral("LastModified")).toInt());
m_licenses << obj.value(QStringLiteral("License")).toString();
m_tarUrl = obj.value(QStringLiteral("URLPath")).toString();
}
} // namespace PackageManagement

18
alpm/aurpackage.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef PACKAGEMANAGEMENT_AURPACKAGE_H
#define PACKAGEMANAGEMENT_AURPACKAGE_H
#include "package.h"
namespace PackageManagement {
class UserRepository;
class AurPackage : public Package
{
public:
AurPackage(const QJsonValue &aurJsonValue, UserRepository *source);
};
} // namespace PackageManagement
#endif // PACKAGEMANAGEMENT_AURPACKAGE_H

View File

@ -40,7 +40,11 @@ ConfigArgs::ConfigArgs(ArgumentParser &parser) :
insecureArg("insecure", string(), "forces the server to run in insecure mode"),
aurArg("aur", "u", "enables/disables AUR queries"),
verboseArg("verbose", "v", "be verbose"),
outputFileArg("output-file", "f", "specifies the output file")
outputFileArg("output-file", "f", "specifies the output file"),
targetDirArg("target-dir", "t", "the directory to store the target archive"),
targetNameArg("target-name", "n", "specifies the name of the target archive"),
targetFormatArg("target-format", "e", "specifies the format of the target archive"),
iconThemesArg("icon-packages", "i", "specifies the names of the icon packages to include")
{
const initializer_list<string> pathValueName = {"path"};
const initializer_list<string> pkgValueNames = {"package 1", "package 2", "package 3"};
@ -83,10 +87,23 @@ ConfigArgs::ConfigArgs(ArgumentParser &parser) :
outputFileArg.setCombinable(true);
outputFileArg.setRequired(true);
outputFileArg.setRequiredValueCount(1);
outputFileArg.setValueNames({"path"});
outputFileArg.setValueNames(pathValueName);
targetDirArg.setCombinable(true);
targetDirArg.setRequiredValueCount(1);
targetDirArg.setValueNames(pathValueName);
targetNameArg.setCombinable(true);
targetNameArg.setRequired(true);
targetNameArg.setRequiredValueCount(1);
targetNameArg.setValueNames({"name"});
targetFormatArg.setCombinable(true);
targetFormatArg.setRequiredValueCount(1);
targetFormatArg.setValueNames({"zip/7z/tar.gz/tar.bz/tar.xz"});
iconThemesArg.setCombinable(true);
iconThemesArg.setRequiredValueCount(-1);
iconThemesArg.setValueNames(pkgValueNames);
serverArg.setSecondaryArguments({&rootdirArg, &dbpathArg, &pacmanConfArg, &certFileArg, &keyFileArg, &insecureArg, &aurArg});
buildOrderArg.setSecondaryArguments({&aurArg, &verboseArg});
mingwBundleArg.setSecondaryArguments({&outputFileArg});
mingwBundleArg.setSecondaryArguments({&targetDirArg, &targetNameArg, &targetFormatArg, &iconThemesArg});
parser.setMainArguments({&buildOrderArg, &serverArg, &mingwBundleArg, &repoindexConfArg, &repoindexConfArg, &helpArg});
}
@ -271,7 +288,10 @@ void RepoEntry::load(const QJsonValue &jsonValue)
m_upgradeSources << str;
}
}
m_sigLevel = Manager::parseSigLevel(obj.value(QStringLiteral("sigLevel")).toString().toLocal8Bit().data());
const auto sigLevelValue = obj.value(QStringLiteral("sigLevel"));
if(sigLevelValue.isString()) {
m_sigLevel = Manager::parseSigLevel(sigLevelValue.toString().toLocal8Bit().data());
}
}
} // namespace Alpm

View File

@ -7,9 +7,7 @@
#include <QStringList>
#include <QHostAddress>
QT_BEGIN_NAMESPACE
class QJsonValue;
QT_END_NAMESPACE
QT_FORWARD_DECLARE_CLASS(QJsonValue)
namespace PackageManagement {
@ -33,6 +31,10 @@ public:
ApplicationUtilities::Argument aurArg;
ApplicationUtilities::Argument verboseArg;
ApplicationUtilities::Argument outputFileArg;
ApplicationUtilities::Argument targetDirArg;
ApplicationUtilities::Argument targetNameArg;
ApplicationUtilities::Argument targetFormatArg;
ApplicationUtilities::Argument iconThemesArg;
};
class Config;

View File

@ -1,149 +0,0 @@
#include "database.h"
#include "group.h"
#include "updatelookup.h"
#include <QList>
#include <QJsonObject>
using namespace std;
namespace PackageManagement {
/*!
* \brief The AlpmDataBase class wraps an ALPM database.
*/
/*!
* \brief Returns the usage of the database.
*/
alpm_db_usage_t AlpmDataBase::usage() const
{
alpm_db_usage_t usage;
if(!alpm_db_get_usage(m_ptr, &usage)) {
return usage;
} else {
return static_cast<alpm_db_usage_t>(ALPM_DB_USAGE_ALL); // return default usage
}
}
/*!
* \brief Returns the server URLs.
*/
const QJsonArray &AlpmDataBase::serverUrls() const
{
if(m_serverUrls.empty()) {
for(const char *str : servers()) {
m_serverUrls << str;
}
}
return m_serverUrls;
}
/*!
* \brief Adds the specified server URLs.
*/
bool AlpmDataBase::addServerUrls(const QStringList &urls)
{
m_serverUrls = QJsonArray();
for(const auto &url : urls) {
if(alpm_db_add_server(m_ptr, url.toLocal8Bit().data()) != 0) {
return false;
}
}
return true;
}
/*!
* \brief Returns the packages of the database.
*/
const std::map<QString, AlpmPackage> &AlpmDataBase::packages() const
{
if(m_packages.empty()) {
for(const AlpmPackage &pkg : PackageList(alpm_db_get_pkgcache(m_ptr))) {
m_packages.emplace(QString::fromLocal8Bit(pkg.name()), pkg);
}
}
return m_packages;
}
/*!
* \brief Returns the package names of the data base as QStringList.
*/
QStringList AlpmDataBase::packageNames() const
{
QStringList packageNames;
packageNames.reserve(packages().size());
for(const auto &pkg : packages()) {
packageNames << pkg.first;
}
return packageNames;
}
/*!
* \brief Returns the package names of the data base as a QJsonArray.
*/
const QJsonArray &AlpmDataBase::packageNameJsonArray() const
{
if(m_packageNamesJsonArray.empty()) {
for(const auto &pkg : packages()) {
m_packageNamesJsonArray << pkg.first;
}
}
return m_packageNamesJsonArray;
}
/*!
* \brief Returns group info (group name + package names).
*/
QJsonObject AlpmDataBase::groupInfo() const
{
QJsonObject groupInfo;
groupInfo.insert(QStringLiteral("repo"), QString::fromLocal8Bit(name()));
QJsonArray groupsArray;
for(const AlpmGroup group : groups()) {
QJsonObject info;
info.insert(QStringLiteral("name"), QString::fromLocal8Bit(group.name()));
info.insert(QStringLiteral("pkgs"), group.packageNames());
groupsArray << info;
}
groupInfo.insert(QStringLiteral("groups"), groupsArray);
return groupInfo;
}
void AlpmDataBase::checkForUpgrades(const QList<const AlpmDataBase *> &syncDbs, UpdateLookupResults<AlpmPackage> &results) const
{
if(syncDbs.isEmpty()) {
results.noSources = true;
} else {
for(const auto &dbPkg : packages()) {
bool orphaned = true;
for(const auto *syncDb : syncDbs) {
const auto &syncDbPkgs = syncDb->packages();
try {
const auto &syncPkg = syncDbPkgs.at(dbPkg.first);
switch(dbPkg.second.compareVersion(syncPkg)) {
case PackageVersionComparsion::Equal:
break; // ignore equal packages
case PackageVersionComparsion::SoftwareUpgrade:
results.newVersions << makeUpdateResult(syncPkg, dbPkg.second.version());
break;
case PackageVersionComparsion::PackageUpgradeOnly:
results.newReleases << makeUpdateResult(syncPkg, dbPkg.second.version());
break;
case PackageVersionComparsion::NewerThenSyncVersion:
results.downgrades << makeUpdateResult(syncPkg, dbPkg.second.version());
}
orphaned = false;
} catch(out_of_range &) {
}
}
if(orphaned) {
results.orphaned << dbPkg.second;
}
}
}
}
} // namespace Alpm

View File

@ -1,256 +0,0 @@
#ifndef ALPM_DATABASE_H
#define ALPM_DATABASE_H
#include "list.h"
#include "updatelookup.h"
#include <alpm.h>
#include <QJsonArray>
#include <QList>
#include <map>
namespace PackageManagement {
class AlpmDataBase
{
public:
AlpmDataBase(alpm_db_t *dataBase = nullptr, const QString &dbFile = QString(), const QString &srcDir = QString(), const QString &pkgDir = QString());
// operators
operator bool() const;
bool operator ==(const AlpmDataBase &other) const;
bool operator !=(const AlpmDataBase &other) const;
// database properties
alpm_db_t *ptr() const;
const char *name() const;
const QString &dataBaseFile() const;
const QString &sourcesDirectory() const;
void setSourcesDirectory(const QString &dir);
const QString &packagesDirectory() const;
void setPackagesDirectory(const QString &dir);
alpm_siglevel_t sigLevel() const;
alpm_db_usage_t usage() const;
StringList servers() const;
bool setServers(StringList servers);
const QJsonArray &serverUrls() const;
bool addServerUrls(const QStringList &urls);
alpm_pkg_t *package(const char *name) const;
const std::map<QString, AlpmPackage> &packages() const;
QStringList packageNames() const;
const QJsonArray &packageNameJsonArray() const;
alpm_group_t *group(const char *name) const;
GroupList groups() const;
QJsonObject groupInfo() const;
PackageList search(StringList terms) const;
// upgrade lookup
const QStringList &upgradeSources() const;
QStringList &upgradeSources();
template<class SyncPackageType>
void checkForUpgrades(const std::map<QString, SyncPackageType> &syncDbPkgs, UpdateLookupResults<SyncPackageType> &results) const;
void checkForUpgrades(const QList<const AlpmDataBase *> &syncDbs, UpdateLookupResults<AlpmPackage> &results) const;
private:
alpm_db_t *m_ptr;
QString m_dbFile;
QString m_srcDir;
QString m_pkgDir;
QStringList m_upgradeSources;
mutable QJsonArray m_serverUrls;
mutable std::map<QString, AlpmPackage> m_packages;
mutable QJsonArray m_packageNamesJsonArray;
mutable QJsonArray m_groupInfo;
};
/*!
* \brief Creates a new instance wrapping the specified database struct.
*/
inline AlpmDataBase::AlpmDataBase(alpm_db_t *dataBase, const QString &dbFile, const QString &srcDir, const QString &pkgDir) :
m_ptr(dataBase),
m_dbFile(dbFile),
m_srcDir(srcDir),
m_pkgDir(pkgDir)
{}
/*!
* \brief Checks whether the specified ALPM database is equal to the current instance.
*/
inline bool AlpmDataBase::operator ==(const AlpmDataBase &other) const
{
return m_ptr == other.m_ptr;
}
/*!
* \brief Checks whether the specified ALPM database is not equal to the current instance.
*/
inline bool AlpmDataBase::operator !=(const AlpmDataBase &other) const
{
return m_ptr != other.m_ptr;
}
/*!
* \brief Returns the pointer to the underlying database struct.
*/
inline alpm_db_t *AlpmDataBase::ptr() const
{
return m_ptr;
}
/*!
* \brief Returns the name of the database.
*/
inline const char *AlpmDataBase::name() const
{
return alpm_db_get_name(m_ptr);
}
/*!
* \brief Returns the path of the data base file.
*/
inline const QString &AlpmDataBase::dataBaseFile() const
{
return m_dbFile;
}
/*!
* \brief Returns the path of the local sources directory.
*/
inline const QString &AlpmDataBase::sourcesDirectory() const
{
return m_srcDir;
}
/*!
* \brief Sets the path of the local sources directory.
*/
inline void AlpmDataBase::setSourcesDirectory(const QString &dir)
{
m_srcDir = dir;
}
/*!
* \brief Returns the path of the local packages directory.
*/
inline const QString &AlpmDataBase::packagesDirectory() const
{
return m_pkgDir;
}
/*!
* \brief Sets the path of the local packages directory.
*/
inline void AlpmDataBase::setPackagesDirectory(const QString &dir)
{
m_pkgDir = dir;
}
/*!
* \brief Returns the signature level of the database.
*/
inline alpm_siglevel_t AlpmDataBase::sigLevel() const
{
return alpm_db_get_siglevel(m_ptr);
}
/*!
* \brief Returns the servers of the database.
*/
inline StringList AlpmDataBase::servers() const
{
return alpm_db_get_servers(m_ptr);
}
/*!
* \brief Sets the servers of the database.
*/
inline bool AlpmDataBase::setServers(StringList servers)
{
return alpm_db_set_servers(m_ptr, servers.begin().ptr()) == 0;
}
/*!
* \brief Returns the package with the specified \a name.
*/
inline alpm_pkg_t *AlpmDataBase::package(const char *name) const
{
return alpm_db_get_pkg(m_ptr, name);
}
/*!
* \brief Returns the groups.
*/
inline alpm_group_t *AlpmDataBase::group(const char *name) const
{
return alpm_db_get_group(m_ptr, name);
}
/*!
* \brief Returns the groups.
*/
inline GroupList AlpmDataBase::groups() const
{
return alpm_db_get_groupcache(m_ptr);
}
/*!
* \brief Performs a search using the build in ALPM function.
*/
inline PackageList AlpmDataBase::search(StringList terms) const
{
return alpm_db_search(m_ptr, terms.begin().ptr());
}
/*!
* \brief Returns a list of databases which are used (by default) to upgrade this database.
*/
inline const QStringList &AlpmDataBase::upgradeSources() const
{
return m_upgradeSources;
}
/*!
* \brief Returns a list of databases which are used (by default) to upgrade this database.
*/
inline QStringList &AlpmDataBase::upgradeSources()
{
return m_upgradeSources;
}
/*!
* \brief Returns whether the database instance is valid or null.
*/
inline PackageManagement::AlpmDataBase::operator bool() const
{
return m_ptr != nullptr;
}
template<class SyncPackageType>
void AlpmDataBase::checkForUpgrades(const std::map<QString, SyncPackageType> &syncDbPkgs, UpdateLookupResults<SyncPackageType> &results) const
{
for(const auto &dbPkg : packages()) {
try {
const auto &syncPkg = syncDbPkgs.at(dbPkg.first);
switch(dbPkg.second.compareVersion(syncPkg)) {
case PackageVersionComparsion::Equal:
break; // ignore equal packages
case PackageVersionComparsion::SoftwareUpgrade:
results.newVersions << makeUpdateResult(syncPkg, dbPkg.second.version());
break;
case PackageVersionComparsion::PackageUpgradeOnly:
results.newReleases << makeUpdateResult(syncPkg, dbPkg.second.version());
break;
case PackageVersionComparsion::NewerThenSyncVersion:
results.downgrades << makeUpdateResult(syncPkg, dbPkg.second.version());
}
} catch(std::out_of_range &) {
results.orphaned << dbPkg.second;
}
}
}
} // namespace Alpm
#endif // ALPM_DATABASE_H

View File

@ -6,15 +6,16 @@
namespace PackageManagement {
/*!
* \brief Returns the package names of the group as QJsonArray.
* \class AlpmGroup
* \brief The AlpmGroup class wraps an ALPM group struct.
*/
QJsonArray AlpmGroup::packageNames() const
GroupInfo::GroupInfo(const AlpmGroup &group)
{
QJsonArray pkgNames;
for(AlpmPackage pkg : packages()) {
pkgNames << QString::fromLocal8Bit(pkg.name());
name = QString::fromLocal8Bit(group.name());
for(auto *pkg : PackageList(group.packages())) {
packages << QString::fromLocal8Bit(alpm_pkg_get_name(pkg));
}
return pkgNames;
}
} // namespace Alpm

View File

@ -2,14 +2,13 @@
#define ALPM_GROUP_H
#include "list.h"
#include "package.h"
#include <alpm.h>
#include <QtGlobal>
#include <QStringList>
QT_BEGIN_NAMESPACE
class QJsonArray;
QT_END_NAMESPACE
QT_FORWARD_DECLARE_CLASS(QJsonArray)
namespace PackageManagement {
@ -21,11 +20,9 @@ public:
// group properties
const char *name() const;
PackageList packages() const;
QJsonArray packageNames() const;
private:
const alpm_group_t *m_ptr;
};
/*!
@ -51,6 +48,20 @@ inline PackageList AlpmGroup::packages() const
return m_ptr->packages;
}
} // namespace Alpm
class GroupInfo
{
public:
GroupInfo(const QString &name, const QStringList &packages = QStringList());
GroupInfo(const AlpmGroup &group);
QString name;
QStringList packages;
};
inline GroupInfo::GroupInfo(const QString &name, const QStringList &packages) :
name(name),
packages(packages)
{}
}
#endif // ALPM_GROUP_H

View File

@ -111,6 +111,7 @@ typedef AlpmList<const char *> StringList;
typedef AlpmList<alpm_depend_t *> DependencyList;
typedef AlpmList<alpm_pkg_t *> PackageList;
typedef AlpmList<alpm_group_t *> GroupList;
typedef AlpmList<alpm_backup_t *> BackupList;
} // namespace Alpm

View File

@ -1,11 +1,14 @@
#include "manager.h"
#include "database.h"
#include "alpmdatabase.h"
#include "utilities.h"
#include "list.h"
#include "config.h"
#include "network/userrepository.h"
#include <c++utilities/io/inifile.h>
#include <c++utilities/conversion/stringconversion.h>
#include <c++utilities/misc/memory.h>
#include <QList>
#include <QSysInfo>
@ -22,9 +25,23 @@ using namespace ConversionUtilities;
namespace PackageManagement {
/*!
* \cond
*/
constexpr int defaultSigLevel = ALPM_SIG_PACKAGE | ALPM_SIG_PACKAGE_OPTIONAL |
ALPM_SIG_DATABASE | ALPM_SIG_DATABASE_OPTIONAL;
inline ostream &operator <<(ostream &stream, const QString &str)
{
stream << str.toLocal8Bit().data();
return stream;
}
/*!
* \endcond
*/
/*!
* \brief The Manager class helps accessing ALPM.
*
@ -40,12 +57,15 @@ constexpr int defaultSigLevel = ALPM_SIG_PACKAGE | ALPM_SIG_PACKAGE_OPTIONAL |
Manager::Manager(const Config &config) :
m_config(config),
m_sigLevel(defaultSigLevel),
m_localFileSigLevel(ALPM_SIG_USE_DEFAULT),
m_aur(m_networkAccessManager)
m_localFileSigLevel(ALPM_SIG_USE_DEFAULT)
{
alpm_errno_t err;
if(!(m_handle = alpm_initialize(config.alpmRootDir().toLocal8Bit().data(), config.alpmDbPath().toLocal8Bit().data(), &err))) {
throw runtime_error(string("Cannot initialize alpm: ") + alpm_strerror(err));
throw runtime_error(string("Cannot initialize ALPM: ") + alpm_strerror(err));
}
m_localDb = make_unique<AlpmDataBase>(alpm_get_localdb(m_handle), config.alpmDbPath());
if(config.isAurEnabled()) {
m_userRepo = make_unique<UserRepository>(m_networkAccessManager);
}
}
@ -60,41 +80,75 @@ Manager::~Manager()
/*!
* \brief Returns the package with the specified name from the specified database.
*/
AlpmPackage Manager::packageFromSyncDataBase(const QString &dbName, const QString &pkgName) const
AlpmPackage *Manager::packageFromDataBase(const QString &dbName, const QString &pkgName)
{
try {
if(dbName == QLatin1String("local")) {
return localDataBase().packages().at(pkgName);
} else {
return syncDataBases().at(dbName).packages().at(pkgName);
}
} catch(out_of_range &) {
return AlpmPackage();
if(auto *db = dataBaseByName(dbName)) {
return static_cast<AlpmPackage *>(db->packageByName(pkgName));
} else {
return nullptr;
}
}
/*!
* \brief Returns the package with the specified name from the specified database.
*/
const AlpmPackage *Manager::packageFromDataBase(const QString &dbName, const QString &pkgName) const
{
if(const auto *db = dataBaseByName(dbName)) {
return static_cast<const AlpmPackage *>(db->packageByName(pkgName));
} else {
return nullptr;
}
}
/*!
* \brief Gets the package with the specified \a name from one of the sync databases.
*/
AlpmPackage *Manager::packageFromSyncDataBases(const QString &pkgName)
{
for(const auto &dbEntry : syncDataBases()) {
if(auto *pkg = dbEntry.second->packageByName(pkgName)) {
return static_cast<AlpmPackage *>(pkg);
}
}
return nullptr;
}
/*!
* \brief Gets the package with the specified \a name from one of the sync databases.
*/
const AlpmPackage *Manager::packageFromSyncDataBases(const QString &pkgName) const
{
for(const auto &dbEntry : syncDataBases()) {
if(const auto *pkg = dbEntry.second->packageByName(pkgName)) {
return static_cast<const AlpmPackage *>(pkg);
}
}
return nullptr;
}
/*!
* \brief Creates a new package instance for the specified package file.
*
* Verifies the integrity of the file if the option is set.
*/
AlpmOwnershipPackage Manager::packageFromFile(const char *fileName, bool verifyIntegrity)
unique_ptr<AlpmOwnershipPackage> Manager::packageFromFile(const char *fileName, bool verifyIntegrity)
{
alpm_pkg_t *pkg;
if(alpm_pkg_load(m_handle, fileName, verifyIntegrity, static_cast<alpm_siglevel_t>(m_localFileSigLevel), &pkg) != 0) {
throw runtime_error(string("Unable to load package file: ") + alpm_strerror(alpm_errno(m_handle)));
} else {
return AlpmOwnershipPackage(pkg);
return make_unique<AlpmOwnershipPackage>(pkg);
}
}
/*!
* \brief Sets the install reason for the specified \a package.
*/
void Manager::setInstallReason(AlpmPackage package, alpm_pkgreason_t reason)
void Manager::setInstallReason(AlpmPackage *package, alpm_pkgreason_t reason)
{
if(alpm_pkg_set_reason(package.ptr(), reason)) {
throw runtime_error(string("Unable to set install reason of the package ") + package.name() + ": " + alpm_strerror(alpm_errno(m_handle)));
if(alpm_pkg_set_reason(package->ptr(), reason)) {
throw runtime_error(string("Unable to set install reason of the package ") + package->name().toLocal8Bit().data() + ": " + alpm_strerror(alpm_errno(m_handle)));
}
}
@ -302,12 +356,12 @@ void Manager::applyPacmanConfig()
cerr << "Warning: Included file \"" << path << "\" has no values." << endl;
}
}
auto emplaced = m_syncDbs.emplace(dbName, make_unique<AlpmDataBase>(db, m_config.alpmDbPath()));
// add sync db to internal map
if(usage & ALPM_DB_USAGE_UPGRADE) {
// -> db is used to upgrade local database
localDataBase().upgradeSources() << dbName;
localDataBase()->upgradeSources() << emplaced.first->second.get();
}
m_syncDbs.emplace(dbName, AlpmDataBase(db, QStringLiteral("%1/sync/%2").arg(m_config.alpmDbPath(), dbName)));
} else {
cerr << "Error: Unable to add sync database [" << scope.first << "]" << endl;
}
@ -324,18 +378,19 @@ void Manager::applyPacmanConfig()
*/
void Manager::applyRepoIndexConfig()
{
// check whether an entry already exists, if not create a new one
for(const RepoEntry &repoEntry : m_config.repoEntries()) {
AlpmDataBase *syncDb;
AlpmDataBase *syncDb = nullptr;
try {
syncDb = &m_syncDbs.at(repoEntry.name());
syncDb = m_syncDbs.at(repoEntry.name()).get();
cerr << "Applying config for database [" << syncDb->name() << "]" << endl;
if(!repoEntry.dataBasePath().isEmpty()) {
cerr << "Warning: Can't use data base path specified in repo index config because the repo \""
<< repoEntry.name().toLocal8Bit().data() << "\" has already been added from the Pacman config." << endl;
<< repoEntry.name() << "\" has already been added from the Pacman config." << endl;
}
if(repoEntry.sigLevel()) {
cerr << "Warning: Can't use sig level path specified in repo index config because the repo \""
<< repoEntry.name().toLocal8Bit().data() << "\" has already been added from the Pacman config." << endl;
cerr << "Warning: Can't use sig level specified in repo index config because the repo \""
<< repoEntry.name() << "\" has already been added from the Pacman config." << endl;
}
syncDb->setPackagesDirectory(repoEntry.packageDir());
syncDb->setSourcesDirectory(repoEntry.sourceDir());
@ -345,21 +400,39 @@ void Manager::applyRepoIndexConfig()
} else if(repoEntry.name().startsWith(QLatin1String("aur"), Qt::CaseInsensitive)) {
cerr << "Error: Unable to add database from repo index config: The database name mustn't start with \"aur\" because this name is reserved for the Arch Linux User Repository." << endl;
} else {
// TODO: database path
auto *db = alpm_register_syncdb(m_handle, repoEntry.name().toLocal8Bit().data(), static_cast<alpm_siglevel_t>(repoEntry.sigLevel()));
auto emplaced = m_syncDbs.emplace(repoEntry.name(), AlpmDataBase(db, repoEntry.dataBasePath(), repoEntry.sourceDir(), repoEntry.packageDir()));
auto emplaced = m_syncDbs.emplace(repoEntry.name(), make_unique<AlpmDataBase>(db, m_config.alpmDbPath()));
if(emplaced.second) {
syncDb = &emplaced.first->second;
syncDb = emplaced.first->second.get();
syncDb->setSourcesDirectory(repoEntry.sourceDir());
syncDb->setPackagesDirectory(repoEntry.packageDir());
if(m_config.isVerbose() || m_config.runServer()) {
cerr << "Added database [" << repoEntry.name().toLocal8Bit().data() << "]" << endl;
cerr << "Added database [" << repoEntry.name() << "]" << endl;
}
}
}
}
if(syncDb) {
syncDb->addServerUrls(repoEntry.servers());
syncDb->upgradeSources() << repoEntry.upgradeSources();
}
}
// add upgrade sources
for(const RepoEntry &repoEntry : m_config.repoEntries()) {
try {
auto &upgradeSources = m_syncDbs.at(repoEntry.name())->upgradeSources();
for(const auto &upgradeSourceName : repoEntry.upgradeSources()) {
if(auto *source = repositoryByName(upgradeSourceName)) {
upgradeSources << source;
} else {
cerr << "Warning: The specified upgrade source \"" << upgradeSourceName << "\" can not be found and will be ignored." << endl;
}
}
} catch(const out_of_range &) {
// entry should have been added before
}
}
}
/*!
@ -372,56 +445,15 @@ void Manager::unregisterSyncDataBases()
}
}
/*!
* \brief Returns the local data base.
*/
const AlpmDataBase &Manager::localDataBase() const
{
if(!m_localDb) {
QMutexLocker locker(&m_localDbMutex);
if(!m_localDb) {
m_localDb = alpm_get_localdb(m_handle);
}
}
return m_localDb;
}
/*!
* \brief Returns the local data base.
*/
AlpmDataBase &Manager::localDataBase()
{
if(!m_localDb) {
m_localDb = alpm_get_localdb(m_handle);
}
return m_localDb;
}
/*!
* \brief Returns a list of all sync databases.
* \remarks Sync databases must be registered with parsePacmanConfig() before.
*/
const std::map<QString, AlpmDataBase> &Manager::syncDataBases() const
const map<QString, unique_ptr<AlpmDataBase> > &Manager::syncDataBases() const
{
return m_syncDbs; // m_syncDbs has been filled when the databases were registered
}
/*!
* \brief Returns basic information about the specified repository.
*/
QJsonObject Manager::basicRepoInfo(AlpmDataBase db, const QString &name, const QString &desc) const
{
QJsonObject repoInfo;
repoInfo.insert(QStringLiteral("name"), name);
repoInfo.insert(QStringLiteral("desc"), desc);
repoInfo.insert(QStringLiteral("servers"), db.serverUrls());
repoInfo.insert(QStringLiteral("usage"), Utilities::usageStrings(db.usage()));
repoInfo.insert(QStringLiteral("sigLevel"), Utilities::sigLevelStrings(db.sigLevel()));
repoInfo.insert(QStringLiteral("upgradeSources"), QJsonArray::fromStringList(db.upgradeSources()));
repoInfo.insert(QStringLiteral("packages"), db.packageNameJsonArray());
return repoInfo;
}
/*!
* \brief Returns basic information about all repositories known to the manager.
*
@ -433,17 +465,22 @@ const QJsonArray &Manager::basicRepoInfo() const
if(m_basicRepoInfo.isEmpty()) {
QMutexLocker locker(&m_basicRepoInfoMutex);
if(m_basicRepoInfo.isEmpty()) {
m_basicRepoInfo << basicRepoInfo(localDataBase(), QStringLiteral("local"), QStringLiteral("The local database."));
auto const &syncDbs = syncDataBases();
for(const auto &syncDb : syncDbs) {
// add local data base
m_basicRepoInfo << localDataBase()->basicInfo();
// add sync data bases
for(const auto &syncDb : syncDataBases()) {
// check if the "sync" database is actually used for syncing
auto usage = syncDb.second.usage();
auto usage = syncDb.second->usage();
if((usage & ALPM_DB_USAGE_SYNC) || (usage & ALPM_DB_USAGE_INSTALL) || (usage & ALPM_DB_USAGE_UPGRADE)) {
m_basicRepoInfo << basicRepoInfo(syncDb.second, syncDb.first, QStringLiteral("The sync database »%1«.").arg(syncDb.first));
m_basicRepoInfo << syncDb.second->basicInfo();
} else {
m_basicRepoInfo << basicRepoInfo(syncDb.second, syncDb.first, QStringLiteral("The database »%1«.").arg(syncDb.first));
m_basicRepoInfo << syncDb.second->basicInfo();
}
}
// add AUR
if(config().isAurEnabled()) {
m_basicRepoInfo << userRepository()->basicInfo();
}
}
}
return m_basicRepoInfo;
@ -452,26 +489,38 @@ const QJsonArray &Manager::basicRepoInfo() const
/*!
* \brief Returns package information for the specified selection of packages.
*/
const QJsonArray Manager::packageInfo(const QJsonArray &pkgSelection, bool full) const
const QJsonArray Manager::packageInfo(const QJsonObject &pkgSelection, bool full) const
{
QJsonArray pkgInfos;
for(const auto &pkgSelJsonVal : pkgSelection) {
QJsonObject pkgSel = pkgSelJsonVal.toObject();
if(!pkgSel.isEmpty()) {
QString repoName = pkgSel.value(QStringLiteral("repo")).toString();
QString pkgName = pkgSel.value(QStringLiteral("name")).toString();
AlpmPackage pkg;
QJsonObject pkgInfo;
if(!repoName.isEmpty() && !pkgName.isEmpty() && (pkg = packageFromSyncDataBase(repoName, pkgName))) {
pkgInfo = full ? pkg.fullInfo() : pkg.basicInfo();
} else {
pkgInfo.insert(QStringLiteral("error"), QStringLiteral("na"));
for(auto i = pkgSelection.constBegin(), end = pkgSelection.constEnd(); i != end; ++i) {
if(auto *repo = repositoryByName(i.key())) {
for(const auto &entry : i.value().toArray()) {
const auto entryObj = entry.toObject();
const auto pkgName = entryObj.value(QStringLiteral("name")).toString();
if(!pkgName.isEmpty()) {
QJsonObject pkgInfo;
if(auto *pkg = repo->packageByName(pkgName)) {
pkgInfo = full ? pkg->fullInfo() : pkg->basicInfo();
} else {
pkgInfo.insert(QStringLiteral("error"), QStringLiteral("na"));
}
pkgInfo.insert(QStringLiteral("name"), pkgName);
pkgInfo.insert(QStringLiteral("repo"), repo->name());
const auto index = entryObj.value(QStringLiteral("index"));
if(!index.isNull() && !index.isUndefined()) {
pkgInfo.insert(QStringLiteral("index"), index);
}
pkgInfos << pkgInfo;
}
}
pkgInfo.insert(QStringLiteral("name"), pkgName);
pkgInfo.insert(QStringLiteral("repo"), repoName);
pkgInfo.insert(QStringLiteral("index"), pkgSel.value(QStringLiteral("index")));
pkgInfos << pkgInfo;
} else {
// specified repository can not be found
QJsonObject errorObj;
errorObj.insert(QStringLiteral("repo"), i.key());
errorObj.insert(QStringLiteral("error"), QStringLiteral("na"));
pkgInfos << errorObj;
}
}
return pkgInfos;
}
@ -484,9 +533,9 @@ const QJsonArray &Manager::groupInfo() const
if(m_groupInfo.empty()) {
QMutexLocker locker(&m_groupInfoMutex);
if(m_groupInfo.empty()) {
m_groupInfo << localDataBase().groupInfo();
m_groupInfo << localDataBase()->groupInfo();
for(const auto &db : m_syncDbs) {
m_groupInfo << db.second.groupInfo();
m_groupInfo << db.second->groupInfo();
}
}
}
@ -495,41 +544,70 @@ const QJsonArray &Manager::groupInfo() const
/*!
* \brief Returns the ALPM database with the specified name.
* \throws Throws std::out_of_range if the specified database is unknown to the manager.
*/
const AlpmDataBase &Manager::dataBaseByName(const QString &dbName) const
const AlpmDataBase *Manager::dataBaseByName(const QString &dbName) const
{
if(dbName == QLatin1String("local")) {
if(dbName.compare(QLatin1String("local"), Qt::CaseInsensitive) == 0) {
return localDataBase();
} else {
return m_syncDbs.at(dbName);
try {
return m_syncDbs.at(dbName).get();
} catch(const out_of_range &) {
return nullptr;
}
}
}
/*!
* \brief Returns the ALPM database with the specified name.
* \throws Throws std::out_of_range if the specified database is unknown to the manager.
*/
AlpmDataBase &Manager::dataBaseByName(const QString &dbName)
AlpmDataBase *Manager::dataBaseByName(const QString &dbName)
{
if(dbName == QLatin1String("local")) {
if(dbName.compare(QLatin1String("local"), Qt::CaseInsensitive) == 0) {
return localDataBase();
} else {
return m_syncDbs.at(dbName);
try {
return m_syncDbs.at(dbName).get();
} catch(const out_of_range &) {
return nullptr;
}
}
}
/*!
* \brief Checks for upgrades availabel to the specified database.
*
* The \a request must have the following values:
* - db: Specifies the name of the database to check for upgrades.
* - syncdbs: Array with the names of the databases used as upgrade sources.
* If not present, appropriate upgrade sources will be determined automatically.
* \brief Returns the package source with the specified name.
*/
void Manager::invokeUpgradeLookup(const QJsonObject &request, UpdateLookupCallback callback) const
const Repository *Manager::repositoryByName(const QString &name) const
{
new UpdateLookup(*this, request, callback); // this object will delete itself
if(name.compare(QLatin1String("local"), Qt::CaseInsensitive) == 0) {
return localDataBase();
} else if(config().isAurEnabled() && (name.compare(QLatin1String("aur"), Qt::CaseInsensitive) == 0)) {
return userRepository();
} else {
try {
return m_syncDbs.at(name).get();
} catch(const out_of_range &) {
return nullptr;
}
}
}
/*!
* \brief Returns the package source with the specified name.
*/
Repository *Manager::repositoryByName(const QString &name)
{
if(name.compare(QLatin1String("local"), Qt::CaseInsensitive) == 0) {
return localDataBase();
} else if(config().isAurEnabled() && (name.compare(QLatin1String("aur"), Qt::CaseInsensitive) == 0)) {
return userRepository();
} else {
try {
return m_syncDbs.at(name).get();
} catch(const out_of_range &) {
return nullptr;
}
}
}
/*!
@ -537,18 +615,10 @@ void Manager::invokeUpgradeLookup(const QJsonObject &request, UpdateLookupCallba
*
* Appropriate upgrade sources will be determined automatically; does not check the AUR.
*/
const UpdateLookupResults<AlpmPackage> Manager::checkForUpgrades(const AlpmDataBase &db) const
const UpgradeLookupResults Manager::checkForUpgrades(AlpmDataBase *db) const
{
UpdateLookupResults<AlpmPackage> results;
QList<const AlpmDataBase *> syncDbSel;
for(const auto &syncDbName : db.upgradeSources()) {
try {
syncDbSel << &(syncDataBases().at(syncDbName));
} catch(out_of_range &) {
;
}
}
db.checkForUpgrades(syncDbSel, results);
UpgradeLookupResults results;
db->checkForUpgrades(results);
return results;
}

View File

@ -1,10 +1,8 @@
#ifndef ALPM_MANAGER_H
#define ALPM_MANAGER_H
#include "database.h"
#include "updatelookup.h"
#include "network/aurquery.h"
#include "upgradelookup.h"
#include "alpmpackage.h"
#include <alpm.h>
@ -14,11 +12,13 @@
#include <QMutex>
#include <map>
#include <memory>
namespace PackageManagement {
class Config;
template<class Package> class UpdateLookupResults;
class UserRepository;
class AlpmDataBase;
class Manager
{
@ -42,30 +42,33 @@ public:
void applyRepoIndexConfig();
void unregisterSyncDataBases();
const AurQuery &aurQuery() const;
AurQuery &aurQuery();
const UserRepository *userRepository() const;
UserRepository *userRepository();
// package lookup
AlpmPackage packageFromSyncDataBase(const QString &dbName, const QString &pkgName) const;
AlpmPackage packageFromSyncDataBases(const char *name) const;
AlpmOwnershipPackage packageFromFile(const char *fileName, bool verifyIntegrity = false);
bool isPackageIgnored(AlpmPackage package) const;
void setInstallReason(AlpmPackage package, alpm_pkgreason_t reason);
AlpmPackage *packageFromDataBase(const QString &dbName, const QString &pkgName);
const AlpmPackage *packageFromDataBase(const QString &dbName, const QString &pkgName) const;
AlpmPackage *packageFromSyncDataBases(const QString &pkgName);
const AlpmPackage *packageFromSyncDataBases(const QString &pkgName) const;
std::unique_ptr<AlpmOwnershipPackage> packageFromFile(const char *fileName, bool verifyIntegrity = false);
bool isPackageIgnored(const AlpmPackage *package) const;
void setInstallReason(AlpmPackage *package, alpm_pkgreason_t reason);
// database lookup
const AlpmDataBase &localDataBase() const;
AlpmDataBase &localDataBase();
const std::map<QString, AlpmDataBase> &syncDataBases() const;
const AlpmDataBase &dataBaseByName(const QString &dbName) const;
AlpmDataBase &dataBaseByName(const QString &dbName);
const UpdateLookupResults<AlpmPackage> checkForUpgrades(const AlpmDataBase &db) const;
// data base lookup
const AlpmDataBase *localDataBase() const;
AlpmDataBase *localDataBase();
const std::map<QString, std::unique_ptr<AlpmDataBase> > &syncDataBases() const;
const AlpmDataBase *dataBaseByName(const QString &dbName) const;
AlpmDataBase *dataBaseByName(const QString &dbName);
const Repository *repositoryByName(const QString &name) const;
Repository *repositoryByName(const QString &name);
const UpgradeLookupResults checkForUpgrades(AlpmDataBase *db) const;
// JSON serialization, handling JSON requests
QJsonObject basicRepoInfo(AlpmDataBase db, const QString &name, const QString &desc = QString()) const;
const QJsonObject basicRepoInfo(const Repository *packageSource) const;
const QJsonArray &basicRepoInfo() const;
const QJsonArray packageInfo(const QJsonArray &pkgSelection, bool full = true) const;
const QJsonArray packageInfo(const QJsonObject &pkgSelection, bool full = true) const;
const QJsonArray &groupInfo() const;
void invokeUpgradeLookup(const QJsonObject &request, UpdateLookupCallback callback) const;
private:
void cleanup();
@ -76,10 +79,9 @@ private:
int m_localFileSigLevel;
QString m_pacmanCacheDir;
QNetworkAccessManager m_networkAccessManager;
AurQuery m_aur;
mutable AlpmDataBase m_localDb;
mutable QMutex m_localDbMutex;
mutable std::map<QString, AlpmDataBase> m_syncDbs;
std::unique_ptr<UserRepository> m_userRepo;
std::unique_ptr<AlpmDataBase> m_localDb;
std::map<QString, std::unique_ptr<AlpmDataBase> > m_syncDbs;
mutable QJsonArray m_basicRepoInfo;
mutable QMutex m_basicRepoInfoMutex;
mutable QJsonArray m_groupInfo;
@ -135,20 +137,12 @@ inline void Manager::setLocalFileSigLevel(int sigLevel)
m_localFileSigLevel = sigLevel;
}
/*!
* \brief Gets the package with the specified \a name from one of the sync databases.
*/
inline AlpmPackage Manager::packageFromSyncDataBases(const char *name) const
{
return alpm_find_dbs_satisfier(m_handle, alpm_get_syncdbs(m_handle), name);
}
/*!
* \brief Returns whether the specified \a package is ignored.
*/
inline bool Manager::isPackageIgnored(AlpmPackage package) const
inline bool Manager::isPackageIgnored(const AlpmPackage *package) const
{
return alpm_pkg_should_ignore(m_handle, package.ptr());
return alpm_pkg_should_ignore(m_handle, const_cast<alpm_pkg_t *>(package->ptr()));
}
/*!
@ -160,14 +154,30 @@ inline const QString &Manager::pacmanCacheDir() const
return m_pacmanCacheDir;
}
inline const AurQuery &Manager::aurQuery() const
inline const UserRepository *Manager::userRepository() const
{
return m_aur;
return m_userRepo.get();
}
inline AurQuery &Manager::aurQuery()
inline UserRepository *Manager::userRepository()
{
return m_aur;
return m_userRepo.get();
}
/*!
* \brief Returns the local data base.
*/
inline const AlpmDataBase *Manager::localDataBase() const
{
return m_localDb.get();
}
/*!
* \brief Returns the local data base.
*/
inline AlpmDataBase *Manager::localDataBase()
{
return m_localDb.get();
}
}

View File

@ -1,13 +1,19 @@
#include "mingwbundle.h"
#include "utilities.h"
#include "manager.h"
#include <c++utilities/conversion/stringconversion.h>
#include <c++utilities/misc/memory.h>
#include <KTar>
#include <K7Zip>
#include <KZip>
#include <QFile>
#include <QtConcurrent/QtConcurrent>
#include <QStringBuilder>
#include <QJsonDocument>
#include <QJsonArray>
#include <QFile>
#include <string>
#include <iostream>
@ -16,18 +22,25 @@ using namespace std;
namespace PackageManagement {
using namespace Utilities;
const string prefix("mingw-w64-");
MingwBundle::MingwBundle(const Manager &manager, const ApplicationUtilities::StringVector &packages) :
MingwBundle::MingwBundle(const Manager &manager, const ApplicationUtilities::StringVector &packages, const ApplicationUtilities::StringVector &iconPackages) :
m_manager(manager)
{
cerr << "Resolving dependencies ..." << endl;
string missing;
// add mingw-w64 packages
for(const auto &pkgName : packages) {
bool found = false;
for(const auto &syncDb : manager.syncDataBases()) {
if(auto pkg = syncDb.second.package(ConversionUtilities::startsWith(pkgName, prefix) ? pkgName.data() : (prefix + pkgName).data())) {
if(auto *pkg = syncDb.second->packageByName(QString::fromLocal8Bit(ConversionUtilities::startsWith(pkgName, prefix) ? pkgName.data() : (prefix + pkgName).data()))) {
if(missing.empty()) {
m_packages.emplace_back(syncDb.second, pkg);
decltype(m_packages)::value_type entry(syncDb.second.get(), pkg);
if(find(m_packages.cbegin(), m_packages.cend(), entry) == m_packages.cend()) {
m_packages.emplace_back(entry);
}
}
addDependencies(pkg);
found = true;
@ -39,50 +52,125 @@ MingwBundle::MingwBundle(const Manager &manager, const ApplicationUtilities::Str
missing.append(pkgName);
}
}
// add additional icon packages
for(const auto &pkgName : iconPackages) {
bool found = false;
for(const auto &syncDb : manager.syncDataBases()) {
if(auto *pkg = syncDb.second->packageByName(QString::fromLocal8Bit(pkgName.data()))) {
if(missing.empty()) {
decltype(m_packages)::value_type entry(syncDb.second.get(), pkg);
if(find(m_packages.cbegin(), m_packages.cend(), entry) == m_packages.cend()) {
m_packages.emplace_back(entry);
}
}
found = true;
break;
}
}
if(!found) {
missing.push_back(' ');
missing.append(pkgName);
}
}
if(!missing.empty()) {
throw runtime_error("The following packages can not be found:" + missing);
} else {
cerr << "Adding the following packages:";
for(const auto &pkg : m_packages) {
cerr << ' ' << pkg.second.name();
cerr << ' ' << pkg.second->name().toLocal8Bit().data();
}
cerr << endl;
}
}
void MingwBundle::addDependencies(const Package *pkg)
{
string missing;
for(const auto &dep : pkg->dependencies()) {
if(dep.name.startsWith(QLatin1String("mingw-w64-"), Qt::CaseInsensitive)) {
bool found = false;
for(const auto &syncDbEntry : m_manager.syncDataBases()) {
if(const auto *pkg = syncDbEntry.second->packageProviding(dep)) {
if(missing.empty()) {
decltype(m_packages)::value_type entry(syncDbEntry.second.get(), pkg);
if(find(m_packages.cbegin(), m_packages.cend(), entry) == m_packages.cend()) {
m_packages.emplace_back(entry);
}
}
addDependencies(pkg);
found = true;
break;
}
}
if(!found) {
missing.push_back(' ');
missing.append(dep.name.toLocal8Bit().data());
}
}
}
if(!missing.empty()) {
throw runtime_error("The following dependencies of the " + string(pkg->name().toLocal8Bit().data()) + " package can not be resolved:" + missing);
}
}
enum class RelevantFileType
{
Binary,
Translation
Translation,
QtTranslation,
QtPlugin,
Icon
};
enum class RelevantFileArch
{
x86_64,
i686
i686,
Any
};
struct RelevantFile
{
RelevantFile(const KArchiveFile *file, const RelevantFileType type, const RelevantFileArch arch) :
RelevantFile(const KArchiveFile *file, const RelevantFileType type, const RelevantFileArch arch, const QString &subDir = QString()) :
file(file),
fileType(type),
arch(arch)
arch(arch),
subDir(subDir)
{}
const KArchiveFile *file;
RelevantFileType fileType;
RelevantFileArch arch;
QString subDir;
};
struct PkgFileInfo
{
PkgFileInfo(const QString &path) : path(path), failure(false) {}
PkgFileInfo(const QString &name, const QString &path) :
name(name),
path(path),
failure(false)
{}
QString name;
QString path;
unique_ptr<KTar> archive;
list<RelevantFile> relevantFiles;
bool failure;
};
void addEntries(PkgFileInfo &pkgFileInfo, RelevantFileType fileType, const KArchiveDirectory *dir, const QString &relPath = QString())
{
QString newPath = relPath.isEmpty() ? dir->name() : relPath % QChar('/') % dir->name();
for(const auto &entryName : dir->entries()) {
if(auto *entry = dir->entry(entryName)) {
if(entry->isDirectory()) {
addEntries(pkgFileInfo, fileType, static_cast<const KArchiveDirectory *>(entry), newPath);
} else if(entry->isFile()) {
pkgFileInfo.relevantFiles.emplace_back(static_cast<const KArchiveFile *>(entry), fileType, RelevantFileArch::Any, newPath);
}
}
}
}
void getFiles(PkgFileInfo &pkgFileInfo)
{
pkgFileInfo.archive = make_unique<KTar>(pkgFileInfo.path);
@ -104,65 +192,190 @@ void getFiles(PkgFileInfo &pkgFileInfo)
if(entry->isFile()) {
const auto *binFile = static_cast<const KArchiveFile *>(entry);
pkgFileInfo.relevantFiles.emplace_back(binFile, RelevantFileType::Binary, root.first);
cerr << entryName.toLocal8Bit().data() << endl;
}
}
}
}
}
const auto *libEntry = rootDir->entry(QStringLiteral("lib"));
if(libEntry && libEntry->isDirectory()) {
const auto *libDir = static_cast<const KArchiveDirectory *>(libEntry);
const auto *qtEntry = libDir->entry("qt");
if(qtEntry && qtEntry->isDirectory()) {
const auto *qtDir = static_cast<const KArchiveDirectory *>(qtEntry);
const auto *pluginsEntry = qtDir->entry(QStringLiteral("plugins"));
if(pluginsEntry && pluginsEntry->isDirectory()) {
const auto *pluginsDir = static_cast<const KArchiveDirectory *>(pluginsEntry);
for(const auto &pluginCategory : pluginsDir->entries()) {
const auto *categoryEntry = pluginsDir->entry(pluginCategory);
if(categoryEntry && categoryEntry->isDirectory()) {
const auto *categoryDir = static_cast<const KArchiveDirectory *>(categoryEntry);
for(const auto &entryName : categoryDir->entries()) {
if(const auto *pluginEntry = categoryDir->entry(entryName)) {
if(pluginEntry->isFile()) {
const auto *pluginFile = static_cast<const KArchiveFile *>(pluginEntry);
pkgFileInfo.relevantFiles.emplace_back(pluginFile, RelevantFileType::QtPlugin, root.first, categoryDir->name());
}
}
}
}
}
}
}
}
const auto *shareEntry = rootDir->entry(QStringLiteral("share"));
if(shareEntry && shareEntry->isDirectory()) {
const auto *shareDir = static_cast<const KArchiveDirectory *>(shareEntry);
const auto *qtEntry = shareDir->entry(QStringLiteral("qt"));
if(qtEntry && qtEntry->isDirectory()) {
const auto *qtDir = static_cast<const KArchiveDirectory *>(qtEntry);
const auto *trEntry = qtDir->entry(QStringLiteral("translations"));
if(trEntry && trEntry->isDirectory()) {
const auto trDir = static_cast<const KArchiveDirectory *>(trEntry);
for(const auto &entryName : trDir->entries()) {
if(entryName.endsWith(QLatin1String(".qm"))) {
if(const auto *qmEntry = trDir->entry(entryName)) {
if(qmEntry->isFile()) {
const auto *qmFile = static_cast<const KArchiveFile *>(qmEntry);
pkgFileInfo.relevantFiles.emplace_back(qmFile, RelevantFileType::QtTranslation, root.first);
}
}
}
}
}
}
if(pkgFileInfo.name.compare(QLatin1String("qt"))) {
const auto *appEntry = shareDir->entry(pkgFileInfo.name);
if(appEntry && appEntry->isDirectory()) {
const auto *appDir = static_cast<const KArchiveDirectory *>(appEntry);
const auto *trEntry = appDir->entry(QStringLiteral("translations"));
if(trEntry && trEntry->isDirectory()) {
const auto trDir = static_cast<const KArchiveDirectory *>(trEntry);
for(const auto &entryName : trDir->entries()) {
if(entryName.endsWith(QLatin1String(".qm"))) {
if(const auto *qmEntry = trDir->entry(entryName)) {
if(qmEntry->isFile()) {
const auto *qmFile = static_cast<const KArchiveFile *>(qmEntry);
pkgFileInfo.relevantFiles.emplace_back(qmFile, RelevantFileType::Translation, root.first);
}
}
}
}
}
}
}
}
}
}
const auto *iconsEntry = pkgFileInfo.archive->directory()->entry(QStringLiteral("usr/share/icons"));
if(iconsEntry && iconsEntry->isDirectory()) {
const auto *iconsDir = static_cast<const KArchiveDirectory *>(iconsEntry);
for(const auto &themeName : iconsDir->entries()) {
const auto *themeEntry = iconsDir->entry(themeName);
if(themeEntry && themeEntry->isDirectory()) {
addEntries(pkgFileInfo, RelevantFileType::Icon, static_cast<const KArchiveDirectory *>(themeEntry));
}
}
}
} else {
pkgFileInfo.failure = true;
}
}
void MingwBundle::createBundle(const string &path) const
void MingwBundle::createBundle(const string &targetDir, const string &targetName, const string &targetFormat) const
{
cerr << "Gathering relevant files ..." << endl;
// get package files
list<PkgFileInfo> pkgFiles;
for(const auto &entry : m_packages) {
QString pkgFile;
if(!entry.first.packagesDirectory().isEmpty()) {
pkgFile = QStringLiteral("%1/%2").arg(entry.first.packagesDirectory(), QString::fromLocal8Bit(entry.second.fileName()));
if(!entry.first->packagesDirectory().isEmpty()) {
pkgFile = entry.first->packagesDirectory() % QChar('/') % entry.second->fileName();
}
if(pkgFile.isEmpty() || !QFile::exists(pkgFile)) {
if(!m_manager.pacmanCacheDir().isEmpty()) {
pkgFile = QStringLiteral("%1/%2").arg(m_manager.pacmanCacheDir(), QString::fromLocal8Bit(entry.second.fileName()));
pkgFile = m_manager.pacmanCacheDir() % QChar('/') % entry.second->fileName();
}
if(pkgFile.isEmpty() || !QFile::exists(pkgFile)) {
throw runtime_error("The package file " + string(entry.second.fileName()) + " can't be found.");
throw runtime_error("The package file " + string(entry.second->fileName().toLocal8Bit().data()) + " can't be found.");
// TODO: download package from mirror
}
}
pkgFiles.emplace_back(pkgFile);
pkgFiles.emplace_back(entry.second->name().startsWith(QLatin1String("mingw-w64-")) ? entry.second->name().mid(10) : entry.second->name(), pkgFile);
}
// get relevant files from packages
QtConcurrent::blockingMap(pkgFiles, getFiles);
}
void MingwBundle::addDependencies(const AlpmPackage &pkg)
{
string missing;
for(const auto &depInfo : pkg.dependencies()) {
bool found = false;
for(const auto &syncDb : m_manager.syncDataBases()) {
if(auto pkg = syncDb.second.package(depInfo->name)) {
if(missing.empty()) {
m_packages.emplace_back(syncDb.second, pkg);
}
addDependencies(pkg);
found = true;
break;
}
}
if(!found) {
missing.push_back(' ');
missing.append(depInfo->name);
// check whether all packages could be opened
string failed;
for(const auto &pkgFile : pkgFiles) {
if(pkgFile.failure) {
failed.push_back(' ');
failed.append(pkgFile.path.toLocal8Bit().data());
}
}
if(!missing.empty()) {
throw runtime_error("The following dependencies of the " + string(pkg.name()) + " package can not be resolved:" + missing);
if(!failed.empty()) {
throw runtime_error("Unable to open the following package files:" + failed);
}
// make a list with package info to be included in the target archive
QJsonArray pkgArray;
for(const auto &entry : m_packages) {
pkgArray << entry.second->basicInfo(true);
}
QJsonDocument pkgList;
pkgList.setArray(pkgArray);
QByteArray pkgListBytes = pkgList.toJson();
// make target archive
static const QString user(QStringLiteral("root"));
static const QString &group = user;
static const pair<RelevantFileArch, QString> roots[] = {
make_pair(RelevantFileArch::x86_64, QStringLiteral("x86_64-w64-mingw32")),
make_pair(RelevantFileArch::i686, QStringLiteral("i686-w64-mingw32"))
};
for(const auto &root : roots) {
QString targetPath = qstr(targetDir) % QChar('/') % root.second % QChar('-') % qstr(targetName) % QChar('.') % qstr(targetFormat);
cerr << "Making archive \"" << targetPath.toLocal8Bit().data() << "\" ..." << endl;
unique_ptr<KArchive> targetArchive;
if(targetFormat == "7z") {
targetArchive = make_unique<K7Zip>(targetPath);
} else if(targetFormat == "zip") {
targetArchive = make_unique<KZip>(targetPath);
} else if(ConversionUtilities::startsWith<string>(targetFormat, "tar")) {
targetArchive = make_unique<KTar>(targetPath);
} else {
throw runtime_error("Specified archive format \"" + targetFormat + "\" is unknown.");
}
if(targetArchive->open(QIODevice::WriteOnly)) {
// add package list
targetArchive->writeFile(root.second % QStringLiteral("/var/lib/repoindex/packages.list"), pkgListBytes, 0100644, user, group);
// add relevant files from packages
for(const auto &pkgFile : pkgFiles) {
for(const RelevantFile &relevantFile : pkgFile.relevantFiles) {
if(relevantFile.arch == RelevantFileArch::Any || relevantFile.arch == root.first) {
switch(relevantFile.fileType) {
case RelevantFileType::Binary:
targetArchive->writeFile(root.second % QStringLiteral("/bin/") % relevantFile.file->name(), relevantFile.file->data(), 0100755, user, group);
break;
case RelevantFileType::Translation:
targetArchive->writeFile(root.second % QStringLiteral("/share/") % pkgFile.name % QStringLiteral("/translations/") % relevantFile.file->name(), relevantFile.file->data(), 0100644, user, group);
break;
case RelevantFileType::QtTranslation:
targetArchive->writeFile(root.second % QStringLiteral("/share/qt/translations/") % relevantFile.file->name(), relevantFile.file->data(), 0100644, user, group);
break;
case RelevantFileType::QtPlugin:
targetArchive->writeFile(root.second % QStringLiteral("/bin/") % relevantFile.subDir % QChar('/') % relevantFile.file->name(), relevantFile.file->data(), 0100755, user, group);
break;
case RelevantFileType::Icon:
targetArchive->writeFile(root.second % QStringLiteral("/share/icons/") % relevantFile.subDir % QChar('/') % relevantFile.file->name(), relevantFile.file->data(), 0100644, user, group);
break;
}
}
}
}
} else if(targetArchive->device()) {
throw runtime_error("Unable to open target archive: " + string(targetArchive->device()->errorString().toLocal8Bit().data()));
} else {
throw runtime_error("Unable to open target archive.");
}
}
}

View File

@ -2,7 +2,7 @@
#define PACKAGEMANAGEMENT_MINGWBUNDLE_H
#include "package.h"
#include "database.h"
#include "alpmdatabase.h"
#include <c++utilities/application/argumentparser.h>
@ -15,15 +15,15 @@ class Manager;
class MingwBundle
{
public:
MingwBundle(const Manager &manager, const ApplicationUtilities::StringVector &packages);
MingwBundle(const Manager &manager, const ApplicationUtilities::StringVector &packages, const ApplicationUtilities::StringVector &iconPackages);
void createBundle(const std::string &path) const;
void createBundle(const std::string &targetDir, const std::string &targetName, const std::string &targetFormat) const;
private:
void addDependencies(const AlpmPackage &pkg);
void addDependencies(const Package *pkg);
const Manager &m_manager;
std::list<std::pair<const AlpmDataBase &, AlpmPackage> > m_packages;
std::list<std::pair<const AlpmDataBase *, const Package *> > m_packages;
};
} // namespace PackageManagement

View File

@ -1,5 +1,7 @@
#include "package.h"
#include "database.h"
#include "alpmdatabase.h"
#include "utilities.h"
#include "repository.h"
#include <QJsonObject>
#include <QJsonValue>
@ -11,82 +13,191 @@ using namespace ChronoUtilities;
namespace PackageManagement {
/*!
* \class The Package class holds meta information about an
* Arch Linux package.
*/
/*!
* \brief Constructs a new package instance.
*
* Since it is intenced to use the Package class as base class only,
* this constructor is protected.
*/
Package::Package(const QString &name, Repository *source) :
m_origin(PackageOrigin::Unknown),
m_source(source),
m_hasGeneralInfo(false),
m_name(name),
m_hasInstallScript(false),
m_hasBuildRelatedMetaData(false),
m_hasInstallRelatedMetaData(false),
m_validationMethods(ALPM_PKG_VALIDATION_UNKNOWN),
m_installReason(ALPM_PKG_REASON_EXPLICIT),
m_id(-1),
m_categoryId(-1),
m_votes(-1)
{
// initialization must be done in derived class
}
Package::~Package()
{}
bool Package::matches(const QString &name, const QString &version, const Dependency &dependency)
{
if(name == dependency.name) {
PackageVersionComparsion cmp;
switch(dependency.mode) {
case ALPM_DEP_MOD_ANY:
return true;
case ALPM_DEP_MOD_EQ:
return version == dependency.version;
case ALPM_DEP_MOD_GE:
return (cmp = PackageVersion(version).compare(PackageVersion(dependency.version))) == PackageVersionComparsion::Equal || cmp == PackageVersionComparsion::NewerThenSyncVersion;
case ALPM_DEP_MOD_LE:
return (cmp = PackageVersion(version).compare(PackageVersion(dependency.version))) == PackageVersionComparsion::Equal || cmp == PackageVersionComparsion::PackageUpgradeOnly || cmp == PackageVersionComparsion::SoftwareUpgrade;
case ALPM_DEP_MOD_GT:
return PackageVersion(version).compare(PackageVersion(dependency.version)) == PackageVersionComparsion::NewerThenSyncVersion;
case ALPM_DEP_MOD_LT:
return (cmp = PackageVersion(version).compare(PackageVersion(dependency.version))) == PackageVersionComparsion::PackageUpgradeOnly || cmp == PackageVersionComparsion::SoftwareUpgrade;
default:
;
}
}
return false;
}
/*!
* \cond
*/
inline QString qstr(const char *str)
{
return QString::fromLocal8Bit(str);
}
namespace Utilities {
inline QJsonArray qjarry(StringList list)
inline void put(QJsonObject &obj, const QString &key, const QJsonValue &value)
{
QJsonArray jsonArray;
for(const char *str : list) {
jsonArray << qstr(str);
if(!value.isNull()) {
obj.insert(key, value);
}
return jsonArray;
}
inline QJsonArray qjarry(DependencyList list)
inline void put(QJsonObject &obj, const QString &key, const DateTime dateTime)
{
QJsonArray jsonArray;
for(alpm_depend_t *dep : list) {
QJsonObject depObj;
depObj.insert(QStringLiteral("name"), dep->name);
depObj.insert(QStringLiteral("desc"), dep->desc);
depObj.insert(QStringLiteral("ver"), dep->version);
switch(dep->mod) {
case ALPM_DEP_MOD_ANY:
depObj.insert(QStringLiteral("mod"), QStringLiteral("any"));
break;
case ALPM_DEP_MOD_EQ:
depObj.insert(QStringLiteral("mod"), QStringLiteral("eq"));
break;
case ALPM_DEP_MOD_GE:
depObj.insert(QStringLiteral("mod"), QStringLiteral("ge"));
break;
case ALPM_DEP_MOD_LE:
depObj.insert(QStringLiteral("mod"), QStringLiteral("le"));
break;
case ALPM_DEP_MOD_GT:
depObj.insert(QStringLiteral("mod"), QStringLiteral("gt"));
break;
case ALPM_DEP_MOD_LT:
depObj.insert(QStringLiteral("mod"), QStringLiteral("lt"));
break;
if(!dateTime.isNull()) {
put(obj, key, QString::fromLocal8Bit(dateTime.toString().data()));
}
}
inline void put(QJsonObject &obj, const QString &key, const QStringList &values)
{
if(!values.isEmpty()) {
put(obj, key, QJsonArray::fromStringList(values));
}
}
void put(QJsonObject &obj, const QString &key, const QList<Dependency> &dependencies)
{
if(!dependencies.isEmpty()) {
QJsonArray jsonArray;
for(const auto &dep : dependencies) {
QJsonObject depObj;
depObj.insert(QStringLiteral("name"), dep.name);
depObj.insert(QStringLiteral("ver"), dep.version);
switch(dep.mode) {
case ALPM_DEP_MOD_ANY:
depObj.insert(QStringLiteral("mod"), QStringLiteral("any"));
break;
case ALPM_DEP_MOD_EQ:
depObj.insert(QStringLiteral("mod"), QStringLiteral("eq"));
break;
case ALPM_DEP_MOD_GE:
depObj.insert(QStringLiteral("mod"), QStringLiteral("ge"));
break;
case ALPM_DEP_MOD_LE:
depObj.insert(QStringLiteral("mod"), QStringLiteral("le"));
break;
case ALPM_DEP_MOD_GT:
depObj.insert(QStringLiteral("mod"), QStringLiteral("gt"));
break;
case ALPM_DEP_MOD_LT:
depObj.insert(QStringLiteral("mod"), QStringLiteral("lt"));
break;
}
jsonArray << depObj;
}
jsonArray << depObj;
put(obj, key, jsonArray);
}
return jsonArray;
}
inline QJsonArray qjarry(_alpm_pkgvalidation_t validation)
{
QJsonArray jsonArray;
if(validation & 0x1) {
jsonArray << QStringLiteral("none");
}
if(validation & 0x2) {
jsonArray << QStringLiteral("MD5");
}
if(validation & 0x4) {
jsonArray << QStringLiteral("SHA256");
}
if(validation & 0x8) {
jsonArray << QStringLiteral("signature");
}
if(jsonArray.empty()) {
jsonArray << QStringLiteral("unknown");
}
return jsonArray;
}
/*!
* \endcond
*/
using namespace Utilities;
/*!
* \brief Returns basic information about the packages as JSON object.
*/
QJsonObject Package::basicInfo(bool includeRepoAndName) const
{
QJsonObject info;
if(includeRepoAndName) {
if(source()) {
put(info, QStringLiteral("repo"), source()->name());
}
put(info, QStringLiteral("name"), name());
}
put(info, QStringLiteral("archs"), architectures());
put(info, QStringLiteral("arch"), buildArchitecture());
put(info, QStringLiteral("ver"), version());
put(info, QStringLiteral("desc"), description());
put(info, QStringLiteral("bdate"), buildDate());
put(info, QStringLiteral("flagdate"), outOfDate());
return info;
}
/*!
* \brief Returns full information about the package as JSON object.
*/
QJsonObject Package::fullInfo(bool includeRepoAndName) const
{
QJsonObject info;
if(includeRepoAndName) {
if(source()) {
put(info, QStringLiteral("repo"), source()->name());
}
put(info, QStringLiteral("name"), name());
}
put(info, QStringLiteral("archs"), architectures());
put(info, QStringLiteral("arch"), buildArchitecture());
put(info, QStringLiteral("ver"), version());
put(info, QStringLiteral("desc"), description());
put(info, QStringLiteral("bdate"), buildDate());
put(info, QStringLiteral("bdate"), buildDate());
put(info, QStringLiteral("flagdate"), outOfDate());
put(info, QStringLiteral("idate"), installDate());
put(info, QStringLiteral("isize"), QJsonValue(static_cast<long long int>(installedSize())));
put(info, QStringLiteral("url"), upstreamUrl());
put(info, QStringLiteral("lic"), licenses());
put(info, QStringLiteral("grp"), groups());
put(info, QStringLiteral("prov"), provides());
put(info, QStringLiteral("optd"), optionalDependencies());
put(info, QStringLiteral("deps"), dependencies());
put(info, QStringLiteral("requ"), requiredBy());
put(info, QStringLiteral("optf"), optionalFor());
put(info, QStringLiteral("conf"), conflicts());
put(info, QStringLiteral("repl"), replaces());
put(info, QStringLiteral("pack"), packer());
put(info, QStringLiteral("expl"), QJsonValue(installReason() == ALPM_PKG_REASON_EXPLICIT));
put(info, QStringLiteral("scri"), QJsonValue(hasInstallScript()));
put(info, QStringLiteral("sig"), Utilities::validationMethodsStrings(validationMethods()));
put(info, QStringLiteral("file"), fileName());
put(info, QStringLiteral("files"), files());
return info;
}
/*!
* \brief The PackageVersion class helps parsing package versions.
*/
@ -94,18 +205,11 @@ inline QJsonArray qjarry(_alpm_pkgvalidation_t validation)
/*!
* \brief Constructs a new PackageVersion instance from the specified \a versionStr.
*/
PackageVersion::PackageVersion(const QString &versionStr) :
PackageVersion(versionStr.toLocal8Bit().data())
{}
/*!
* \brief Constructs a new PackageVersion instance from the specified \a versionStr.
*/
PackageVersion::PackageVersion(const char *versionStr)
PackageVersion::PackageVersion(const QString &versionStr)
{
// determine start offsets of version and release
const char *versionBeg = nullptr, *releaseBeg = nullptr;
for(const char *i = versionStr; ; ++i) {
const ushort *str = versionStr.utf16(), *versionBeg = nullptr, *releaseBeg = nullptr;
for(const auto *i = str; ; ++i) {
switch(*i) {
case 0:
goto terminationFound;
@ -123,22 +227,22 @@ PackageVersion::PackageVersion(const char *versionStr)
terminationFound:
if(versionBeg) {
// epoch present
epoch = QString::fromLocal8Bit(versionStr, versionBeg - versionStr - 1);
epoch = QString::fromUtf16(str, versionBeg - str - 1);
if(releaseBeg) {
// release present
version = QString::fromLocal8Bit(versionBeg, releaseBeg - versionBeg - 1);
release = QString::fromLocal8Bit(releaseBeg);
version = QString::fromUtf16(versionBeg, releaseBeg - versionBeg - 1);
release = QString::fromUtf16(releaseBeg);
} else {
version = QString::fromLocal8Bit(versionBeg);
version = QString::fromUtf16(versionBeg);
}
} else {
// epoch not present
if(releaseBeg) {
// release present
version = QString::fromLocal8Bit(versionStr, releaseBeg - versionStr - 1);
release = QString::fromLocal8Bit(releaseBeg);
version = QString::fromUtf16(str, releaseBeg - str - 1);
release = QString::fromUtf16(releaseBeg);
} else {
version = QString::fromLocal8Bit(versionStr);
version = QString::fromUtf16(str);
}
}
}
@ -227,157 +331,5 @@ PackageVersionComparsion PackageVersion::compare(const PackageVersion &other) co
return PackageVersionComparsion::Equal;
}
/*!
* \brief The AurPackage class holds information about AUR packages. It allows to convert the information
* to JSON objects used by the network classes and the web interface.
*/
/*!
* \brief Creates a new instance from the specified "AurJson value".
*/
AurPackage::AurPackage(const QJsonValue &aurJsonValue) :
AurPackage()
{
QJsonObject obj = aurJsonValue.toObject();
m_id = obj.value(QStringLiteral("ID")).toInt(-1);
m_categoryId = obj.value(QStringLiteral("CategoryID")).toInt(-1);
m_name = obj.value(QStringLiteral("Name")).toString();
m_version = obj.value(QStringLiteral("Version")).toString();
m_description = obj.value(QStringLiteral("Description")).toString();
m_upstreamUrl = obj.value(QStringLiteral("URL")).toString();
m_votes = obj.value(QStringLiteral("NumVotes")).toInt(0);
m_outOfDate = DateTime::fromTimeStamp(obj.value(QStringLiteral("OutOfDate")).toInt());
m_maintainer = obj.value(QStringLiteral("Maintainer")).toString();
m_firstSubmitted = DateTime::fromTimeStamp(obj.value(QStringLiteral("FirstSubmitted")).toInt());
m_lastModified = DateTime::fromTimeStamp(obj.value(QStringLiteral("LastModified")).toInt());
m_license = obj.value(QStringLiteral("License")).toString();
m_tarUrl = obj.value(QStringLiteral("URLPath")).toString();
}
/*!
* \brief Returns basic information about the packages as JSON object.
*/
QJsonObject AurPackage::basicInfo(bool includeRepoAndName) const
{
QJsonObject packageInfo;
if(includeRepoAndName) {
packageInfo.insert(QStringLiteral("repo"), QStringLiteral("aur"));
packageInfo.insert(QStringLiteral("name"), name());
}
packageInfo.insert(QStringLiteral("arch"), QStringLiteral("n.a."));
packageInfo.insert(QStringLiteral("ver"), version());
packageInfo.insert(QStringLiteral("desc"), description());
packageInfo.insert(QStringLiteral("bdate"), QStringLiteral("n.a."));
packageInfo.insert(QStringLiteral("flagdate"), outOfDate().isNull() ? QStringLiteral("none") : qstr(outOfDate().toString().data()));
return packageInfo;
}
/*!
* \brief Returns full information about the package as JSON object.
*/
QJsonObject AurPackage::fullInfo(bool includeRepoAndName) const
{
QJsonObject packageInfo;
if(includeRepoAndName) {
packageInfo.insert(QStringLiteral("repo"), QStringLiteral("aur"));
packageInfo.insert(QStringLiteral("name"), name());
}
packageInfo.insert(QStringLiteral("arch"), QStringLiteral("n.a."));
packageInfo.insert(QStringLiteral("ver"), version());
packageInfo.insert(QStringLiteral("desc"), description());
packageInfo.insert(QStringLiteral("bdate"), QStringLiteral("n.a."));
packageInfo.insert(QStringLiteral("idate"), QStringLiteral("n.a."));
packageInfo.insert(QStringLiteral("isize"), QStringLiteral("n.a."));
packageInfo.insert(QStringLiteral("url"), upstreamUrl());
packageInfo.insert(QStringLiteral("lic"), license());
packageInfo.insert(QStringLiteral("grp"), QStringLiteral("TODO"));
packageInfo.insert(QStringLiteral("prov"), QStringLiteral("TODO"));
packageInfo.insert(QStringLiteral("optd"), QStringLiteral("TODO"));
packageInfo.insert(QStringLiteral("deps"), QStringLiteral("TODO"));
packageInfo.insert(QStringLiteral("requ"), QStringLiteral("TODO"));
packageInfo.insert(QStringLiteral("optf"), QStringLiteral("TODO"));
packageInfo.insert(QStringLiteral("conf"), QStringLiteral("TODO"));
packageInfo.insert(QStringLiteral("repl"), QStringLiteral("TODO"));
packageInfo.insert(QStringLiteral("pack"), QStringLiteral("n.a."));
packageInfo.insert(QStringLiteral("expl"), QStringLiteral("n.a."));
packageInfo.insert(QStringLiteral("scri"), QStringLiteral("TODO"));
packageInfo.insert(QStringLiteral("sig"), QStringLiteral("TODO"));
packageInfo.insert(QStringLiteral("file"), QStringLiteral("n.a."));
return packageInfo;
}
/*!
* \brief The AlpmPackage class helps getting information about ALPM packages. It allows to convert the
* information to JSON objects used by the network classes and the web interface.
*/
/*!
* \brief Returns basic information about the packages as JSON object.
*/
QJsonObject AlpmPackage::basicInfo(bool includeRepoAndName) const
{
QJsonObject packageInfo;
if(includeRepoAndName) {
packageInfo.insert(QStringLiteral("repo"), qstr(AlpmDataBase(associatedDatabase()).name()));
packageInfo.insert(QStringLiteral("name"), qstr(name()));
}
packageInfo.insert(QStringLiteral("arch"), qstr(architecture()));
packageInfo.insert(QStringLiteral("ver"), qstr(version()));
packageInfo.insert(QStringLiteral("desc"), qstr(description()));
packageInfo.insert(QStringLiteral("bdate"), qstr(buildDate().toString().c_str()));
packageInfo.insert(QStringLiteral("flagdate"), QStringLiteral("n.a."));
return packageInfo;
}
/*!
* \brief Returns full information about the package as JSON object.
*/
QJsonObject AlpmPackage::fullInfo(bool includeRepoAndName) const
{
QJsonObject packageInfo;
if(includeRepoAndName) {
packageInfo.insert(QStringLiteral("repo"), qstr(AlpmDataBase(associatedDatabase()).name()));
packageInfo.insert(QStringLiteral("name"), qstr(name()));
}
packageInfo.insert(QStringLiteral("arch"), qstr(architecture()));
packageInfo.insert(QStringLiteral("ver"), qstr(version()));
packageInfo.insert(QStringLiteral("desc"), qstr(description()));
packageInfo.insert(QStringLiteral("bdate"), qstr(buildDate().toString().c_str()));
packageInfo.insert(QStringLiteral("idate"), qstr(installDate().toString().c_str()));
packageInfo.insert(QStringLiteral("isize"), static_cast<long long int>(installedSize()));
packageInfo.insert(QStringLiteral("url"), qstr(upstreamUrl()));
packageInfo.insert(QStringLiteral("lic"), qjarry(licenses()));
packageInfo.insert(QStringLiteral("grp"), qjarry(groups()));
packageInfo.insert(QStringLiteral("prov"), qjarry(provides()));
packageInfo.insert(QStringLiteral("optd"), qjarry(optionalDependencies()));
packageInfo.insert(QStringLiteral("deps"), qjarry(dependencies()));
packageInfo.insert(QStringLiteral("requ"), qjarry(requiredBy()));
packageInfo.insert(QStringLiteral("optf"), qjarry(optionalFor()));
packageInfo.insert(QStringLiteral("conf"), qjarry(conflicts()));
packageInfo.insert(QStringLiteral("repl"), qjarry(replaces()));
packageInfo.insert(QStringLiteral("pack"), qstr(packager()));
packageInfo.insert(QStringLiteral("expl"), installReason() == ALPM_PKG_REASON_EXPLICIT);
packageInfo.insert(QStringLiteral("scri"), hasInstallScript());
packageInfo.insert(QStringLiteral("sig"), qjarry(validation()));
packageInfo.insert(QStringLiteral("file"), qstr(fileName()));
QJsonArray fileInfos;
alpm_filelist_t *fileList = files();
for(alpm_file_t *file = fileList->files, *end = fileList->files + fileList->count; file != end; ++file) {
QJsonObject fileInfo;
fileInfo.insert(QStringLiteral("name"), qstr(file->name));
if(file->mode) {
fileInfo.insert(QStringLiteral("mode"), static_cast<int>(file->mode));
}
if(file->size) {
fileInfo.insert(QStringLiteral("size"), static_cast<int>(file->size));
}
fileInfos << fileInfo;
}
packageInfo.insert(QStringLiteral("files"), fileInfos);
return packageInfo;
}
}

View File

@ -12,14 +12,15 @@
#include <QString>
#include <QHash>
#include <QJsonArray>
QT_BEGIN_NAMESPACE
class QJsonObject;
class QJsonValue;
QT_END_NAMESPACE
QT_FORWARD_DECLARE_CLASS(QJsonObject)
QT_FORWARD_DECLARE_CLASS(QJsonValue)
namespace PackageManagement {
class Repository;
/*!
* \brief The PackageVersionComparsion enum defines possible results of packages version comparison.
*/
@ -41,11 +42,29 @@ enum class PackageVersionPartComparsion
Older /*!< Part 2 is newer then part 1. */
};
/*!
* \brief The PackageOrigin enum describes where a Package instance comes from.
*/
enum class PackageOrigin
{
Unknown = 20, /*! The origin is unknown. */
File = ALPM_PKG_FROM_FILE, /*!< The instance has been created from a package file; source() returns nullptr in this case. */
LocalDb = ALPM_PKG_FROM_LOCALDB, /*! The instance is from the local data base; source() is an AlpmDataBase instance. */
SyncDb = ALPM_PKG_FROM_SYNCDB, /*! The instance is from a sync data base; source() is an AlpmDataBase instance. */
Aur = 21 /*! The instance is from the AUR; source() is a UserRepository instance. */
};
enum class InstallStatus
{
Explicit = ALPM_PKG_REASON_EXPLICIT,
AsDependency = ALPM_PKG_REASON_DEPEND,
None = 20
};
class PackageVersion
{
public:
PackageVersion(const QString &versionStr);
PackageVersion(const char *versionStr);
explicit PackageVersion(const QString &versionStr);
static PackageVersionPartComparsion compareParts(const QString &part1, const QString &part2);
PackageVersionComparsion compare(const PackageVersion &other) const;
@ -55,487 +74,525 @@ public:
QString release;
};
class AurPackage
class Dependency
{
public:
AurPackage();
AurPackage(const QJsonValue &aurJsonValue);
explicit Dependency(const QString &name, const QString &version, _alpm_depmod_t mode = ALPM_DEP_MOD_ANY);
QString name;
QString version;
_alpm_depmod_t mode;
};
bool isValid() const;
bool hasFullInfo() const;
int id() const;
int categoryId() const;
inline Dependency::Dependency(const QString &name, const QString &version, _alpm_depmod_t mode) :
name(name),
version(version),
mode(mode)
{}
class Package
{
public:
virtual ~Package();
// general package meta data
PackageOrigin origin() const;
Repository *source() const;
bool hasGeneralInfo() const;
const QString &name() const;
const QString &version() const;
template<class Package>
PackageVersionComparsion compareVersion(const Package &syncPackage) const;
const QString &description() const;
const QString &upstreamUrl() const;
const QStringList &licenses() const;
const QStringList &groups() const;
const QList<Dependency> &dependencies() const;
const QList<Dependency> &optionalDependencies() const;
const QList<Dependency> &conflicts() const;
const QList<Dependency> &provides() const;
const QList<Dependency> &replaces() const;
const QStringList &requiredBy() const;
const QStringList &optionalFor() const;
bool hasInstallScript() const;
// build related meta data
bool hasBuildRelatedMetaData() const;
const QString &fileName() const;
const QJsonArray &files() const;
ChronoUtilities::DateTime buildDate() const;
const QString &packer() const;
const QString &md5() const;
const QString &sha256() const;
const QString &buildArchitecture() const;
uint32 packageSize() const;
const QList<Dependency> &makeDependencies() const;
// installation related meta data
bool hasInstallRelatedMetaData() const;
ChronoUtilities::DateTime installDate() const;
uint32 installedSize() const;
const QStringList &backupFiles() const;
alpm_pkgvalidation_t validationMethods() const;
alpm_pkgreason_t installReason() const;
// source related meta data
bool hasSourceRelatedMetaData() const;
const QString &baseName() const;
const QStringList &architectures() const;
int id() const;
int categoryId() const;
int votes() const;
ChronoUtilities::DateTime outOfDate() const;
const QString &maintainer() const;
ChronoUtilities::DateTime firstSubmitted() const;
ChronoUtilities::DateTime lastModified() const;
const QString &license() const;
const QString &tarUrl() const;
// JSON serialization
QJsonObject basicInfo(bool includeRepoAndName) const;
QJsonObject fullInfo(bool includeRepoAndName = false) const;
private:
bool m_fullInfo;
int m_id;
int m_categoryId;
QString m_name;
QString m_version;
QString m_description;
QString m_upstreamUrl;
int m_votes;
ChronoUtilities::DateTime m_outOfDate;
QString m_maintainer;
ChronoUtilities::DateTime m_firstSubmitted;
ChronoUtilities::DateTime m_lastModified;
QString m_license;
QString m_tarUrl;
};
/*!
* \brief Constructs a empty, invalid AUR package.
*/
inline AurPackage::AurPackage() :
m_fullInfo(false),
m_id(-1),
m_categoryId(-1),
m_votes(-1),
m_outOfDate(false)
{}
/*!
* \brief Returns an indication whether the package is valid.
*/
inline bool AurPackage::isValid() const
{
return m_id >= 0;
}
/*!
* \brief Returns an indication whether full package info is available.
*/
inline bool AurPackage::hasFullInfo() const
{
return m_fullInfo;
}
/*!
* \brief Returns the ID of the package in the AUR.
*/
inline int AurPackage::id() const
{
return m_id;
}
/*!
* \brief Returns the category ID of the package in the AUR.
*/
inline int AurPackage::categoryId() const
{
return m_categoryId;
}
/*!
* \brief Returns the name of the package.
*/
inline const QString &AurPackage::name() const
{
return m_name;
}
/*!
* \brief Returns the version of the package.
*/
inline const QString &AurPackage::version() const
{
return m_version;
}
template<class Package>
inline PackageVersionComparsion AurPackage::compareVersion(const Package &syncPackage) const
{
return PackageVersion(version()).compare(PackageVersion(syncPackage.version()));
}
/*!
* \brief Returns the description of the package.
*/
inline const QString &AurPackage::description() const
{
return m_description;
}
/*!
* \brief Returns the upstream URL of the package.
*/
inline const QString &AurPackage::upstreamUrl() const
{
return m_upstreamUrl;
}
/*!
* \brief Returns the votes of the package in the AUR.
*/
inline int AurPackage::votes() const
{
return m_votes;
}
/*!
* \brief Returns wheter the package is flagged as out-of-date.
*/
inline ChronoUtilities::DateTime AurPackage::outOfDate() const
{
return m_outOfDate;
}
/*!
* \brief Returns the maintainer of the package.
*/
inline const QString &AurPackage::maintainer() const
{
return m_maintainer;
}
/*!
* \brief Returns the time the package was first submitted.
*/
inline ChronoUtilities::DateTime AurPackage::firstSubmitted() const
{
return m_firstSubmitted;
}
/*!
* \brief Returns the time the package was last modified.
*/
inline ChronoUtilities::DateTime AurPackage::lastModified() const
{
return m_lastModified;
}
/*!
* \brief Returns the license.
*/
inline const QString &AurPackage::license() const
{
return m_license;
}
/*!
* \brief Returns a URL to the tar file from AUR.
*/
inline const QString &AurPackage::tarUrl() const
{
return m_tarUrl;
}
class AlpmPackage
{
public:
AlpmPackage(alpm_pkg_t *package = nullptr);
// package properties
const alpm_pkg_t *ptr() const;
alpm_pkg_t *ptr();
bool hasInstallScript() const;
const char *fileName() const;
const char *name() const;
const char *version() const;
template<class Package>
PackageVersionComparsion compareVersion(const Package &syncPackage) const;
alpm_pkgfrom_t origin() const;
const char *description() const;
const char *upstreamUrl() const;
ChronoUtilities::DateTime buildDate() const;
ChronoUtilities::DateTime installDate() const;
const char *packager() const;
const char *md5() const;
const char *sha256() const;
const char *architecture() const;
off_t packageSize() const;
off_t installedSize() const;
alpm_pkgreason_t installReason() const;
void setInstallReason(alpm_pkgreason_t reason);
StringList licenses() const;
StringList groups() const;
DependencyList dependencies() const;
DependencyList optionalDependencies() const;
DependencyList conflicts() const;
DependencyList provides() const;
StringList deltas() const;
DependencyList replaces() const;
alpm_filelist_t *files() const;
AlpmList<alpm_backup_t *> backupFiles() const;
alpm_db_t *associatedDatabase() const;
const char *base64Signature() const;
alpm_pkgvalidation_t validation() const;
StringList requiredBy() const;
StringList optionalFor() const;
void *openChangelog() const;
size_t readChangelog(void *changelog, void *buffer, size_t bufferSize);
bool closeChangelog(void *changelog);
operator bool() const;
// version comparsion
PackageVersionComparsion compareVersion(const Package *syncPackage) const;
PackageVersionComparsion compareVersion(const Dependency &dependency) const;
static bool matches(const QString &name, const QString &version, const Dependency &dependency);
bool matches(const Dependency &dependency);
// JSON serialization
QJsonObject basicInfo(bool includeRepoAndName = false) const;
QJsonObject fullInfo(bool includeRepoAndName = false) const;
protected:
alpm_pkg_t *m_ptr;
explicit Package(const QString &name, Repository *source);
PackageOrigin m_origin;
Repository *m_source;
// general package meta data
bool m_hasGeneralInfo;
QString m_name;
QString m_version;
QString m_description;
QString m_upstreamUrl;
QStringList m_licenses;
QStringList m_groups;
QList<Dependency> m_dependencies;
QList<Dependency> m_optionalDependencies;
QList<Dependency> m_conflicts;
QList<Dependency> m_provides;
QList<Dependency> m_replaces;
QStringList m_requiredBy;
QStringList m_optionalFor;
bool m_hasInstallScript;
// build related meta data
bool m_hasBuildRelatedMetaData;
QString m_fileName;
QJsonArray m_files;
ChronoUtilities::DateTime m_buildDate;
QString m_packer;
QString m_md5;
QString m_sha256;
QString m_buildArchitecture;
uint32 m_packageSize;
QList<Dependency> m_makeDependencies;
// installation related meta data
bool m_hasInstallRelatedMetaData;
ChronoUtilities::DateTime m_installDate;
uint32 m_installedSize;
QStringList m_backupFiles;
alpm_pkgvalidation_t m_validationMethods;
alpm_pkgreason_t m_installReason;
// source related meta data
bool m_hasSourceRelatedMetaData;
QString m_baseName;
QStringList m_architectures;
int m_id;
int m_categoryId;
int m_votes;
ChronoUtilities::DateTime m_outOfDate;
QString m_maintainer;
ChronoUtilities::DateTime m_firstSubmitted;
ChronoUtilities::DateTime m_lastModified;
QString m_tarUrl;
};
inline uint qHash(const AlpmPackage &key)
{
return qHash(key.ptr());
}
/*!
* \brief Constructs a new package instance for the specified ALPM \a package.
* \brief Returns where the package instance comes from (local db, sync db, pkg file, AUR).
*/
inline AlpmPackage::AlpmPackage(alpm_pkg_t *package) :
m_ptr(package)
{}
inline const alpm_pkg_t *AlpmPackage::ptr() const
inline PackageOrigin Package::origin() const
{
return m_ptr;
}
inline alpm_pkg_t *AlpmPackage::ptr()
{
return m_ptr;
}
inline bool AlpmPackage::hasInstallScript() const
{
return alpm_pkg_has_scriptlet(m_ptr);
}
inline const char *AlpmPackage::fileName() const
{
return alpm_pkg_get_filename(m_ptr);
}
inline const char *AlpmPackage::name() const
{
return alpm_pkg_get_name(m_ptr);
}
inline const char *AlpmPackage::version() const
{
return alpm_pkg_get_version(m_ptr);
return m_origin;
}
/*!
* \brief Compares the version of this package with the version of the specified package.
* \brief Returns the package source.
* \remarks Might be nullptr if no source is associated.
*/
inline Repository *Package::source() const
{
return m_source;
}
/*!
* \brief Returns whether general information is available for the package.
*/
inline bool Package::hasGeneralInfo() const
{
return m_hasGeneralInfo;
}
/*!
* \brief Returns the name.
*/
inline const QString &Package::name() const
{
return m_name;
}
/*!
* \brief Returns the version.
*/
inline const QString &Package::version() const
{
return m_version;
}
/*!
* \brief Returns the description.
*/
inline const QString &Package::description() const
{
return m_description;
}
/*!
* \brief Returns the upstream URL.
*/
inline const QString &Package::upstreamUrl() const
{
return m_upstreamUrl;
}
/*!
* \brief Returns the licenses.
*/
inline const QStringList &Package::licenses() const
{
return m_licenses;
}
/*!
* \brief Returns the groups.
*/
inline const QStringList &Package::groups() const
{
return m_groups;
}
/*!
* \brief Returns the dependencies.
*/
inline const QList<Dependency> &Package::dependencies() const
{
return m_dependencies;
}
/*!
* \brief Returns the optional dependencies.
*/
inline const QList<Dependency> &Package::optionalDependencies() const
{
return m_optionalDependencies;
}
/*!
* \brief Returns conflicting packages.
*/
inline const QList<Dependency> &Package::conflicts() const
{
return m_conflicts;
}
/*!
* \brief Returns provides.
*/
inline const QList<Dependency> &Package::provides() const
{
return m_provides;
}
/*!
* \brief Returns packages which are replaced by this package.
*/
inline const QList<Dependency> &Package::replaces() const
{
return m_replaces;
}
/*!
* \brief Returns packages requiring this packages.
*/
inline const QStringList &Package::requiredBy() const
{
return m_requiredBy;
}
/*!
* \brief Returns packages having this package as optional dependency.
*/
inline const QStringList &Package::optionalFor() const
{
return m_optionalFor;
}
/*!
* \brief Returns whether the package has an install script.
*/
inline bool Package::hasInstallScript() const
{
return m_hasInstallScript;
}
/*!
* \brief Returns whether the package has build-related meta data.
*
* This method distinguishes between software upgrades and package releases. See Alpm::PackageVersionComparsion enum.
* Build-related meta data is information about a particular package file such
* as architecture, file name, build date, ....
*/
template<class Package>
inline PackageVersionComparsion AlpmPackage::compareVersion(const Package &syncPackage) const
inline bool Package::hasBuildRelatedMetaData() const
{
return PackageVersion(version()).compare(PackageVersion(syncPackage.version()));
return m_hasBuildRelatedMetaData;
}
inline alpm_pkgfrom_t AlpmPackage::origin() const
/*!
* \brief Returns the file name of the package file.
*/
inline const QString &Package::fileName() const
{
return alpm_pkg_get_origin(m_ptr);
return m_fileName;
}
inline const char *AlpmPackage::description() const
/*!
* \brief Returns the file of the package as JSON array.
*/
inline const QJsonArray &Package::files() const
{
return alpm_pkg_get_desc(m_ptr);
return m_files;
}
inline const char *AlpmPackage::upstreamUrl() const
/*!
* \brief Returns the build date of the package file.
*/
inline ChronoUtilities::DateTime Package::buildDate() const
{
return alpm_pkg_get_url(m_ptr);
return m_buildDate;
}
inline ChronoUtilities::DateTime AlpmPackage::buildDate() const
/*!
* \brief Returns the packer of the package file.
*/
inline const QString &Package::packer() const
{
return ChronoUtilities::DateTime::fromTimeStamp(static_cast<time_t>(alpm_pkg_get_builddate(m_ptr)));
return m_packer;
}
inline ChronoUtilities::DateTime AlpmPackage::installDate() const
/*!
* \brief Returns the MD5 hash of the package file.
*/
inline const QString &Package::md5() const
{
return ChronoUtilities::DateTime::fromTimeStamp(static_cast<time_t>(alpm_pkg_get_installdate(m_ptr)));
return m_md5;
}
inline const char *AlpmPackage::packager() const
/*!
* \brief Returns the SHA-256 hash of the package file.
*/
inline const QString &Package::sha256() const
{
return alpm_pkg_get_packager(m_ptr);
return m_sha256;
}
inline const char *AlpmPackage::md5() const
/*!
* \brief Returns the architecture of the package file.
*/
inline const QString &Package::buildArchitecture() const
{
return alpm_pkg_get_md5sum(m_ptr);
return m_buildArchitecture;
}
inline const char *AlpmPackage::sha256() const
/*!
* \brief Returns the size of the package file.
*/
inline uint32 Package::packageSize() const
{
return alpm_pkg_get_sha256sum(m_ptr);
return m_packageSize;
}
inline const char *AlpmPackage::architecture() const
/*!
* \brief Returns make dependencies.
*/
inline const QList<Dependency> &Package::makeDependencies() const
{
return alpm_pkg_get_arch(m_ptr);
return m_makeDependencies;
}
inline off_t AlpmPackage::packageSize() const
/*!
* \brief Returns whether install-related meta data is available.
*
* Install-related meta data is information such as the install date,
* the installed size, files backuped during installation, ...
*
* Most of the install-related meta data is only available for packages
* from the local data base (see origin()).
*/
inline bool Package::hasInstallRelatedMetaData() const
{
return alpm_pkg_get_size(m_ptr);
return m_hasInstallRelatedMetaData;
}
inline off_t AlpmPackage::installedSize() const
/*!
* \brief Returns the install date.
*/
inline ChronoUtilities::DateTime Package::installDate() const
{
return alpm_pkg_get_isize(m_ptr);
return m_installDate;
}
inline alpm_pkgreason_t AlpmPackage::installReason() const
/*!
* \brief Returns the installed size.
*/
inline uint32 Package::installedSize() const
{
return alpm_pkg_get_reason(m_ptr);
return m_installedSize;
}
inline StringList AlpmPackage::licenses() const
/*!
* \brief Returns the files which have been backued up during installation.
*/
inline const QStringList &Package::backupFiles() const
{
return alpm_pkg_get_licenses(m_ptr);
return m_backupFiles;
}
inline StringList AlpmPackage::groups() const
/*!
* \brief Returns the validation methods used during installation.
*/
inline alpm_pkgvalidation_t Package::validationMethods() const
{
return alpm_pkg_get_groups(m_ptr);
return m_validationMethods;
}
inline DependencyList AlpmPackage::dependencies() const
/*!
* \brief Returns whether the package has been installed explicitely or as a dependency.
*/
inline alpm_pkgreason_t Package::installReason() const
{
return alpm_pkg_get_depends(m_ptr);
return m_installReason;
}
inline DependencyList AlpmPackage::optionalDependencies() const
/*!
* \brief Returns whether source-related meta data is available.
*
* Source-related meta data is information about the PKGBUILD file such has
* its AUR IDs, AUR votes, maintainer, flag date, ...
*/
inline bool Package::hasSourceRelatedMetaData() const
{
return alpm_pkg_get_optdepends(m_ptr);
return m_hasSourceRelatedMetaData;
}
inline DependencyList AlpmPackage::conflicts() const
/*!
* \brief Returns the base name.
*/
inline const QString &Package::baseName() const
{
return alpm_pkg_get_conflicts(m_ptr);
return m_baseName;
}
inline DependencyList AlpmPackage::provides() const
/*!
* \brief Returns the architecutes (from the PKGBUILD file).
* \remarks For the architecture of the particular binary package
* see buildArchitecture().
*/
inline const QStringList &Package::architectures() const
{
return alpm_pkg_get_provides(m_ptr);
return m_architectures;
}
inline StringList AlpmPackage::deltas() const
/*!
* \brief Returns the ID.
*/
inline int Package::id() const
{
return alpm_pkg_get_deltas(m_ptr);
return m_id;
}
inline DependencyList AlpmPackage::replaces() const
/*!
* \brief Returns the category ID.
*/
inline int Package::categoryId() const
{
return alpm_pkg_get_replaces(m_ptr);
return m_categoryId;
}
inline alpm_filelist_t *AlpmPackage::files() const
/*!
* \brief Returns the votes of the package.
*/
inline int Package::votes() const
{
return alpm_pkg_get_files(m_ptr);
return m_votes;
}
inline AlpmList<alpm_backup_t *> AlpmPackage::backupFiles() const
/*!
* \brief Returns the flag date.
*/
inline ChronoUtilities::DateTime Package::outOfDate() const
{
return alpm_pkg_get_backup(m_ptr);
return m_outOfDate;
}
inline alpm_db_t *AlpmPackage::associatedDatabase() const
/*!
* \brief Returns the maintainer.
*/
inline const QString &Package::maintainer() const
{
return alpm_pkg_get_db(m_ptr);
return m_maintainer;
}
inline const char *AlpmPackage::base64Signature() const
/*!
* \brief Returns when the package was first submitted.
*/
inline ChronoUtilities::DateTime Package::firstSubmitted() const
{
return alpm_pkg_get_base64_sig(m_ptr);
return m_firstSubmitted;
}
inline alpm_pkgvalidation_t AlpmPackage::validation() const
/*!
* \brief Returns the last time when the package was modified.
*/
inline ChronoUtilities::DateTime Package::lastModified() const
{
return alpm_pkg_get_validation(m_ptr);
return m_lastModified;
}
inline StringList AlpmPackage::requiredBy() const
/*!
* \brief Returns a URL to a tar file with the sources.
*/
inline const QString &Package::tarUrl() const
{
return alpm_pkg_compute_requiredby(m_ptr);
return m_tarUrl;
}
inline StringList AlpmPackage::optionalFor() const
inline PackageVersionComparsion Package::compareVersion(const Package *syncPackage) const
{
return alpm_pkg_compute_optionalfor(m_ptr);
return PackageVersion(version()).compare(PackageVersion(syncPackage->version()));
}
inline void *AlpmPackage::openChangelog() const
inline PackageVersionComparsion Package::compareVersion(const Dependency &dependency) const
{
return alpm_pkg_changelog_open(m_ptr);
return PackageVersion(version()).compare(PackageVersion(dependency.version));
}
inline size_t AlpmPackage::readChangelog(void *changelog, void *buffer, size_t bufferSize)
inline bool Package::matches(const Dependency &dependency)
{
return alpm_pkg_changelog_read(buffer, bufferSize, m_ptr, changelog);
}
inline bool AlpmPackage::closeChangelog(void *changelog)
{
return alpm_pkg_changelog_close(m_ptr, changelog);
}
inline PackageManagement::AlpmPackage::operator bool() const
{
return m_ptr != nullptr;
}
class AlpmOwnershipPackage : public AlpmPackage
{
public:
// constructor, destructor
AlpmOwnershipPackage(alpm_pkg_t *package);
AlpmOwnershipPackage(const AlpmOwnershipPackage &other) = delete;
AlpmOwnershipPackage(AlpmOwnershipPackage &&other);
~AlpmOwnershipPackage();
// assignment operator
AlpmOwnershipPackage &operator =(const AlpmOwnershipPackage &other) = delete;
AlpmOwnershipPackage &operator =(AlpmOwnershipPackage &&other);
};
inline AlpmOwnershipPackage::AlpmOwnershipPackage(alpm_pkg_t *package) :
AlpmPackage(package)
{}
inline AlpmOwnershipPackage::AlpmOwnershipPackage(AlpmOwnershipPackage &&other) :
AlpmPackage(other.m_ptr)
{
other.m_ptr = nullptr;
}
inline AlpmOwnershipPackage &AlpmOwnershipPackage::operator =(AlpmOwnershipPackage &&other)
{
if(this != &other) {
m_ptr = other.m_ptr;
other.m_ptr = nullptr;
}
return *this;
}
inline AlpmOwnershipPackage::~AlpmOwnershipPackage()
{
alpm_pkg_free(ptr());
return matches(name(), version(), dependency);
}
}

298
alpm/repository.cpp Normal file
View File

@ -0,0 +1,298 @@
#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

288
alpm/repository.h Normal file
View File

@ -0,0 +1,288 @@
#ifndef PACKAGEMANAGEMENT_PACKAGESOURCE_H
#define PACKAGEMANAGEMENT_PACKAGESOURCE_H
#include "package.h"
#include "group.h"
#include <QObject>
#include <memory>
#include <functional>
QT_FORWARD_DECLARE_CLASS(QNetworkReply)
namespace PackageManagement {
class UpgradeLookupResults;
class Reply : public QObject
{
Q_OBJECT
public:
Reply(QNetworkReply *networkReply);
const QString &error() const;
signals:
void resultsAvailable();
private slots:
virtual void processData() = 0;
protected:
QNetworkReply *m_networkReply;
QString m_error;
};
inline const QString &Reply::error() const
{
return m_error;
}
class PackageReply : public Reply
{
Q_OBJECT
public:
PackageReply(QNetworkReply *networkReply, std::map<QString, std::unique_ptr<Package> > &packages);
const std::map<QString, std::unique_ptr<Package> > &packages() const;
protected:
std::map<QString, std::unique_ptr<Package> > &m_packages;
};
inline PackageReply::PackageReply(QNetworkReply *networkReply, std::map<QString, std::unique_ptr<Package> > &packages) :
Reply(networkReply),
m_packages(packages)
{}
inline const std::map<QString, std::unique_ptr<Package> > &PackageReply::packages() const
{
return m_packages;
}
class SuggestionsReply : public Reply
{
Q_OBJECT
public:
SuggestionsReply(QNetworkReply *networkReply);
const QJsonArray &suggestions() const;
protected:
QJsonArray m_suggestions;
};
inline SuggestionsReply::SuggestionsReply(QNetworkReply *networkReply) :
Reply(networkReply)
{}
inline const QJsonArray &SuggestionsReply::suggestions() const
{
return m_suggestions;
}
enum class RepositoryType
{
AlpmDataBase, /*! The repository is an AlpmDataBase instance. */
UserRepository, /*! The repository is a UserRepository instance. */
Other /*! The repository type is unknown. */
};
class Repository : public QObject
{
Q_OBJECT
public:
~Repository();
virtual RepositoryType type() const = 0;
// general meta data
const QString &name() const;
const QString &description() const;
const std::map<QString, std::unique_ptr<Package> > &packages() const;
std::map<QString, std::unique_ptr<Package> > &packages();
const QStringList packageNames() const;
alpm_db_usage_t usage() const;
virtual bool isSourceOnly() const;
const std::map<QString, QList<Package *> > &groups() const;
const QStringList &serverUrls() const;
alpm_siglevel_t sigLevel() const;
// gathering data
virtual bool requestsRequired() const;
virtual SuggestionsReply *requestSuggestions(const QString &phrase) const;
virtual PackageReply *requestPackageInfo(const QStringList &packageNames, bool forceUpdate = false) const;
virtual PackageReply *requestFullPackageInfo(const QString &package, bool forceUpdate = false) const;
// package search
const Package *packageByName(const QString &name) const;
Package *packageByName(const QString &name);
const Package *packageProviding(const Dependency &dependency) const;
QList<const Package *> packagesProviding(const Dependency &dependency) const;
QList<Package *> packageByFilter(std::function<bool (const Package *)> pred);
// upgrade lookup
const QList<const Repository *> &upgradeSources() const;
QList<const Repository *> &upgradeSources();
QJsonArray upgradeSourcesJsonArray() const;
void checkForUpgrades(UpgradeLookupResults &results) const;
void checkForUpgrades(UpgradeLookupResults &results, const QList<const Repository *> &upgradeSources) const;
// build system
const QString &sourcesDirectory() const;
void setSourcesDirectory(const QString &dir);
const QString &packagesDirectory() const;
void setPackagesDirectory(const QString &dir);
// JSON serialization
QJsonArray packageNamesJsonArray() const;
QJsonObject basicInfo() const;
QJsonObject groupInfo() const;
protected:
explicit Repository(const QString &name, QObject *parent = nullptr);
QString m_name;
QString m_description;
std::map<QString, std::unique_ptr<Package> > m_packages;
alpm_db_usage_t m_usage;
std::map<QString, QList<Package *> > m_groups;
QStringList m_serverUrls;
alpm_siglevel_t m_sigLevel;
QList<const Repository *> m_upgradeSources;
QString m_srcDir;
QString m_pkgDir;
};
/*!
* \brief Returns the name.
*/
inline const QString &Repository::name() const
{
return m_name;
}
/*!
* \brief Returns the description.
*/
inline const QString &Repository::description() const
{
return m_description;
}
/*!
* \brief Returns the packages.
*/
inline const std::map<QString, std::unique_ptr<Package> > &Repository::packages() const
{
return m_packages;
}
/*!
* \brief Returns the packages.
*/
inline std::map<QString, std::unique_ptr<Package> > &Repository::packages()
{
return m_packages;
}
/*!
* \brief Returns the package with the specified \a name or nullptr if the package can not be found.
* \remarks Ownership remains by this instance.
*/
inline const Package *Repository::packageByName(const QString &name) const
{
try {
return m_packages.at(name).get();
} catch(const std::out_of_range &) {
return nullptr;
}
}
/*!
* \brief Returns the package with the specified \a name or nullptr if the package can not be found.
* \remarks Ownership remains by this instance.
*/
inline Package *Repository::packageByName(const QString &name)
{
try {
return m_packages.at(name).get();
} catch(const std::out_of_range &) {
return nullptr;
}
}
inline alpm_db_usage_t Repository::usage() const
{
return m_usage;
}
inline const std::map<QString, QList<Package *> > &Repository::groups() const
{
return m_groups;
}
/*!
* \brief Returns the server URLs.
*/
inline const QStringList &Repository::serverUrls() const
{
return m_serverUrls;
}
/*!
* \brief Returns the signature level of the database.
*/
inline alpm_siglevel_t Repository::sigLevel() const
{
return m_sigLevel;
}
inline const QList<const Repository *> &Repository::upgradeSources() const
{
return m_upgradeSources;
}
inline QList<const Repository *> &Repository::upgradeSources()
{
return m_upgradeSources;
}
inline void Repository::checkForUpgrades(UpgradeLookupResults &results) const
{
checkForUpgrades(results, upgradeSources());
}
/*!
* \brief Returns the path of the local sources directory.
*/
inline const QString &Repository::sourcesDirectory() const
{
return m_srcDir;
}
/*!
* \brief Sets the path of the local sources directory.
*/
inline void Repository::setSourcesDirectory(const QString &dir)
{
m_srcDir = dir;
}
/*!
* \brief Returns the path of the local packages directory.
*/
inline const QString &Repository::packagesDirectory() const
{
return m_pkgDir;
}
/*!
* \brief Sets the path of the local packages directory.
*/
inline void Repository::setPackagesDirectory(const QString &dir)
{
m_pkgDir = dir;
}
} // namespace PackageManagement
#endif // PACKAGEMANAGEMENT_PACKAGESOURCE_H

View File

@ -172,8 +172,8 @@ QStringList BuildOrderResolver::resolve(const StringVector &packages) const
void BuildOrderResolver::addDeps(QList<TaskInfo *> &tasks, TaskInfo *task) const
{
if(const auto pkg = m_manager.packageFromSyncDataBases(task->name().toLocal8Bit().data())) {
for(auto dep : pkg.dependencies()) {
if(auto *depTask = addDep(tasks, dep->name)) {
for(auto dep : pkg->dependencies()) {
if(auto *depTask = addDep(tasks, dep.name)) {
task->addDep(depTask);
}
}
@ -184,7 +184,7 @@ void BuildOrderResolver::addDeps(QList<TaskInfo *> &tasks, TaskInfo *task) const
}
}
TaskInfo *BuildOrderResolver::addDep(QList<TaskInfo *> &tasks, const char *depName) const
TaskInfo *BuildOrderResolver::addDep(QList<TaskInfo *> &tasks, const QString &depName) const
{
if(auto *task = TaskInfo::find(tasks, depName)) {
// we've already added a task for this dependency

View File

@ -20,7 +20,7 @@ public:
private:
void addDeps(QList<TaskInfo *> &tasks, TaskInfo *task) const;
TaskInfo *addDep(QList<TaskInfo *> &pkgInfos, const char *depName) const;
TaskInfo *addDep(QList<TaskInfo *> &pkgInfos, const QString &depName) const;
const Manager &m_manager;
};

View File

@ -1,185 +0,0 @@
#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

View File

@ -1,145 +0,0 @@
#ifndef PACKAGEMANAGEMENT_UPDATELOOKUP_H
#define PACKAGEMANAGEMENT_UPDATELOOKUP_H
#include "package.h"
#include <QObject>
#include <QJsonObject>
#include <QJsonArray>
#include <QFutureWatcher>
#include <functional>
QT_FORWARD_DECLARE_CLASS(QNetworkReply)
namespace PackageManagement {
class Manager;
class AlpmDataBase;
typedef std::function<void (const QJsonObject &&results)> UpdateLookupCallback;
template<class Package, class VersionType = QString>
class UpdateResult
{
public:
UpdateResult(const Package &package, const VersionType &previousVersion);
Package package;
VersionType previousVersion;
QJsonObject json() const;
};
template<class Package, class VersionType>
inline UpdateResult<Package, VersionType>::UpdateResult(const Package &package, const VersionType &previousVersion) :
package(package),
previousVersion(previousVersion)
{}
template<class Package, class VersionType>
QJsonObject UpdateResult<Package, VersionType>::json() const
{
QJsonObject obj;
obj.insert(QStringLiteral("pkg"), package.basicInfo(true));
obj.insert(QStringLiteral("prevVersion"), previousVersion);
return obj;
}
template<class Package>
inline UpdateResult<Package> makeUpdateResult(const Package &package, const QString &previousVersion)
{
return UpdateResult<Package>(package, previousVersion);
}
template<class Package>
inline UpdateResult<Package> makeUpdateResult(const Package &package, const char *previousVersion)
{
return UpdateResult<Package>(package, QString::fromLocal8Bit(previousVersion));
}
template<class Package>
class UpdateLookupResults
{
public:
UpdateLookupResults();
/*!
* \brief Indicates that there are no upgrade sources available.
*/
bool noSources;
/*!
* \brief Packages providing a software upgrade (new version).
*/
QList<UpdateResult<Package> > newVersions;
/*!
* \brief Package upgrades only (new release).
*/
QList<UpdateResult<Package> > newReleases;
/*!
* \brief Downgrades (older version in sync db).
*/
QList<UpdateResult<Package> > downgrades;
/*!
* \brief Orphaned packages (could not be found in any of the sync dbs).
*/
QSet<AlpmPackage> orphaned;
/*!
* \brief Warnings occured when checking for updates.
*/
QStringList warnings;
/*!
* \brief Errors occured when checking for updates.
*/
QStringList errors;
};
/*!
* \brief Constructs new update lookup results.
*/
template<class Package>
inline UpdateLookupResults<Package>::UpdateLookupResults() :
noSources(false)
{}
class UpdateLookup : public QObject
{
Q_OBJECT
public:
explicit UpdateLookup(const Manager &manager, const QJsonObject &request, const UpdateLookupCallback callback, QObject *parent = nullptr);
private slots:
UpdateLookupResults<AlpmPackage> checkSyncDbs(const QJsonValue &syncDbsValue);
void aurPackageInfoAvailable(const QNetworkReply *reply);
UpdateLookupResults<AurPackage> checkAur();
void lookupDone();
private:
const Manager &m_manager;
const QJsonObject m_request;
const UpdateLookupCallback m_callback;
const AlpmDataBase *m_db;
QFutureWatcher<UpdateLookupResults<AlpmPackage> > *m_syncDbsWatcher;
QFutureWatcher<UpdateLookupResults<AurPackage> > *m_aurWatcher;
UpdateLookupResults<AlpmPackage> m_syncDbsResults;
UpdateLookupResults<AurPackage> m_aurResults;
QNetworkReply *m_aurReply;
bool m_sourcesAvailable;
QJsonArray m_warnings;
QJsonArray m_errors;
QJsonArray m_softwareUpdates;
QJsonArray m_packageOnlyUpdates;
QJsonArray m_downgrades;
QJsonArray m_orphanedPackages;
};
} // namespace PackageManagement
#endif // PACKAGEMANAGEMENT_UPDATELOOKUP_H

155
alpm/upgradelookup.cpp Normal file
View File

@ -0,0 +1,155 @@
#include "upgradelookup.h"
#include "manager.h"
#include "alpmdatabase.h"
#include "config.h"
#include <QtConcurrent/QtConcurrent>
#include <assert.h>
using namespace std;
namespace PackageManagement {
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<void>(this))
{
connect(this, &UpgradeLookupProcess::finished, upgradeLookup, &UpgradeLookup::processFinished);
if(m_upgradeSource->requestsRequired()) {
if((m_reply = m_upgradeSource->requestPackageInfo(m_toCheck->packageNames()))) {
m_reply->setParent(this);
connect(m_reply, &PackageReply::resultsAvailable, this, &UpgradeLookupProcess::sourceReady);
return;
}
}
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<void>::finished, this, &UpgradeLookupProcess::finished);
m_watcher->setFuture(QtConcurrent::run(this, &UpgradeLookupProcess::checkUpgrades));
}
}
void UpgradeLookupProcess::checkUpgrades()
{
m_toCheck->checkForUpgrades(m_results, QList<const Repository *>() << 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<UpgradeLookupProcess *>(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

137
alpm/upgradelookup.h Normal file
View File

@ -0,0 +1,137 @@
#ifndef PACKAGEMANAGEMENT_UPDATELOOKUP_H
#define PACKAGEMANAGEMENT_UPDATELOOKUP_H
#include "package.h"
#include <QObject>
#include <QJsonObject>
#include <QJsonArray>
#include <QFutureWatcher>
namespace PackageManagement {
class Manager;
class UpgradeLookup;
class UpgradeLookupProcess;
class PackageReply;
class UpgradeResult
{
public:
UpgradeResult(const Package *package, const QString &previousVersion);
const Package *package;
QString previousVersion;
QJsonObject json() const;
};
inline UpgradeResult::UpgradeResult(const Package *package, const QString &previousVersion) :
package(package),
previousVersion(previousVersion)
{}
class UpgradeLookupResults
{
public:
UpgradeLookupResults();
/*!
* \brief Indicates that there are no upgrade sources available.
*/
bool noSources;
/*!
* \brief Packages providing a software upgrade (new version).
*/
QList<UpgradeResult> newVersions;
/*!
* \brief Package upgrades only (new release).
*/
QList<UpgradeResult> newReleases;
/*!
* \brief Downgrades (older version in sync db).
*/
QList<UpgradeResult> downgrades;
/*!
* \brief Orphaned packages (could not be found in any of the sync dbs).
*/
QSet<const Package *> orphaned;
/*!
* \brief Warnings occured when checking for updates.
*/
QStringList warnings;
/*!
* \brief Errors occured when checking for updates.
*/
QStringList errors;
};
/*!
* \brief Constructs new update lookup results.
*/
inline UpgradeLookupResults::UpgradeLookupResults() :
noSources(false)
{}
class UpgradeLookupProcess : public QObject
{
Q_OBJECT
public:
explicit UpgradeLookupProcess(UpgradeLookup *upgradeLookup, const Repository *upgradeSource);
const UpgradeLookupResults &results() const;
signals:
void finished();
private slots:
void sourceReady();
void checkUpgrades();
private:
const Repository *m_toCheck;
const Repository *m_upgradeSource;
PackageReply *m_reply;
QFutureWatcher<void> *m_watcher;
UpgradeLookupResults m_results;
};
class UpgradeLookup : public QObject
{
Q_OBJECT
friend class UpgradeLookupProcess;
public:
explicit UpgradeLookup(const Manager &manager, const QJsonObject &request, QObject *parent = nullptr);
const Repository *toCheck() const;
signals:
void resultsAvailable(const QJsonValue &what, const QJsonValue &id, const QJsonValue &value);
private slots:
void processFinished();
private:
const QJsonObject m_request;
const Repository *m_toCheck;
unsigned int m_remainingProcesses;
bool m_firstFinished;
QSet<const Package *> m_orphanedPackages;
QJsonArray m_warningsArray;
QJsonArray m_errorsArray;
QJsonArray m_softwareUpdatesArray;
QJsonArray m_packageOnlyUpdatesArray;
QJsonArray m_downgradesArray;
QJsonArray m_orphanedPackagesArray;
};
inline const Repository *UpgradeLookup::toCheck() const
{
return m_toCheck;
}
} // namespace PackageManagement
#endif // PACKAGEMANAGEMENT_UPDATELOOKUP_H

View File

@ -1,7 +1,8 @@
#include "utilities.h"
#include <QString>
#include <QJsonObject>
#include <QJsonArray>
#include <QStringList>
using namespace std;
@ -105,6 +106,102 @@ QString sigStatusString(alpm_sigstatus_t sigStatus)
}
}
/*!
* \brief Returns the string representation for the specified \a validationMethods.
*/
QJsonArray validationMethodsStrings(alpm_pkgvalidation_t validationMethods)
{
QJsonArray jsonArray;
if(validationMethods & 0x1) {
jsonArray << QStringLiteral("none");
}
if(validationMethods & 0x2) {
jsonArray << QStringLiteral("MD5");
}
if(validationMethods & 0x4) {
jsonArray << QStringLiteral("SHA256");
}
if(validationMethods & 0x8) {
jsonArray << QStringLiteral("signature");
}
if(jsonArray.empty()) {
jsonArray << QStringLiteral("unknown");
}
return jsonArray;
}
QJsonArray qjarry(StringList list)
{
QJsonArray jsonArray;
for(const char *str : list) {
jsonArray << qstr(str);
}
return jsonArray;
}
QJsonArray qjarry(DependencyList list)
{
QJsonArray jsonArray;
for(alpm_depend_t *dep : list) {
QJsonObject depObj;
depObj.insert(QStringLiteral("name"), dep->name);
depObj.insert(QStringLiteral("desc"), dep->desc);
depObj.insert(QStringLiteral("ver"), dep->version);
switch(dep->mod) {
case ALPM_DEP_MOD_ANY:
depObj.insert(QStringLiteral("mod"), QStringLiteral("any"));
break;
case ALPM_DEP_MOD_EQ:
depObj.insert(QStringLiteral("mod"), QStringLiteral("eq"));
break;
case ALPM_DEP_MOD_GE:
depObj.insert(QStringLiteral("mod"), QStringLiteral("ge"));
break;
case ALPM_DEP_MOD_LE:
depObj.insert(QStringLiteral("mod"), QStringLiteral("le"));
break;
case ALPM_DEP_MOD_GT:
depObj.insert(QStringLiteral("mod"), QStringLiteral("gt"));
break;
case ALPM_DEP_MOD_LT:
depObj.insert(QStringLiteral("mod"), QStringLiteral("lt"));
break;
}
jsonArray << depObj;
}
return jsonArray;
}
QJsonArray qjarry(_alpm_pkgvalidation_t validation)
{
QJsonArray jsonArray;
if(validation & 0x1) {
jsonArray << QStringLiteral("none");
}
if(validation & 0x2) {
jsonArray << QStringLiteral("MD5");
}
if(validation & 0x4) {
jsonArray << QStringLiteral("SHA256");
}
if(validation & 0x8) {
jsonArray << QStringLiteral("signature");
}
if(jsonArray.empty()) {
jsonArray << QStringLiteral("unknown");
}
return jsonArray;
}
QStringList qstrlist(StringList list)
{
QStringList strings;
for(const auto *str : list) {
strings << qstr(str);
}
return strings;
}
}
} // namespace Alpm

View File

@ -3,15 +3,12 @@
#include "list.h"
#include <QtGlobal>
#include <QString>
#include <string>
#include <list>
QT_BEGIN_NAMESPACE
class QString;
class QJsonArray;
QT_END_NAMESPACE
QT_FORWARD_DECLARE_CLASS(QJsonArray)
namespace PackageManagement {
@ -22,6 +19,22 @@ std::list<std::string> getNames(DependencyList dependencyList);
QJsonArray sigLevelStrings(alpm_siglevel_t sigLevel);
QJsonArray usageStrings(alpm_db_usage_t usage);
QString sigStatusString(alpm_sigstatus_t sigStatus);
QJsonArray validationMethodsStrings(alpm_pkgvalidation_t validationMethods);
QJsonArray qjarry(StringList list);
QJsonArray qjarry(DependencyList list);
QJsonArray qjarry(_alpm_pkgvalidation_t validation);
QStringList qstrlist(StringList list);
inline QString qstr(const char *str)
{
return QString::fromLocal8Bit(str);
}
inline QString qstr(const std::string &str)
{
return QString::fromLocal8Bit(str.data());
}
}

View File

@ -8,9 +8,6 @@ RCC_DIR = ./res
# compiler flags
QMAKE_CXXFLAGS += -std=c++11
QMAKE_LFLAGS += -std=c++11
unix {
QMAKE_LFLAGS += "-Wl,--rpath=./"
}
# prefix
targetprefix = $$(TARGET_PREFIX)
message("Using target prefix \"$${targetprefix}\".")

View File

@ -3,6 +3,7 @@
#include "alpm/config.h"
#include "alpm/resolvebuildorder.h"
#include "alpm/mingwbundle.h"
#include "network/server.h"
#include <c++utilities/application/argumentparser.h>
@ -39,6 +40,7 @@ int main(int argc, char *argv[])
if(find_if(parser.mainArguments().cbegin(), parser.mainArguments().cend(), [&configArgs] (const Argument *arg) {
return arg != &configArgs.helpArg && arg->isPresent();
}) != parser.mainArguments().cend()) {
cerr << "Loading databases ..." << endl;
// create app
QCoreApplication application(argc, argv);
// setup ALPM
@ -61,8 +63,10 @@ int main(int argc, char *argv[])
}
cout << endl;
} else if(configArgs.mingwBundleArg.isPresent()) {
MingwBundle bundle(manager, configArgs.mingwBundleArg.values());
bundle.createBundle(configArgs.outputFileArg.values().front());
MingwBundle bundle(manager, configArgs.mingwBundleArg.values(), configArgs.iconThemesArg.values());
bundle.createBundle(configArgs.targetDirArg.isPresent() ? configArgs.targetDirArg.values().front() : string("."),
configArgs.targetNameArg.values().front(),
configArgs.targetFormatArg.isPresent() ? configArgs.targetFormatArg.values().front() : string("zip"));
}
} else {
cout << "No command line arguments specified. See --help for available commands." << endl;

View File

@ -1,137 +0,0 @@
#include "aurquery.h"
#include "alpm/package.h"
#include <QUrlQuery>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <iostream>
using namespace std;
namespace PackageManagement {
QUrl AurQuery::m_aurRpcUrl = QUrl(QStringLiteral("https://aur.archlinux.org/rpc.php"));
QUrl AurQuery::m_aurPkgbuildUrl = QUrl(QStringLiteral("https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD"));
const char *requestTypeProp = "type";
const QString rpcRequestTypeKey(QStringLiteral("type"));
const QString rpcRequestTypeSuggest(QStringLiteral("suggest"));
const QString rpcRequestTypeMultiInfo(QStringLiteral("multiinfo"));
const QString rpcArgKey(QStringLiteral("arg"));
const QString rpcArgArray(QStringLiteral("arg[]"));
const QString pkgbuildRequestType(QString("pkgbuild"));
AurQuery::AurQuery(QNetworkAccessManager &networkAccessManager, QObject *parent) :
QObject(parent),
m_networkAccessManager(networkAccessManager)
{}
QNetworkReply *AurQuery::requestSuggestions(const QString &phrase) const
{
auto url = m_aurRpcUrl;
QUrlQuery query;
query.addQueryItem(rpcRequestTypeKey, rpcRequestTypeSuggest);
query.addQueryItem(rpcArgKey, phrase);
url.setQuery(query);
auto *reply = m_networkAccessManager.get(QNetworkRequest(url));
reply->setProperty(requestTypeProp, rpcRequestTypeSuggest);
connect(reply, &QNetworkReply::finished, this, &AurQuery::dataReceived);
return reply;
}
/*!
* \brief Requests package information for the specified packages from the AUR.
* \returns Returns the QNetworkReply used for the request.
* \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.
*/
QNetworkReply *AurQuery::requestPackageInfo(const QStringList &packageNames, bool forceUpdate) const
{
QUrlQuery query;
for(const auto &packageName : packageNames) {
if(forceUpdate || !m_packages.count(packageName)) {
query.addQueryItem(rpcArgArray, packageName);
}
}
if(query.isEmpty()) {
return nullptr;
} else {
auto url = m_aurRpcUrl;
query.addQueryItem(rpcRequestTypeKey, rpcRequestTypeMultiInfo);
url.setQuery(query);
auto *reply = m_networkAccessManager.get(QNetworkRequest(url));
reply->setProperty(requestTypeProp, rpcRequestTypeMultiInfo);
connect(reply, &QNetworkReply::finished, this, &AurQuery::dataReceived);
return reply;
}
}
QNetworkReply *AurQuery::requestFullPackageInfo(const QString &package, bool forceUpdate) const
{
try {
const auto &pkg = m_packages.at(package);
if(pkg.hasFullInfo() && !forceUpdate) {
return nullptr;
}
} catch(const out_of_range &) {
}
auto url = m_aurPkgbuildUrl;
QUrlQuery query;
query.addQueryItem(QStringLiteral("h"), package);
url.setQuery(query);
auto *reply = m_networkAccessManager.get(QNetworkRequest(url));
reply->setProperty(requestTypeProp, pkgbuildRequestType);
connect(reply, &QNetworkReply::finished, this, &AurQuery::dataReceived);
return reply;
}
void AurQuery::dataReceived()
{
if(auto *reply = qobject_cast<QNetworkReply *>(sender())) {
if(reply->error() == QNetworkReply::NoError) {
QJsonParseError error;
QByteArray data = reply->readAll();
cerr << "AUR reply: " << data.data() << endl;
const QJsonDocument doc = QJsonDocument::fromJson(data, &error);
//const QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &error);
if(error.error == QJsonParseError::NoError) {
const QString requestType = reply->property(requestTypeProp).toString();
if(requestType == rpcRequestTypeSuggest) {
emit suggestionsAvailable(reply, doc.array());
} else if(requestType == rpcRequestTypeMultiInfo) {
processPackageInfo(reply, doc.object().value(QStringLiteral("results")).toArray());
} else {
cerr << "Error: Reply has invalid type. (should never happen)" << endl;
}
} else {
cerr << "Error: Unable to parse JSON received from AUR: " << error.errorString().toLocal8Bit().data() << " at character " << error.offset << endl;
}
} else {
cerr << "Error: Unable to request data from AUR: " << reply->errorString().toLocal8Bit().data() << endl;
}
}
}
void AurQuery::processPackageInfo(const QNetworkReply *reply, const QJsonArray &results)
{
for(const auto &result : results) {
AurPackage package(result);
if(!package.name().isEmpty()) {
m_packages[package.name()] = move(package);
}
}
emit packageInfoAvailable(reply);
}
} // namespace Alpm

View File

@ -1,71 +0,0 @@
#ifndef ALPM_AURQUERY_H
#define ALPM_AURQUERY_H
#include "alpm/package.h"
#include <QUrl>
#include <QObject>
#include <vector>
QT_FORWARD_DECLARE_CLASS(QNetworkAccessManager)
QT_FORWARD_DECLARE_CLASS(QNetworkReply)
namespace PackageManagement {
class AurQuery : public QObject
{
Q_OBJECT
public:
AurQuery(QNetworkAccessManager &networkAccessManager, QObject *parent = nullptr);
static const QUrl aurRpcUrl();
static void setAurRpcUrl(const QUrl &aurRpcUrl);
QNetworkReply *requestSuggestions(const QString &phrase) const;
QNetworkReply *requestPackageInfo(const QStringList &packageNames, bool forceUpdate = false) const;
QNetworkReply *requestFullPackageInfo(const QString &package, bool forceUpdate = false) const;
const std::map<QString, AurPackage> &packages() const;
std::map<QString, AurPackage> &packages();
signals:
void suggestionsAvailable(const QNetworkReply *reply, const QJsonArray &suggestions);
void packageInfoAvailable(const QNetworkReply *reply);
private slots:
void dataReceived();
private:
void processPackageInfo(const QNetworkReply *reply, const QJsonArray &results);
QNetworkAccessManager &m_networkAccessManager;
std::map<QString, AurPackage> m_packages;
static QUrl m_aurRpcUrl;
static QUrl m_aurPkgbuildUrl;
};
inline const QUrl AurQuery::aurRpcUrl()
{
return m_aurRpcUrl;
}
inline void AurQuery::setAurRpcUrl(const QUrl &aur4Url)
{
m_aurRpcUrl = aur4Url;
}
inline const std::map<QString, AurPackage> &AurQuery::packages() const
{
return m_packages;
}
inline std::map<QString, AurPackage> &AurQuery::packages()
{
return m_packages;
}
} // namespace Alpm
#endif // ALPM_AURQUERY_H

View File

@ -1,19 +1,18 @@
#include "connection.h"
#include "alpm/manager.h"
#include "alpm/upgradelookup.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QWebSocket>
#include <functional>
using namespace std;
using namespace PackageManagement;
namespace Network {
Connection::Connection(const PackageManagement::Manager &alpmManager, QWebSocket *socket, QObject *parent) :
Connection::Connection(const Manager &alpmManager, QWebSocket *socket, QObject *parent) :
QObject(parent),
m_socket(socket),
m_alpmManager(alpmManager),
@ -39,7 +38,7 @@ void Connection::sendError(const QString &msg)
sendJson(response);
}
void Connection::sendResult(const QString &what, const QJsonValue &id, const QJsonValue &value)
void Connection::sendResult(const QJsonValue &what, const QJsonValue &id, const QJsonValue &value)
{
QJsonObject response;
response.insert(QStringLiteral("class"), QStringLiteral("results"));
@ -51,7 +50,7 @@ void Connection::sendResult(const QString &what, const QJsonValue &id, const QJs
sendJson(response);
}
void Connection::sendResults(const QString &what, const QJsonValue &id, const QJsonArray &values)
void Connection::sendResults(const QJsonValue &what, const QJsonValue &id, const QJsonArray &values)
{
QJsonObject response;
response.insert(QStringLiteral("class"), QStringLiteral("results"));
@ -71,18 +70,14 @@ void Connection::handleQuery(const QJsonObject &obj)
m_repoInfoUpdatesRequested = obj.value(QStringLiteral("updates")).toBool(m_repoInfoUpdatesRequested);
sendResults(what, id, m_alpmManager.basicRepoInfo());
} else if(what == QLatin1String("basicpkginfo")) {
sendResults(what, id, m_alpmManager.packageInfo(obj.value("sel").toArray(), false));
sendResults(what, id, m_alpmManager.packageInfo(obj.value("sel").toObject(), false));
} else if(what == QLatin1String("fullpkginfo")) {
sendResults(what, id, m_alpmManager.packageInfo(obj.value("sel").toArray(), true));
sendResults(what, id, m_alpmManager.packageInfo(obj.value("sel").toObject(), true));
} else if(what == QLatin1String("groupinfo")) {
m_groupInfoUpdatesRequested = obj.value(QStringLiteral("updates")).toBool(m_groupInfoUpdatesRequested);
sendResults(what, id, m_alpmManager.groupInfo());
} else if(what == QLatin1String("checkforupdates")) {
//sendResult(what, id, m_alpmManager.invokeUpgradeLookup(obj));
m_alpmManager.invokeUpgradeLookup(obj, bind(&Connection::sendResult, this, what, id, placeholders::_1));
//m_alpmManager.checkForUpgrades(obj, [this] (const QJsonObject &results) {
// sendResult(what, id, results);
//};
connect(new UpgradeLookup(m_alpmManager, obj), &UpgradeLookup::resultsAvailable, this, &Connection::sendResult);
} else if(what == QLatin1String("ping")) {
sendResult(what, id, QStringLiteral("pong"));
} else {

View File

@ -24,12 +24,12 @@ private slots:
void processTextMessage(const QString &message);
void processBinaryMessage(const QByteArray &message);
void socketDisconnected();
void sendResult(const QJsonValue &what, const QJsonValue &id, const QJsonValue &value);
void sendResults(const QJsonValue &what, const QJsonValue &id, const QJsonArray &values);
private:
void sendJson(const QJsonObject &obj);
void sendError(const QString &msg);
void sendResult(const QString &what, const QJsonValue &id, const QJsonValue &value);
void sendResults(const QString &what, const QJsonValue &id, const QJsonArray &values);
void handleQuery(const QJsonObject &obj);
QWebSocket *m_socket;

145
network/userrepository.cpp Normal file
View File

@ -0,0 +1,145 @@
#include "userrepository.h"
#include "alpm/aurpackage.h"
#include <c++utilities/misc/memory.h>
#include <QStringBuilder>
#include <QUrlQuery>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
using namespace std;
namespace PackageManagement {
const char *requestTypeProp = "type";
const QString rpcRequestTypeKey(QStringLiteral("type"));
const QString rpcRequestTypeSuggest(QStringLiteral("suggest"));
const QString rpcRequestTypeMultiInfo(QStringLiteral("multiinfo"));
const QString rpcArgKey(QStringLiteral("arg"));
const QString rpcArgArray(QStringLiteral("arg[]"));
const QString pkgbuildRequestType(QString("pkgbuild"));
QUrl UserRepository::m_aurRpcUrl = QUrl(QStringLiteral("https://aur.archlinux.org/rpc.php"));
QUrl UserRepository::m_aurPkgbuildUrl = QUrl(QStringLiteral("https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD"));
QUrl UserRepository::m_aurSrcInfoUrl = QUrl(QStringLiteral("https://aur.archlinux.org/cgit/aur.git/plain/.SRCINFO"));
AurPackageReply::AurPackageReply(QNetworkReply *networkReply, UserRepository *userRepo) :
PackageReply(networkReply, userRepo->packages()),
m_userRepo(userRepo)
{}
void AurPackageReply::processData()
{
if(m_networkReply->error() == QNetworkReply::NoError) {
QJsonParseError error;
//QByteArray data = m_networkReply->readAll();
//cerr << "AUR reply: " << data.data() << endl;
//const QJsonDocument doc = QJsonDocument::fromJson(data, &error);
const QJsonDocument doc = QJsonDocument::fromJson(m_networkReply->readAll(), &error);
if(error.error == QJsonParseError::NoError) {
for(const auto &result : doc.object().value(QStringLiteral("results")).toArray()) {
auto package = make_unique<AurPackage>(result, m_userRepo);
if(!package->name().isEmpty()) {
m_packages[package->name()] = move(package);
}
}
} else {
m_error = QStringLiteral("Error: Unable to parse JSON received from AUR: ") % error.errorString() % QStringLiteral(" at character ") % QString::number(error.offset);
}
} else {
m_error = QStringLiteral("Error: Unable to request data from AUR: ") + m_networkReply->errorString();
}
emit resultsAvailable();
}
AurSuggestionsReply::AurSuggestionsReply(QNetworkReply *networkReply) :
SuggestionsReply(networkReply)
{}
void AurSuggestionsReply::processData()
{
if(m_networkReply->error() == QNetworkReply::NoError) {
QJsonParseError error;
//QByteArray data = m_networkReply->readAll();
//cerr << "AUR reply: " << data.data() << endl;
//const QJsonDocument doc = QJsonDocument::fromJson(data, &error);
const QJsonDocument doc = QJsonDocument::fromJson(m_networkReply->readAll(), &error);
if(error.error == QJsonParseError::NoError) {
m_suggestions = doc.array();
} else {
m_error = QStringLiteral("Error: Unable to parse JSON received from AUR: ") % error.errorString() % QStringLiteral(" at character ") % QString::number(error.offset);
}
} else {
m_error = QStringLiteral("Error: Unable to request data from AUR: ") + m_networkReply->errorString();
}
emit resultsAvailable();
}
UserRepository::UserRepository(QNetworkAccessManager &networkAccessManager, QObject *parent) :
Repository(QStringLiteral("AUR"), parent),
m_networkAccessManager(networkAccessManager)
{
m_description = QStringLiteral("Arch User Repository");
}
RepositoryType UserRepository::type() const
{
return RepositoryType::UserRepository;
}
bool UserRepository::requestsRequired() const
{
return true;
}
AurSuggestionsReply *UserRepository::requestSuggestions(const QString &phrase) const
{
auto url = m_aurRpcUrl;
QUrlQuery query;
query.addQueryItem(rpcRequestTypeKey, rpcRequestTypeSuggest);
query.addQueryItem(rpcArgKey, phrase);
url.setQuery(query);
return new AurSuggestionsReply(m_networkAccessManager.get(QNetworkRequest(url)));
}
AurPackageReply *UserRepository::requestPackageInfo(const QStringList &packageNames, bool forceUpdate) const
{
QUrlQuery query;
for(const auto &packageName : packageNames) {
if(forceUpdate || !m_packages.count(packageName)) {
query.addQueryItem(rpcArgArray, packageName);
}
}
if(query.isEmpty()) {
return nullptr;
} else {
auto url = m_aurRpcUrl;
query.addQueryItem(rpcRequestTypeKey, rpcRequestTypeMultiInfo);
url.setQuery(query);
return new AurPackageReply(m_networkAccessManager.get(QNetworkRequest(url)), const_cast<UserRepository *>(this));
}
}
AurPackageReply *UserRepository::requestFullPackageInfo(const QString &package, bool forceUpdate) const
{
try {
const auto &pkg = m_packages.at(package);
if(pkg->hasGeneralInfo() && !forceUpdate) {
return nullptr;
}
} catch(const out_of_range &) {
}
auto url = m_aurPkgbuildUrl;
QUrlQuery query;
query.addQueryItem(QStringLiteral("h"), package);
url.setQuery(query);
return new AurPackageReply(m_networkAccessManager.get(QNetworkRequest(url)), const_cast<UserRepository *>(this));
}
} // namespace Alpm

79
network/userrepository.h Normal file
View File

@ -0,0 +1,79 @@
#ifndef ALPM_USER_REPOSITORY_H
#define ALPM_USER_REPOSITORY_H
#include "alpm/package.h"
#include "alpm/repository.h"
#include <QUrl>
#include <QObject>
#include <vector>
#include <memory>
QT_FORWARD_DECLARE_CLASS(QNetworkAccessManager)
QT_FORWARD_DECLARE_CLASS(QNetworkReply)
namespace PackageManagement {
class UserRepository;
class AurPackageReply : public PackageReply
{
Q_OBJECT
public:
AurPackageReply(QNetworkReply *networkReply, UserRepository *userRepo);
const std::map<QString, std::unique_ptr<Package> > &packages() const;
private slots:
void processData();
private:
UserRepository *m_userRepo;
};
class AurSuggestionsReply : public SuggestionsReply
{
Q_OBJECT
public:
AurSuggestionsReply(QNetworkReply *networkReply);
private slots:
void processData();
};
class UserRepository : public Repository
{
Q_OBJECT
public:
UserRepository(QNetworkAccessManager &networkAccessManager, QObject *parent = nullptr);
RepositoryType type() const;
static const QUrl aurRpcUrl();
static void setAurRpcUrl(const QUrl &aurRpcUrl);
bool requestsRequired() const;
AurSuggestionsReply *requestSuggestions(const QString &phrase) const;
AurPackageReply *requestPackageInfo(const QStringList &packageNames, bool forceUpdate = false) const;
AurPackageReply *requestFullPackageInfo(const QString &package, bool forceUpdate = false) const;
private:
QNetworkAccessManager &m_networkAccessManager;
static QUrl m_aurRpcUrl;
static QUrl m_aurPkgbuildUrl;
static QUrl m_aurSrcInfoUrl;
};
inline const QUrl UserRepository::aurRpcUrl()
{
return m_aurRpcUrl;
}
inline void UserRepository::setAurRpcUrl(const QUrl &aur4Url)
{
m_aurRpcUrl = aur4Url;
}
} // namespace Alpm
#endif // ALPM_USER_REPOSITORY_H

View File

@ -1,4 +1,7 @@
projectname = repoindex
appname = "Repository Index"
appauthor = Martchus
appurl = "https://github.com/$${appauthor}/$${projectname}"
VERSION = 1.0.0
# include ../../common.pri when building as part of a subdirs project; otherwise include general.pri
@ -18,30 +21,36 @@ SOURCES += main.cpp \
alpm/manager.cpp \
alpm/package.cpp \
alpm/utilities.cpp \
alpm/database.cpp \
network/server.cpp \
network/connection.cpp \
alpm/group.cpp \
alpm/config.cpp \
network/aurquery.cpp \
alpm/updatelookup.cpp \
alpm/resolvebuildorder.cpp \
alpm/mingwbundle.cpp
alpm/mingwbundle.cpp \
network/userrepository.cpp \
alpm/alpmpackage.cpp \
alpm/aurpackage.cpp \
alpm/alpmdatabase.cpp \
alpm/repository.cpp \
alpm/upgradelookup.cpp
HEADERS += \
alpm/manager.h \
alpm/package.h \
alpm/list.h \
alpm/utilities.h \
alpm/database.h \
network/server.h \
network/connection.h \
alpm/group.h \
alpm/config.h \
network/aurquery.h \
alpm/updatelookup.h \
alpm/resolvebuildorder.h \
alpm/mingwbundle.h
alpm/mingwbundle.h \
network/userrepository.h \
alpm/alpmpackage.h \
alpm/aurpackage.h \
alpm/alpmdatabase.h \
alpm/repository.h \
alpm/upgradelookup.h
DISTFILES += \
README.md \
@ -60,13 +69,18 @@ DISTFILES += \
web/css/dashboard.css \
repoindex.conf.js
# defines
CONFIG(release, debug|release) {
DEFINES += NDEBUG
}
# libs and includepath
CONFIG(debug, debug|release) {
LIBS += -L../../ -lc++utilitiesd -lalpm -lKF5Archive
LIBS += -lc++utilitiesd
} else {
LIBS += -L../../ -lc++utilities -lalpm -lKF5Archive
LIBS += -lc++utilities
}
INCLUDEPATH += ../
LIBS += -lalpm -lKF5Archive
# installs
target.path = $$(INSTALL_ROOT)/bin

View File

@ -232,11 +232,9 @@
<tr><th>Package count</th><td id="repo_pkgcount"></td></tr>
<tr><th>Usage</th><td id="repo_usage"></td></tr>
<tr><th>Signature level</th><td id="repo_siglevel"></td></tr>
<tr><th>Source-only</th><td id="repo_source_only"></td></tr>
<tr><th>Upgrade sources</th><td id="repo_upgrade_sources"></td></tr>
<tr>
<th>Upgrades</th>
<td><span id="repo_checkforupdates"></span></td>
</tr>
<tr><th>Upgrades</th><td><span id="repo_checkforupdates"></span></td></tr>
</tbody>
</table>
</div>

View File

@ -248,10 +248,10 @@
repoMgr.removeEntries();
pkgMgr.removeEntries();
for(var i1 = 0; i1 < values.length; ++i1) {
repoMgr.addEntry(values[i1]);
var packages = values[i1].packages;
var repoEntry = repoMgr.addEntry(values[i1]);
var packages = repoEntry.info.packages;
for(var i2 = 0; i2 < packages.length; ++i2) {
pkgMgr.addEntry(values[i1].name, packages[i2]);
pkgMgr.addEntry(repoEntry, packages[i2]);
}
}
this.hasBasicRepoInfo = true;

View File

@ -180,6 +180,24 @@
}
};
this.entryByName = function(entryName) {
if(this.customSelection) {
for(var i = 0; i < this.customSelection.length; ++i) {
var entry = this.customSelection[i];
if(entry.info && entry.info.name === entryName) {
return entry;
}
}
} else {
for(var i = 0; i < this.entries.length; ++i) {
var entry = this.entries[i];
if(entry.info && entry.info.name === entryName) {
return entry;
}
}
}
};
// function called by the ALPM client when requested data is available
this.useRequestedData = function() {
this.invalidate();

View File

@ -8,7 +8,8 @@
var PackageEntry = {};
PackageEntry.prototype = new repoindex.Entry();
PackageEntry.prototype.constructor = PackageEntry;
PackageEntry = function(packageInfo, color) {
PackageEntry = function(repoEntry, packageInfo, color) {
this.repoEntry = repoEntry; // might be undefined
repoindex.Entry.prototype.constructor.call(this, packageInfo);
// init row element
@ -20,7 +21,8 @@
};
this.initTableRow = function() {
var values = [this.info.arch, this.info.repo, this.info.name, this.info.ver, this.info.desc, this.info.bdate, ""];
var srcOnly = this.repoEntry && this.repoEntry.info.srcOnly;
var values = [srcOnly ? "n/a" : this.info.arch, this.info.repo, this.info.name, this.info.ver, this.info.desc, srcOnly ? "n/a" : this.info.bdate, this.info.flagdate];
for(var i = 0; i < 7; ++i) {
this.rowElement.addCell(repoindex.makeStr(values[i]));
}
@ -35,6 +37,7 @@
if(info.ver) this.info.ver = info.ver;
if(info.desc) this.info.desc = info.desc;
if(info.bdate) this.info.bdate = info.bdate;
if(info.flagdate) this.info.flagdate = info.flagdate;
this.info.basic = true;
if(!noUpdate) {
this.updateTableRow();
@ -80,22 +83,19 @@
this.getContainerQuantity = repoindex.entryManagerGetRepoQuantity;
this.createCustomEntry = function(color) {
return new PackageEntry({}, color);
return new PackageEntry(undefined, {}, color);
};
this.addEntry = function(repoName, packageName) {
this.addEntry = function(repoEntry, packageName) {
var packageInfo = {
index: this.entries.length,
arch: undefined,
repo: repoName,
repo: repoEntry.info.name,
name: packageName,
version: undefined,
desc: undefined,
builddate: undefined,
flagdate: undefined,
received: false
};
this.entries.push(new PackageEntry(packageInfo));
var entry = new PackageEntry(repoEntry, packageInfo);
this.entries.push(entry);
return entry;
};
// handle a page selection
@ -106,15 +106,22 @@
// if there is no page because there are no package entries, pageElement is null
if(pageElement) {
// show elements of selected page
var packageSelection = []; // package selection for requesting package infos
var packageSelection = {}; // package selection for requesting package infos
var entriesRequired = false;
pageElement.forRange(function(i) {
var entry = mgr.filteredEntries[i];
entry.add(mgr.entryContainer);
if(!entry.info.basic) {
packageSelection.push({index: entry.info.index, repo: entry.info.repo, name: entry.info.name});
var repoArray = packageSelection[entry.info.repo];
if(!Array.isArray(repoArray)) {
packageSelection[entry.info.repo] = [{index: entry.info.index, name: entry.info.name}];
} else {
repoArray.push({index: entry.info.index, name: entry.info.name});
}
entriesRequired = true;
}
}, mgr.filteredEntries.length);
if(packageSelection.length > 0) {
if(entriesRequired) {
var pkgEntries = repoindex.pageManager.packageManager.relevantEntries();
var useBasicPackageInfo = function(values) {
for(var i = 0; i < values.length; ++i) {
@ -228,7 +235,9 @@
};
if(!i.full) {
// don't have the full package info yet -> request full package info
repoindex.alpmClient.requestFullPackagesInfo([{index: entryIndex, repo: i.repo, name: i.name}], useFullPackageInfo);
var packageSelection = {};
packageSelection[i.repo] = [{index: entryIndex, name: i.name}];
repoindex.alpmClient.requestFullPackagesInfo(packageSelection, useFullPackageInfo);
}
// set currentInfo (the pageManager needs this value to update the hash)
this.currentInfo = i;
@ -254,7 +263,10 @@
showEntry();
} else {
// no -> request full info, use callback to show entry when info becomes available
repoindex.alpmClient.requestFullPackagesInfo([{index: i.index, repo: i.repo, name: i.name}], showEntry());
//repoindex.alpmClient.requestFullPackagesInfo([{index: i.index, repo: i.repo, name: i.name}], showEntry());
var packageSelection = {};
packageSelection[i.repo] = [{index: entryIndex, name: i.name}];
repoindex.alpmClient.requestFullPackagesInfo(packageSelection, showEntry);
}
} else {
// no -> show error

View File

@ -4,6 +4,9 @@
RepoEntry.prototype = new repoindex.Entry();
RepoEntry.prototype.constructor = RepoEntry;
RepoEntry = function(repoInfo, enabled) {
if(enabled === undefined) {
enabled = !repoInfo.requestRequired;
}
repoindex.Entry.prototype.constructor.call(this, repoInfo, enabled);
this.info.currentServer = 0;
@ -40,12 +43,14 @@
this.link.setAttribute("data-placement", "bottom");
$(this.link).tooltip();
// create badge with package count
var span = document.createElement("span");
span.className = "badge";
span.appendChild(document.createTextNode(repoInfo.packages.length));
this.link.appendChild(document.createTextNode(" "));
this.link.appendChild(span);
if(!repoInfo.requestRequired) {
// create badge with package count
var span = document.createElement("span");
span.className = "badge";
span.appendChild(document.createTextNode(repoInfo.packages.length));
this.link.appendChild(document.createTextNode(" "));
this.link.appendChild(span);
}
this.link.add = function() {
repoindex.pageManager.repoManager.buttonContainer.appendChild(this);
@ -103,12 +108,13 @@
// provide a function to add repo entries
this.addEntry = function(repoInfo) {
var entry = new RepoEntry(repoInfo, true);
var entry = new RepoEntry(repoInfo);
entry.statusChanged = this.applyRepoStatusChange;
entry.pageManager = this;
entry.repoEntryManager = this;
entry.info.index = this.entries.length;
this.entries.push(entry);
return entry;
};
this.baseRemoveEntries = this.removeEntries;
@ -172,9 +178,10 @@
var i = entry.info;
repoindex.setText("repo_name", i.name);
repoindex.setText("repo_desc", i.desc);
repoindex.setText("repo_pkgcount", i.packages.length);
repoindex.setText("repo_pkgcount", i.requestRequired ? "unknown" : i.packages.length);
repoindex.setText("repo_usage", repoindex.makeArray(i.usage, ", "));
repoindex.setText("repo_siglevel", repoindex.makeArray(i.sigLevel, ", "));
repoindex.setText("repo_source_only", repoindex.makeBool(i.srcOnly));
repoindex.setText("repo_upgrade_sources", repoindex.makeArray(i.upgradeSources, ", "));
var invokeUpdateLookupParams = {repo: i.name, invoke: "updatelookup"};
repoindex.setDownloadButton("repo_checkforupdates", "check for updates", repoindex.makeHash(repoindex.Pages.Repositories, invokeUpdateLookupParams, true), function() {
@ -238,6 +245,7 @@
}
];
var pkgMgr = repoindex.pageManager.packageManager;
var repoMgr = repoindex.pageManager.repoManager;
for(var i1 = 0; i1 < updates.length; ++i1) {
for(var i2 = 0; i2 < updates[i1].entries.length; ++i2) {
var newEntry = pkgMgr.createCustomEntry(updates[i1].color);
@ -247,6 +255,10 @@
if(updates[i1].entries[i2].prevVersion) {
newEntry.info.ver = updates[i1].entries[i2].prevVersion + " → " + (newEntry.info.ver ? newEntry.info.ver : "?");
}
// find associated repo entry
if((newEntry.repoEntry = repoMgr.entryByName(newEntry.info.repo))) {
newEntry.repoEntry.updateEnabled(true); // ensure repo is enabled
}
newEntry.updateTableRow();
} else {
newEntry.applyBasicInfo(updates[i1].entries[i2]);
@ -276,14 +288,6 @@
repoindex.pageManager.setPage(repoindex.Pages.Packages);
}
};
// determine sync databases (this is done by the server now)
//var syncDbNames = [];
//var repoEntries = repoindex.pageManager.repoManager.entries;
//for(var index = 0; index < repoEntries.length; ++index) {
// if(repoEntries[index].info.name !== repo) {
// syncDbNames.push(repoEntries[index].info.name);
// }
//}
repoindex.alpmClient.checkForUpdates(repo, null, showUpdates);
};
// basic repo info available?

View File

@ -18,13 +18,18 @@
</p>
<script type="text/javascript">
if(true) {
var test = "asdf";
var testobj = {};
var testarray = testobj["attr"];
if(!Array.isArray(testarray)) {
testobj["attr"] = testarray = [];
}
testarray.push("123");
testarray.push("456");
for(var i = 0; i < testobj["attr"].length; ++i) {
window.alert(testobj["attr"][i]);
}
var func = function() {
window.alert(test);
};
func();
var debugTextArea = document.getElementById("debugTextArea");
function debug(message) {