caching is now implemented, overall improvements
This commit is contained in:
parent
98e565b8c3
commit
6d06663791
|
@ -41,6 +41,7 @@ public:
|
|||
}
|
||||
m_db->packages().emplace(res->name(), move(res));
|
||||
}
|
||||
|
||||
private:
|
||||
AlpmDatabase *m_db;
|
||||
QMutex *m_mutex;
|
||||
|
@ -89,7 +90,6 @@ PackageLoader *AlpmDatabase::init()
|
|||
m_serverUrls << qstr(str);
|
||||
}
|
||||
m_sigLevel = alpm_db_get_siglevel(m_ptr);
|
||||
|
||||
return new PackageLoader(this);
|
||||
}
|
||||
|
||||
|
@ -109,6 +109,7 @@ PackageDetailAvailability AlpmDatabase::requestsRequired(PackageDetail packageDe
|
|||
case PackageDetail::Basics:
|
||||
case PackageDetail::Dependencies:
|
||||
case PackageDetail::PackageInfo:
|
||||
case PackageDetail::AllAvailable:
|
||||
return PackageDetailAvailability::Immediately;
|
||||
default:
|
||||
return PackageDetailAvailability::Never;
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace ChronoUtilities;
|
||||
|
||||
namespace RepoIndex {
|
||||
|
@ -54,11 +56,11 @@ AlpmPackage::AlpmPackage(alpm_pkg_t *package, AlpmDatabase *source) :
|
|||
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);
|
||||
//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));
|
||||
|
|
|
@ -37,5 +37,13 @@ AurPackage::AurPackage(const QJsonValue &aurJsonValue, UserRepository *source) :
|
|||
m_tarUrl = obj.value(QStringLiteral("URLPath")).toString();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates a new, empty instance.
|
||||
* \remarks The only purpose of this c'tor is to use it with restoreFromCacheStream().
|
||||
*/
|
||||
AurPackage::AurPackage(UserRepository *source) :
|
||||
Package(QString(), source)
|
||||
{}
|
||||
|
||||
} // namespace PackageManagement
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ class AurPackage : public Package
|
|||
{
|
||||
public:
|
||||
AurPackage(const QJsonValue &aurJsonValue, UserRepository *source);
|
||||
AurPackage(UserRepository *source);
|
||||
};
|
||||
|
||||
} // namespace PackageManagement
|
||||
|
|
|
@ -113,7 +113,7 @@ ConfigArgs::ConfigArgs(ArgumentParser &parser) :
|
|||
shSyntaxArg.setCombinable(true);
|
||||
repoArg.setRequiredValueCount(1);
|
||||
repoArg.setValueNames({"repo name"});
|
||||
serverArg.setSecondaryArguments({&rootdirArg, &dbpathArg, &pacmanConfArg, &certFileArg, &keyFileArg, &websocketAddrArg, &websocketPortArg, &insecureArg, &aurArg});
|
||||
serverArg.setSecondaryArguments({&rootdirArg, &dbpathArg, &pacmanConfArg, &certFileArg, &keyFileArg, &websocketAddrArg, &websocketPortArg, &insecureArg, &aurArg, &shSyntaxArg});
|
||||
upgradeLookupArg.setSecondaryArguments({&shSyntaxArg});
|
||||
buildOrderArg.setSecondaryArguments({&aurArg, &verboseArg, &shSyntaxArg});
|
||||
mingwBundleArg.setSecondaryArguments({&targetDirArg, &targetNameArg, &targetFormatArg, &iconThemesArg});
|
||||
|
@ -160,7 +160,20 @@ inline void assign(quint16 &num, const QJsonValue &val)
|
|||
inline void assign(QHostAddress &addr, const QString &val)
|
||||
{
|
||||
if(!val.isEmpty() && !addr.setAddress(val)) {
|
||||
cerr << shchar << "Error: Unable to parse the specified host address \"" << val.toStdString() << "\"." << endl;
|
||||
// checking some special values might be useful
|
||||
if(val == QLatin1String("localhost")) {
|
||||
addr = QHostAddress::LocalHost;
|
||||
} else if(val == QLatin1String("localhost-IPv6")) {
|
||||
addr = QHostAddress::LocalHostIPv6;
|
||||
} else if(val == QLatin1String("any-IPv4")) {
|
||||
addr = QHostAddress::AnyIPv4;
|
||||
} else if(val == QLatin1String("any-IPv6")) {
|
||||
addr = QHostAddress::AnyIPv6;
|
||||
} else if(val == QLatin1String("any")) {
|
||||
addr = QHostAddress::Any;
|
||||
} else {
|
||||
cerr << shchar << "Error: Unable to parse the specified host address \"" << val.toStdString() << "\"." << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,6 +219,7 @@ void Config::loadFromConfigFile(const QString &configFilePath)
|
|||
m_alpmRootDir = alpmObj.value(QStringLiteral("rootDir")).toString(m_alpmRootDir);
|
||||
m_alpmDbPath = alpmObj.value(QStringLiteral("dbPath")).toString(m_alpmDbPath);
|
||||
m_pacmanConfFile = alpmObj.value(QStringLiteral("pacmanConfigFile")).toString(m_pacmanConfFile);
|
||||
m_cacheDir = mainObj.value(QStringLiteral("cacheDir")).toString(m_cacheDir);
|
||||
auto aurObj = mainObj.value(QStringLiteral("aur")).toObject();
|
||||
m_aurEnabled = aurObj.value(QStringLiteral("enabled")).toBool(m_aurEnabled);
|
||||
auto serverObj = mainObj.value(QStringLiteral("server")).toObject();
|
||||
|
|
|
@ -117,6 +117,7 @@ public:
|
|||
const QString &alpmRootDir() const;
|
||||
const QString &alpmDbPath() const;
|
||||
const QString &pacmanConfFile() const;
|
||||
const QString &cacheDir() const;
|
||||
const QHostAddress &websocketServerListeningAddr() const;
|
||||
quint16 websocketServerListeningPort() const;
|
||||
const QString &serverCertFile() const;
|
||||
|
@ -137,6 +138,7 @@ private:
|
|||
QString m_alpmRootDir;
|
||||
QString m_alpmDbPath;
|
||||
QString m_pacmanConfFile;
|
||||
QString m_cacheDir;
|
||||
|
||||
QHostAddress m_websocketServerListeningAddr;
|
||||
quint16 m_websocketServerListeningPort;
|
||||
|
@ -166,6 +168,11 @@ inline const QString &Config::pacmanConfFile() const
|
|||
return m_pacmanConfFile;
|
||||
}
|
||||
|
||||
inline const QString &Config::cacheDir() const
|
||||
{
|
||||
return m_cacheDir;
|
||||
}
|
||||
|
||||
inline const QHostAddress &Config::websocketServerListeningAddr() const
|
||||
{
|
||||
return m_websocketServerListeningAddr;
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
#include <QList>
|
||||
#include <QSysInfo>
|
||||
#include <QMutexLocker>
|
||||
#include <QStringBuilder>
|
||||
#include <QFile>
|
||||
#include <QDataStream>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
@ -56,6 +59,7 @@ inline ostream &operator <<(ostream &stream, const QString &str)
|
|||
*/
|
||||
Manager::Manager(const Config &config) :
|
||||
m_config(config),
|
||||
m_writeCacheBeforeGone(true),
|
||||
m_sigLevel(defaultSigLevel),
|
||||
m_localFileSigLevel(ALPM_SIG_USE_DEFAULT)
|
||||
{
|
||||
|
@ -74,6 +78,9 @@ Manager::Manager(const Config &config) :
|
|||
*/
|
||||
Manager::~Manager()
|
||||
{
|
||||
if(m_writeCacheBeforeGone) {
|
||||
writeCache();
|
||||
}
|
||||
alpm_release(m_handle);
|
||||
}
|
||||
|
||||
|
@ -390,7 +397,7 @@ void Manager::applyPacmanConfig()
|
|||
// add sync db to internal map
|
||||
if(usage & ALPM_DB_USAGE_UPGRADE) {
|
||||
// -> db is used to upgrade local database
|
||||
localDatabase()->upgradeSources() << emplaced.first->second.get();
|
||||
localDataBase()->upgradeSources() << emplaced.first->second.get();
|
||||
}
|
||||
} else {
|
||||
cerr << shchar << "Error: Unable to add sync database [" << scope.first << "]" << endl;
|
||||
|
@ -469,17 +476,69 @@ void Manager::applyRepoIndexConfig()
|
|||
* \brief Initiates all ALPM data bases.
|
||||
* \remarks Must be called, after all relevant sync data bases have been registered (eg. via applyPacmanConfig()).
|
||||
*/
|
||||
void Manager::initAlpmDataBases()
|
||||
void Manager::initAlpmDataBases(bool computeRequiredBy)
|
||||
{
|
||||
QList<PackageLoader *> loaders;
|
||||
loaders.reserve(m_syncDbs.size() + 1);
|
||||
loaders << localDatabase()->init();
|
||||
for(auto &syncDbEntry : m_syncDbs) {
|
||||
loaders << syncDbEntry.second->init();
|
||||
// call the init method
|
||||
{
|
||||
QList<PackageLoader *> loaders;
|
||||
loaders.reserve(m_syncDbs.size() + 1);
|
||||
loaders << localDataBase()->init();
|
||||
for(auto &syncDbEntry : m_syncDbs) {
|
||||
loaders << syncDbEntry.second->init();
|
||||
}
|
||||
for(auto *loader : loaders) {
|
||||
loader->future().waitForFinished();
|
||||
delete loader;
|
||||
}
|
||||
}
|
||||
for(auto *loader : loaders) {
|
||||
loader->future().waitForFinished();
|
||||
delete loader;
|
||||
// compute required-by and optional-for
|
||||
if(computeRequiredBy) {
|
||||
QList<QFuture<void> > futures;
|
||||
futures.reserve(m_syncDbs.size() + 1);
|
||||
futures << localDataBase()->computeRequiredBy(*this);
|
||||
for(auto &syncDbEntry : m_syncDbs) {
|
||||
futures << syncDbEntry.second->computeRequiredBy(*this);
|
||||
}
|
||||
for(auto &future : futures) {
|
||||
future.waitForFinished();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Writes the cache for all repositories where caching makes sense.
|
||||
*/
|
||||
void Manager::writeCache()
|
||||
{
|
||||
// could iterate through all repos and check isCachingUseful() but
|
||||
// currently its just the AUR which is needed to be cached
|
||||
if(userRepository()) {
|
||||
QFile file(config().cacheDir() % QChar('/') % userRepository()->name() % QStringLiteral(".cache"));
|
||||
if(file.open(QFileDevice::WriteOnly)) {
|
||||
QDataStream stream(&file);
|
||||
userRepository()->writeToCacheStream(stream);
|
||||
// if warnings/errors occur, these will be printed directly by writeToCacheStream()
|
||||
} else {
|
||||
cerr << shchar << "Warning: Unable to write cache file for the AUR." << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::restoreCache()
|
||||
{
|
||||
// could iterate through all repos and check isCachingUseful() but
|
||||
// currently its just the AUR which is needed to be cached
|
||||
if(userRepository()) {
|
||||
QFile file(config().cacheDir() % QChar('/') % userRepository()->name() % QStringLiteral(".cache"));
|
||||
if(file.exists()) {
|
||||
if(file.open(QFileDevice::ReadOnly)) {
|
||||
QDataStream stream(&file);
|
||||
userRepository()->restoreFromCacheStream(stream);
|
||||
// if warnings/errors occur, these will be printed directly by restoreFromCacheStream()
|
||||
} else {
|
||||
cerr << shchar << "Warning: Unable to open cache file for the AUR." << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -514,7 +573,7 @@ const QJsonArray &Manager::basicRepoInfo() const
|
|||
QMutexLocker locker(&m_basicRepoInfoMutex);
|
||||
if(m_basicRepoInfo.isEmpty()) {
|
||||
// add local data base
|
||||
m_basicRepoInfo << localDatabase()->basicInfo();
|
||||
m_basicRepoInfo << localDataBase()->basicInfo();
|
||||
// add sync data bases
|
||||
for(const auto &syncDb : syncDatabases()) {
|
||||
// check if the "sync" database is actually used for syncing
|
||||
|
@ -581,7 +640,7 @@ 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();
|
||||
}
|
||||
|
@ -596,7 +655,7 @@ const QJsonArray &Manager::groupInfo() const
|
|||
const AlpmDatabase *Manager::databaseByName(const QString &dbName) const
|
||||
{
|
||||
if(dbName.compare(QLatin1String("local"), Qt::CaseInsensitive) == 0) {
|
||||
return localDatabase();
|
||||
return localDataBase();
|
||||
} else {
|
||||
try {
|
||||
return m_syncDbs.at(dbName).get();
|
||||
|
@ -612,7 +671,7 @@ const AlpmDatabase *Manager::databaseByName(const QString &dbName) const
|
|||
AlpmDatabase *Manager::databaseByName(const QString &dbName)
|
||||
{
|
||||
if(dbName.compare(QLatin1String("local"), Qt::CaseInsensitive) == 0) {
|
||||
return localDatabase();
|
||||
return localDataBase();
|
||||
} else {
|
||||
try {
|
||||
return m_syncDbs.at(dbName).get();
|
||||
|
@ -628,7 +687,7 @@ AlpmDatabase *Manager::databaseByName(const QString &dbName)
|
|||
const Repository *Manager::repositoryByName(const QString &name) const
|
||||
{
|
||||
if(name.compare(QLatin1String("local"), Qt::CaseInsensitive) == 0) {
|
||||
return localDatabase();
|
||||
return localDataBase();
|
||||
} else if(config().isAurEnabled() && (name.compare(QLatin1String("aur"), Qt::CaseInsensitive) == 0)) {
|
||||
return userRepository();
|
||||
} else {
|
||||
|
@ -646,7 +705,7 @@ const Repository *Manager::repositoryByName(const QString &name) const
|
|||
Repository *Manager::repositoryByName(const QString &name)
|
||||
{
|
||||
if(name.compare(QLatin1String("local"), Qt::CaseInsensitive) == 0) {
|
||||
return localDatabase();
|
||||
return localDataBase();
|
||||
} else if(config().isAurEnabled() && (name.compare(QLatin1String("aur"), Qt::CaseInsensitive) == 0)) {
|
||||
return userRepository();
|
||||
} else {
|
||||
|
|
|
@ -31,6 +31,8 @@ public:
|
|||
|
||||
// configuration, signature level, etc
|
||||
const Config &config() const;
|
||||
bool writeCacheBeforeGone() const;
|
||||
void setWriteCacheBeforeGone(bool writeCacheBeforeGone);
|
||||
int sigLevel() const;
|
||||
void setSigLevel(int sigLevel);
|
||||
int localFileSigLevel() const;
|
||||
|
@ -40,7 +42,9 @@ public:
|
|||
static int parseUsage(const std::string &usageStr);
|
||||
void applyPacmanConfig();
|
||||
void applyRepoIndexConfig();
|
||||
void initAlpmDataBases();
|
||||
void initAlpmDataBases(bool computeRequiredBy);
|
||||
void writeCache();
|
||||
void restoreCache();
|
||||
|
||||
void unregisterSyncDataBases();
|
||||
|
||||
|
@ -56,8 +60,8 @@ public:
|
|||
void setInstallReason(AlpmPackage *package, alpm_pkgreason_t reason);
|
||||
|
||||
// repository lookup
|
||||
const AlpmDatabase *localDatabase() const;
|
||||
AlpmDatabase *localDatabase();
|
||||
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);
|
||||
|
@ -79,6 +83,7 @@ private:
|
|||
void cleanup();
|
||||
|
||||
const Config &m_config;
|
||||
bool m_writeCacheBeforeGone;
|
||||
alpm_handle_t *m_handle;
|
||||
int m_sigLevel;
|
||||
int m_localFileSigLevel;
|
||||
|
@ -102,6 +107,26 @@ inline const Config &Manager::config() const
|
|||
return m_config;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether the manager writes cache files for all relevant repositories before the manager is
|
||||
* gone (out of scope, deleted, ...).
|
||||
* \sa setWriteCacheBeforeGone()
|
||||
*/
|
||||
inline bool Manager::writeCacheBeforeGone() const
|
||||
{
|
||||
return m_writeCacheBeforeGone;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets whether the manager writes cache files for all relevant repositories before the manager is
|
||||
* gone (out of scope, deleted, ...).
|
||||
* \sa writeCacheBeforeGone()
|
||||
*/
|
||||
inline void Manager::setWriteCacheBeforeGone(bool writeCacheBeforeGone)
|
||||
{
|
||||
m_writeCacheBeforeGone = writeCacheBeforeGone;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the signature level.
|
||||
*
|
||||
|
@ -172,7 +197,7 @@ inline UserRepository *Manager::userRepository()
|
|||
/*!
|
||||
* \brief Returns the local data base.
|
||||
*/
|
||||
inline const AlpmDatabase *Manager::localDatabase() const
|
||||
inline const AlpmDatabase *Manager::localDataBase() const
|
||||
{
|
||||
return m_localDb.get();
|
||||
}
|
||||
|
@ -180,7 +205,7 @@ inline const AlpmDatabase *Manager::localDatabase() const
|
|||
/*!
|
||||
* \brief Returns the local data base.
|
||||
*/
|
||||
inline AlpmDatabase *Manager::localDatabase()
|
||||
inline AlpmDatabase *Manager::localDataBase()
|
||||
{
|
||||
return m_localDb.get();
|
||||
}
|
||||
|
|
293
alpm/package.cpp
293
alpm/package.cpp
|
@ -2,11 +2,16 @@
|
|||
#include "./alpmdatabase.h"
|
||||
#include "./utilities.h"
|
||||
#include "./repository.h"
|
||||
#include "./manager.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QVariant>
|
||||
#include <QDataStream>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace ChronoUtilities;
|
||||
|
@ -29,6 +34,7 @@ Package::Package(const QString &name, Repository *source) :
|
|||
m_source(source),
|
||||
m_hasGeneralInfo(false),
|
||||
m_name(name),
|
||||
m_requiredByComputed(false),
|
||||
m_hasInstallScript(false),
|
||||
m_hasBuildRelatedMetaData(false),
|
||||
m_hasInstallRelatedMetaData(false),
|
||||
|
@ -41,9 +47,79 @@ Package::Package(const QString &name, Repository *source) :
|
|||
// initialization must be done in derived class
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Writes the package-type-specific cache header.
|
||||
*/
|
||||
void Package::writeSpecificCacheHeader(QDataStream &out)
|
||||
{
|
||||
Q_UNUSED(out)
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Restores the package-type-specific cache header.
|
||||
*/
|
||||
void Package::restoreSpecificCacheHeader(QDataStream &in)
|
||||
{
|
||||
Q_UNUSED(in)
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the package.
|
||||
*/
|
||||
Package::~Package()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Computes required-by and optional-for.
|
||||
*/
|
||||
void Package::computeRequiredBy(Manager &manager)
|
||||
{
|
||||
if(m_requiredByComputed) {
|
||||
m_requiredBy.clear();
|
||||
m_optionalFor.clear();
|
||||
}
|
||||
switch(origin()) {
|
||||
case PackageOrigin::File:
|
||||
case PackageOrigin::LocalDb:
|
||||
for(const auto &pkgEntry : manager.localDataBase()->packages()) {
|
||||
for(const auto &dep : pkgEntry.second->dependencies()) {
|
||||
if(dep.name == m_name) {
|
||||
m_requiredBy << pkgEntry.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(const auto &dep : pkgEntry.second->optionalDependencies()) {
|
||||
if(dep.name == m_name) {
|
||||
m_optionalFor << pkgEntry.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PackageOrigin::SyncDb:
|
||||
for(const auto &dbEntry : manager.syncDatabases()) {
|
||||
for(const auto &pkgEntry : dbEntry.second->packages()) {
|
||||
for(const auto &dep : pkgEntry.second->dependencies()) {
|
||||
if(dep.name == m_name) {
|
||||
m_requiredBy << pkgEntry.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(const auto &dep : pkgEntry.second->optionalDependencies()) {
|
||||
if(dep.name == m_name) {
|
||||
m_optionalFor << pkgEntry.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
; // can not compute this for packages from other sources
|
||||
}
|
||||
m_requiredByComputed = true;
|
||||
}
|
||||
|
||||
bool Package::matches(const QString &name, const QString &version, const Dependency &dependency)
|
||||
{
|
||||
if(name == QStringLiteral("gst-plugins-base-libs") && dependency.name == QStringLiteral("gst-plugins-base-libs")) {
|
||||
|
@ -79,9 +155,7 @@ namespace Utilities {
|
|||
|
||||
inline void put(QJsonObject &obj, const QString &key, const QJsonValue &value)
|
||||
{
|
||||
if(!value.isNull()) {
|
||||
obj.insert(key, value);
|
||||
}
|
||||
obj.insert(key, value);
|
||||
}
|
||||
|
||||
inline void put(QJsonObject &obj, const QString &key, const DateTime dateTime)
|
||||
|
@ -93,43 +167,117 @@ inline void put(QJsonObject &obj, const QString &key, const DateTime dateTime)
|
|||
|
||||
inline void put(QJsonObject &obj, const QString &key, const QStringList &values)
|
||||
{
|
||||
if(!values.isEmpty()) {
|
||||
put(obj, key, QJsonArray::fromStringList(values));
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
put(obj, key, jsonArray);
|
||||
jsonArray << depObj;
|
||||
}
|
||||
put(obj, key, jsonArray);
|
||||
}
|
||||
|
||||
QDataStream &operator <<(QDataStream &out, const QList<Dependency> dependencies)
|
||||
{
|
||||
out << static_cast<quint32>(dependencies.count());
|
||||
for(const auto &dependency : dependencies) {
|
||||
out << dependency.name << dependency.version << static_cast<quint32>(dependency.mode);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
QDataStream &operator >>(QDataStream &in, QList<Dependency> &dependencies)
|
||||
{
|
||||
quint32 size;
|
||||
in >> size;
|
||||
for(quint32 i = 0; i < size; ++i) {
|
||||
QString name;
|
||||
in >> name;
|
||||
QString version;
|
||||
in >> version;
|
||||
quint32 mode;
|
||||
in >> mode;
|
||||
dependencies << Dependency(name, version, static_cast<_alpm_depmod_t>(mode));
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
inline QDataStream &operator <<(QDataStream &out, const DateTime dateTime)
|
||||
{
|
||||
return out << static_cast<quint64>(dateTime.totalTicks());
|
||||
}
|
||||
|
||||
inline QDataStream &operator >>(QDataStream &in, DateTime &dateTime)
|
||||
{
|
||||
quint64 ticks;
|
||||
in >> ticks;
|
||||
dateTime = DateTime(ticks);
|
||||
return in;
|
||||
}
|
||||
|
||||
QDataStream &operator <<(QDataStream &out, const map<QString, QByteArray> fileMap)
|
||||
{
|
||||
out << static_cast<quint32>(fileMap.size());
|
||||
for(const auto &entry : fileMap) {
|
||||
out << entry.first << entry.second;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
QDataStream &operator >>(QDataStream &in, map<QString, QByteArray> &fileMap)
|
||||
{
|
||||
quint32 size;
|
||||
in >> size;
|
||||
for(quint32 i = 0; i < size; ++i) {
|
||||
QString path;
|
||||
in >> path;
|
||||
QByteArray data;
|
||||
in >> data;
|
||||
fileMap.emplace(path, data);
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
QDataStream &operator <<(QDataStream &out, const QJsonArray &jsonArray)
|
||||
{
|
||||
QJsonDocument doc;
|
||||
doc.setArray(jsonArray);
|
||||
out << doc.toBinaryData();
|
||||
return out;
|
||||
}
|
||||
|
||||
QDataStream &operator >>(QDataStream &in, QJsonArray &jsonArray)
|
||||
{
|
||||
QByteArray data;
|
||||
in >> data;
|
||||
QJsonDocument doc = QJsonDocument::fromBinaryData(data);
|
||||
jsonArray = doc.array();
|
||||
return in;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -152,12 +300,12 @@ QJsonObject Package::basicInfo(bool includeRepoAndName) const
|
|||
}
|
||||
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());
|
||||
put(info, QStringLiteral("arch"), buildArchitecture());
|
||||
put(info, QStringLiteral("bdate"), buildDate());
|
||||
put(info, QStringLiteral("archs"), architectures());
|
||||
return info;
|
||||
}
|
||||
|
||||
|
@ -173,6 +321,8 @@ QJsonObject Package::fullInfo(bool includeRepoAndName) const
|
|||
}
|
||||
put(info, QStringLiteral("name"), name());
|
||||
}
|
||||
put(info, QStringLiteral("build_avail"), hasBuildRelatedMetaData());
|
||||
put(info, QStringLiteral("src_avail"), hasSourceRelatedMetaData());
|
||||
put(info, QStringLiteral("archs"), architectures());
|
||||
put(info, QStringLiteral("arch"), buildArchitecture());
|
||||
put(info, QStringLiteral("ver"), version());
|
||||
|
@ -201,6 +351,75 @@ QJsonObject Package::fullInfo(bool includeRepoAndName) const
|
|||
return info;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Writes the package contents to the specified data stream.
|
||||
*/
|
||||
void Package::writeToCacheStream(QDataStream &out)
|
||||
{
|
||||
out << static_cast<qint32>(m_origin);
|
||||
// general info
|
||||
out << m_hasGeneralInfo << m_name << m_version << m_description << m_upstreamUrl << m_licenses
|
||||
<< m_groups << m_dependencies << m_optionalDependencies << m_conflicts << m_provides
|
||||
<< m_replaces << m_requiredByComputed << m_requiredBy << m_optionalFor << m_hasInstallScript;
|
||||
// build related meta data
|
||||
out << m_hasBuildRelatedMetaData << m_fileName << m_files << m_buildDate << m_packer
|
||||
<< m_md5 << m_sha256 << m_buildArchitecture << m_packageSize << m_makeDependencies;
|
||||
// installation related meta data
|
||||
out << m_hasInstallRelatedMetaData << m_installDate << m_installedSize << m_backupFiles
|
||||
<< static_cast<qint32>(m_validationMethods) << static_cast<qint32>(m_installReason);
|
||||
// source related meta data
|
||||
out << m_hasSourceRelatedMetaData << m_baseName << m_architectures << m_id
|
||||
<< m_categoryId << m_votes << m_outOfDate
|
||||
<< m_maintainer << m_firstSubmitted << m_lastModified << m_tarUrl << m_sourceFiles;
|
||||
// write specific header
|
||||
auto headerStart = out.device()->pos();
|
||||
out.device()->seek(headerStart + 4);
|
||||
writeSpecificCacheHeader(out);
|
||||
auto headerEnd = out.device()->pos();
|
||||
out.device()->seek(headerStart);
|
||||
out << static_cast<quint32>(headerEnd - headerStart - 4);
|
||||
out.device()->seek(headerEnd);
|
||||
// no extended header
|
||||
out << static_cast<quint32>(0);
|
||||
}
|
||||
|
||||
void Package::restoreFromCacheStream(QDataStream &in)
|
||||
{
|
||||
qint32 tmp;
|
||||
// origin
|
||||
in >> tmp;
|
||||
m_origin = static_cast<PackageOrigin>(tmp); // TODO: validate value
|
||||
// general info
|
||||
in >> m_hasGeneralInfo >> m_name >> m_version >> m_description >> m_upstreamUrl >> m_licenses
|
||||
>> m_groups >> m_dependencies >> m_optionalDependencies >> m_conflicts >> m_provides
|
||||
>> m_replaces >> m_requiredByComputed >> m_requiredBy >> m_optionalFor >> m_hasInstallScript;
|
||||
// build related meta data
|
||||
in >> m_hasBuildRelatedMetaData >> m_fileName >> m_files >> m_buildDate >> m_packer
|
||||
>> m_md5 >> m_sha256 >> m_buildArchitecture >> m_packageSize >> m_makeDependencies;
|
||||
// installation related meta data
|
||||
in >> m_hasInstallRelatedMetaData >> m_installDate >> m_installedSize >> m_backupFiles;
|
||||
in >> tmp;
|
||||
m_validationMethods = static_cast<alpm_pkgvalidation_t>(m_validationMethods); // TODO: validate value
|
||||
in >> tmp;
|
||||
m_installReason = static_cast<alpm_pkgreason_t>(m_installReason); // TODO: validate value
|
||||
// source related meta data
|
||||
in >> m_hasSourceRelatedMetaData >> m_baseName >> m_architectures >> m_id
|
||||
>> m_categoryId >> m_votes >> m_outOfDate
|
||||
>> m_maintainer >> m_firstSubmitted >> m_lastModified >> m_tarUrl >> m_sourceFiles;
|
||||
// specific header
|
||||
quint32 headerSize;
|
||||
in >> headerSize;
|
||||
quint64 headerEnd = in.device()->pos() + headerSize;
|
||||
restoreSpecificCacheHeader(in);
|
||||
in.device()->seek(headerEnd);
|
||||
if(in.status() == QDataStream::Ok) {
|
||||
// skip extended header
|
||||
in >> headerSize;
|
||||
quint64 headerEnd = in.device()->pos() + headerSize;
|
||||
in.device()->seek(headerEnd);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief The PackageVersion class helps parsing package versions.
|
||||
*/
|
||||
|
|
|
@ -88,6 +88,8 @@ inline Dependency::Dependency(const QString &name, const QString &version, _alpm
|
|||
mode(mode)
|
||||
{}
|
||||
|
||||
class Manager;
|
||||
|
||||
class Package
|
||||
{
|
||||
public:
|
||||
|
@ -108,6 +110,8 @@ public:
|
|||
const QList<Dependency> &conflicts() const;
|
||||
const QList<Dependency> &provides() const;
|
||||
const QList<Dependency> &replaces() const;
|
||||
bool isRequiredByComputed() const;
|
||||
void computeRequiredBy(Manager &manager);
|
||||
const QStringList &requiredBy() const;
|
||||
const QStringList &optionalFor() const;
|
||||
bool hasInstallScript() const;
|
||||
|
@ -136,9 +140,9 @@ public:
|
|||
bool hasSourceRelatedMetaData() const;
|
||||
const QString &baseName() const;
|
||||
const QStringList &architectures() const;
|
||||
int id() const;
|
||||
int categoryId() const;
|
||||
int votes() const;
|
||||
int32 id() const;
|
||||
int32 categoryId() const;
|
||||
int32 votes() const;
|
||||
ChronoUtilities::DateTime outOfDate() const;
|
||||
const QString &maintainer() const;
|
||||
ChronoUtilities::DateTime firstSubmitted() const;
|
||||
|
@ -156,8 +160,14 @@ public:
|
|||
QJsonObject basicInfo(bool includeRepoAndName = false) const;
|
||||
QJsonObject fullInfo(bool includeRepoAndName = false) const;
|
||||
|
||||
// caching
|
||||
void writeToCacheStream(QDataStream &out);
|
||||
void restoreFromCacheStream(QDataStream &in);
|
||||
|
||||
protected:
|
||||
explicit Package(const QString &name, Repository *source);
|
||||
virtual void writeSpecificCacheHeader(QDataStream &out);
|
||||
virtual void restoreSpecificCacheHeader(QDataStream &in);
|
||||
|
||||
PackageOrigin m_origin;
|
||||
Repository *m_source;
|
||||
|
@ -175,6 +185,7 @@ protected:
|
|||
QList<Dependency> m_conflicts;
|
||||
QList<Dependency> m_provides;
|
||||
QList<Dependency> m_replaces;
|
||||
bool m_requiredByComputed;
|
||||
QStringList m_requiredBy;
|
||||
QStringList m_optionalFor;
|
||||
bool m_hasInstallScript;
|
||||
|
@ -203,9 +214,9 @@ protected:
|
|||
bool m_hasSourceRelatedMetaData;
|
||||
QString m_baseName;
|
||||
QStringList m_architectures;
|
||||
int m_id;
|
||||
int m_categoryId;
|
||||
int m_votes;
|
||||
int32 m_id;
|
||||
int32 m_categoryId;
|
||||
int32 m_votes;
|
||||
ChronoUtilities::DateTime m_outOfDate;
|
||||
QString m_maintainer;
|
||||
ChronoUtilities::DateTime m_firstSubmitted;
|
||||
|
@ -327,6 +338,14 @@ inline const QList<Dependency> &Package::replaces() const
|
|||
return m_replaces;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether required-by and optional-for have been computed.
|
||||
*/
|
||||
inline bool Package::isRequiredByComputed() const
|
||||
{
|
||||
return m_requiredByComputed;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns packages requiring this packages.
|
||||
*/
|
||||
|
@ -520,7 +539,7 @@ inline const QStringList &Package::architectures() const
|
|||
/*!
|
||||
* \brief Returns the ID.
|
||||
*/
|
||||
inline int Package::id() const
|
||||
inline int32 Package::id() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
@ -528,7 +547,7 @@ inline int Package::id() const
|
|||
/*!
|
||||
* \brief Returns the category ID.
|
||||
*/
|
||||
inline int Package::categoryId() const
|
||||
inline int32 Package::categoryId() const
|
||||
{
|
||||
return m_categoryId;
|
||||
}
|
||||
|
@ -536,7 +555,7 @@ inline int Package::categoryId() const
|
|||
/*!
|
||||
* \brief Returns the votes of the package.
|
||||
*/
|
||||
inline int Package::votes() const
|
||||
inline int32 Package::votes() const
|
||||
{
|
||||
return m_votes;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
#include "./repository.h"
|
||||
#include "./upgradelookup.h"
|
||||
#include "./utilities.h"
|
||||
#include "./config.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
#include <QDataStream>
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -209,6 +214,43 @@ QList<Package *> Repository::packageByFilter(std::function<bool (const Package *
|
|||
return packages;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \cond
|
||||
*/
|
||||
|
||||
class ComputeRequired
|
||||
{
|
||||
public:
|
||||
ComputeRequired(Manager &manager, bool forceUpdate) :
|
||||
m_manager(manager),
|
||||
m_forceUpdate(forceUpdate)
|
||||
{}
|
||||
|
||||
void operator () (const pair<const QString, unique_ptr<Package> > &packageEntry)
|
||||
{
|
||||
if(m_forceUpdate || !packageEntry.second->isRequiredByComputed()) {
|
||||
packageEntry.second->computeRequiredBy(m_manager);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Manager &m_manager;
|
||||
bool m_forceUpdate;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \endcond
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Computes required-by and optional-for for all packages.
|
||||
* \remarks Computition is done async.
|
||||
*/
|
||||
QFuture<void> Repository::computeRequiredBy(Manager &manager, bool forceUpdate)
|
||||
{
|
||||
return QtConcurrent::map(m_packages, ComputeRequired(manager, forceUpdate));
|
||||
}
|
||||
|
||||
QJsonArray Repository::upgradeSourcesJsonArray() const
|
||||
{
|
||||
QJsonArray sources;
|
||||
|
@ -323,5 +365,110 @@ QJsonObject Repository::groupInfo() const
|
|||
return info;
|
||||
}
|
||||
|
||||
} // namespace PackageManagement
|
||||
/*!
|
||||
* \brief Writes the repository information to the specified cache stream.
|
||||
*/
|
||||
void Repository::writeToCacheStream(QDataStream &out)
|
||||
{
|
||||
out << static_cast<quint32>(0x7265706F); // magic number
|
||||
out << static_cast<quint32>(0x0); // version
|
||||
out << static_cast<quint32>(type());
|
||||
out << static_cast<quint32>(m_packages.size());
|
||||
for(const auto &pkg : m_packages) {
|
||||
pkg.second->writeToCacheStream(out);
|
||||
}
|
||||
// write specific header
|
||||
auto headerStart = out.device()->pos();
|
||||
out.device()->seek(headerStart + 4);
|
||||
writeSpecificCacheHeader(out);
|
||||
auto headerEnd = out.device()->pos();
|
||||
out.device()->seek(headerStart);
|
||||
out << static_cast<quint32>(headerEnd - headerStart - 4);
|
||||
out.device()->seek(headerEnd);
|
||||
// no extended header
|
||||
out << static_cast<quint32>(0x0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Restores the repository information from cache.
|
||||
*/
|
||||
void Repository::restoreFromCacheStream(QDataStream &in)
|
||||
{
|
||||
quint32 magic;
|
||||
in >> magic;
|
||||
if(magic == 0x7265706F) {
|
||||
// read version
|
||||
quint32 version;
|
||||
in >> version;
|
||||
// read type
|
||||
quint32 denotedType;
|
||||
in >> denotedType;
|
||||
if(denotedType == static_cast<quint32>(type())) {
|
||||
// read packages
|
||||
quint32 packageCount;
|
||||
in >> packageCount;
|
||||
bool good = true;
|
||||
for(quint32 i = 0; i < packageCount && good && in.status() == QDataStream::Ok; ++i) {
|
||||
if(unique_ptr<Package> package = emptyPackage()) {
|
||||
package->restoreFromCacheStream(in);
|
||||
if(!package->name().isEmpty()) {
|
||||
m_packages[package->name()] = move(package);
|
||||
} else {
|
||||
good = false;
|
||||
}
|
||||
} else {
|
||||
good = false;
|
||||
}
|
||||
}
|
||||
if(in.status() == QDataStream::Ok) {
|
||||
// specific header
|
||||
quint32 headerSize;
|
||||
in >> headerSize;
|
||||
quint64 headerEnd = in.device()->pos() + headerSize;
|
||||
restoreSpecificCacheHeader(in);
|
||||
in.device()->seek(headerEnd);
|
||||
if(in.status() == QDataStream::Ok) {
|
||||
// skip extended header
|
||||
in >> headerSize;
|
||||
quint64 headerEnd = in.device()->pos() + headerSize;
|
||||
in.device()->seek(headerEnd);
|
||||
} else {
|
||||
cerr << shchar << "Failed to restore cache for repository \"" << m_name.toLocal8Bit().data() << "\": unable to parse specific cache header" << endl;
|
||||
}
|
||||
} else {
|
||||
cerr << shchar << "Failed to restore cache for repository \"" << m_name.toLocal8Bit().data() << "\": unable to parse packages" << endl;
|
||||
}
|
||||
} else {
|
||||
cerr << shchar << "Failed to restore cache for repository \"" << m_name.toLocal8Bit().data() << "\": denoted type does not match expected type" << endl;
|
||||
}
|
||||
} else {
|
||||
cerr << shchar << "Failed to restore cache for repository \"" << m_name.toLocal8Bit().data() << "\": bad magic number" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Writes the repo-type-specific cache header.
|
||||
*/
|
||||
void Repository::writeSpecificCacheHeader(QDataStream &out)
|
||||
{
|
||||
Q_UNUSED(out)
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns an new, empty package.
|
||||
* \remarks Used to when restoring packages from cache.
|
||||
*/
|
||||
unique_ptr<Package> Repository::emptyPackage()
|
||||
{
|
||||
return unique_ptr<Package>();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Restores the repo-type-specific cache header.
|
||||
*/
|
||||
void Repository::restoreSpecificCacheHeader(QDataStream &in)
|
||||
{
|
||||
Q_UNUSED(in)
|
||||
}
|
||||
|
||||
} // namespace PackageManagement
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "./group.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QFuture>
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
@ -104,7 +105,8 @@ enum class PackageDetail
|
|||
Basics, /*! Basic information about the package such as knowing it exists, its name, version and description. */
|
||||
Dependencies, /*! The runtime dependencies of the package. */
|
||||
SourceInfo, /*! The source info such as make dependencies of the package. */
|
||||
PackageInfo /*! Information related to a specific package (pkg-file). */
|
||||
PackageInfo, /*! Information related to a specific package (pkg-file). */
|
||||
AllAvailable /*! All available package details. */
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -153,6 +155,7 @@ public:
|
|||
Package *packageProviding(const Dependency &dependency);
|
||||
QList<const Package *> packagesProviding(const Dependency &dependency) const;
|
||||
QList<Package *> packageByFilter(std::function<bool (const Package *)> pred);
|
||||
QFuture<void> computeRequiredBy(Manager &manager, bool forceUpdate = false);
|
||||
|
||||
// upgrade lookup
|
||||
const QList<const Repository *> &upgradeSources() const;
|
||||
|
@ -172,6 +175,14 @@ public:
|
|||
QJsonObject basicInfo() const;
|
||||
QJsonObject groupInfo() const;
|
||||
|
||||
// caching
|
||||
bool isCachingUseful() const;
|
||||
void writeToCacheStream(QDataStream &out);
|
||||
void restoreFromCacheStream(QDataStream &in);
|
||||
virtual void writeSpecificCacheHeader(QDataStream &out);
|
||||
virtual std::unique_ptr<Package> emptyPackage();
|
||||
virtual void restoreSpecificCacheHeader(QDataStream &in);
|
||||
|
||||
protected:
|
||||
explicit Repository(const QString &name, QObject *parent = nullptr);
|
||||
|
||||
|
@ -331,6 +342,20 @@ inline void Repository::setPackagesDirectory(const QString &dir)
|
|||
m_pkgDir = dir;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether caching this repository is useful.
|
||||
*/
|
||||
inline bool Repository::isCachingUseful() const
|
||||
{
|
||||
switch(requestsRequired(PackageDetail::AllAvailable)) {
|
||||
case PackageDetailAvailability::Request:
|
||||
case PackageDetailAvailability::FullRequest:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace PackageManagement
|
||||
|
||||
#endif // PACKAGEMANAGEMENT_PACKAGESOURCE_H
|
||||
|
|
|
@ -103,7 +103,6 @@ void UpgradeLookupProcess::checkUpgrades()
|
|||
/*!
|
||||
* \class UpgradeLookup
|
||||
* \brief The UpgradeLookup class performs an async upgrade lookup for using multiple upgrade sources.
|
||||
* \remarks The object deletes itself after the lookup is done.
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
@ -123,6 +122,7 @@ UpgradeLookup::UpgradeLookup(QObject *parent) :
|
|||
|
||||
/*!
|
||||
* \class UpgradeLookupJson
|
||||
* \remarks The object deletes itself after the lookup is done (hence it must be created using new).
|
||||
* \brief The UpgradeLookupJson class performs an async upgrade lookup for using multiple upgrade sources.
|
||||
*
|
||||
* The request and the results are in JSON.
|
||||
|
@ -367,8 +367,7 @@ void UpgradeLookupCli::printResults()
|
|||
Utilities::printValues(cout, "Orphaned packages", m_orphanedPackagesArray);
|
||||
}
|
||||
}
|
||||
// lookup done, delete this helper object
|
||||
deleteLater();
|
||||
emit finished();
|
||||
}
|
||||
|
||||
} // namespace PackageManagement
|
||||
|
|
|
@ -160,6 +160,9 @@ public:
|
|||
explicit UpgradeLookupCli(const Manager &manager, const std::string &repo, QObject *parent = nullptr);
|
||||
const Repository *toCheck() const;
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
private slots:
|
||||
void processFinished();
|
||||
|
||||
|
|
8
main.cpp
8
main.cpp
|
@ -50,12 +50,13 @@ int main(int argc, char *argv[])
|
|||
}) != parser.mainArguments().cend()) {
|
||||
// create app
|
||||
QCoreApplication application(argc, argv);
|
||||
// setup ALPM
|
||||
// setup manager
|
||||
Manager manager(config);
|
||||
manager.applyPacmanConfig();
|
||||
manager.applyRepoIndexConfig();
|
||||
cerr << shchar << "Loading databases ..." << endl;
|
||||
manager.initAlpmDataBases();
|
||||
manager.initAlpmDataBases(configArgs.serverArg.isPresent());
|
||||
manager.restoreCache();
|
||||
if(configArgs.serverArg.isPresent()) {
|
||||
// setup the server
|
||||
Server server(manager, manager.config());
|
||||
|
@ -71,7 +72,8 @@ int main(int argc, char *argv[])
|
|||
configArgs.targetNameArg.values().front(),
|
||||
configArgs.targetFormatArg.isPresent() ? configArgs.targetFormatArg.values().front() : string("zip"));
|
||||
} else if(configArgs.upgradeLookupArg.isPresent()) {
|
||||
QObject::connect(new UpgradeLookupCli(manager, configArgs.upgradeLookupArg.values().front()), &QObject::destroyed, &application, &QCoreApplication::quit);
|
||||
UpgradeLookupCli upgradeLookup(manager, configArgs.upgradeLookupArg.values().front());
|
||||
QObject::connect(&upgradeLookup, &UpgradeLookupCli::finished, &application, &QCoreApplication::quit);
|
||||
return application.exec();
|
||||
}
|
||||
} else if(!configArgs.helpArg.isPresent()) {
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QWebSocket>
|
||||
#include <QCoreApplication>
|
||||
|
||||
namespace RepoIndex {
|
||||
|
||||
Connection::Connection(const Manager &alpmManager, QWebSocket *socket, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_socket(socket),
|
||||
m_alpmManager(alpmManager),
|
||||
m_manager(alpmManager),
|
||||
m_repoInfoUpdatesRequested(false),
|
||||
m_groupInfoUpdatesRequested(false)
|
||||
{
|
||||
|
@ -28,11 +29,14 @@ void Connection::sendJson(const QJsonObject &obj)
|
|||
m_socket->sendTextMessage(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
||||
}
|
||||
|
||||
void Connection::sendError(const QString &msg)
|
||||
void Connection::sendError(const QString &msg, const QJsonValue &id)
|
||||
{
|
||||
QJsonObject response;
|
||||
response.insert(QStringLiteral("class"), QStringLiteral("error"));
|
||||
response.insert(QStringLiteral("msg"), msg);
|
||||
if(!id.isNull() && !id.isUndefined()) {
|
||||
response.insert(QStringLiteral("id"), id);
|
||||
}
|
||||
sendJson(response);
|
||||
}
|
||||
|
||||
|
@ -42,7 +46,7 @@ void Connection::sendResult(const QJsonValue &what, const QJsonValue &id, const
|
|||
response.insert(QStringLiteral("class"), QStringLiteral("results"));
|
||||
response.insert(QStringLiteral("what"), what);
|
||||
response.insert(QStringLiteral("value"), value);
|
||||
if(!id.isNull()) {
|
||||
if(!id.isNull() && !id.isUndefined()) {
|
||||
response.insert("id", id);
|
||||
}
|
||||
sendJson(response);
|
||||
|
@ -54,7 +58,7 @@ void Connection::sendResults(const QJsonValue &what, const QJsonValue &id, const
|
|||
response.insert(QStringLiteral("class"), QStringLiteral("results"));
|
||||
response.insert(QStringLiteral("what"), what);
|
||||
response.insert(QStringLiteral("values"), values);
|
||||
if(!id.isNull()) {
|
||||
if(!id.isNull() && !id.isUndefined()) {
|
||||
response.insert("id", id);
|
||||
}
|
||||
sendJson(response);
|
||||
|
@ -66,20 +70,35 @@ void Connection::handleQuery(const QJsonObject &obj)
|
|||
const auto id = obj.value(QStringLiteral("id"));
|
||||
if(what == QLatin1String("basicrepoinfo")) {
|
||||
m_repoInfoUpdatesRequested = obj.value(QStringLiteral("updates")).toBool(m_repoInfoUpdatesRequested);
|
||||
sendResults(what, id, m_alpmManager.basicRepoInfo());
|
||||
sendResults(what, id, m_manager.basicRepoInfo());
|
||||
} else if(what == QLatin1String("basicpkginfo")) {
|
||||
sendResults(what, id, m_alpmManager.packageInfo(obj.value("sel").toObject(), false));
|
||||
sendResults(what, id, m_manager.packageInfo(obj.value("sel").toObject(), false));
|
||||
} else if(what == QLatin1String("fullpkginfo")) {
|
||||
sendResults(what, id, m_alpmManager.packageInfo(obj.value("sel").toObject(), true));
|
||||
sendResults(what, id, m_manager.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());
|
||||
sendResults(what, id, m_manager.groupInfo());
|
||||
} else if(what == QLatin1String("checkforupdates")) {
|
||||
connect(new UpgradeLookupJson(m_alpmManager, obj), &UpgradeLookupJson::resultsAvailable, this, &Connection::sendResult);
|
||||
connect(new UpgradeLookupJson(m_manager, obj), &UpgradeLookupJson::resultsAvailable, this, &Connection::sendResult);
|
||||
} else if(what == QLatin1String("ping")) {
|
||||
sendResult(what, id, QStringLiteral("pong"));
|
||||
} else {
|
||||
sendResult(what, id, QStringLiteral("unknownquery"));
|
||||
sendError(QStringLiteral("unknown query"), id);
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::handleCmd(const QJsonObject &obj)
|
||||
{
|
||||
const auto what = obj.value(QStringLiteral("what")).toString();
|
||||
const auto id = obj.value(QStringLiteral("id"));
|
||||
if(what == QLatin1String("stop")) {
|
||||
if(m_socket->peerAddress().isLoopback()) {
|
||||
QCoreApplication::quit();
|
||||
} else {
|
||||
sendError(QStringLiteral("rejected"), id);
|
||||
}
|
||||
} else {
|
||||
sendError(QStringLiteral("unknown command"), id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,11 +107,14 @@ void Connection::processTextMessage(const QString &message)
|
|||
QJsonParseError error;
|
||||
QByteArray jsonData;
|
||||
jsonData.append(message);
|
||||
QJsonDocument doc = QJsonDocument::fromJson(jsonData, &error);
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(jsonData, &error);
|
||||
if(error.error == QJsonParseError::NoError) {
|
||||
QString msgClass = doc.object().value(QStringLiteral("class")).toString();
|
||||
const QJsonObject obj = doc.object();
|
||||
const QString msgClass = obj.value(QStringLiteral("class")).toString();
|
||||
if(msgClass == QLatin1String("query")) {
|
||||
handleQuery(doc.object());
|
||||
handleQuery(obj);
|
||||
} else if(msgClass == QLatin1String("cmd")) {
|
||||
handleCmd(obj);
|
||||
} else {
|
||||
sendError(QStringLiteral("no message class specified"));
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define CONNECTION_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QJsonValue>
|
||||
|
||||
#include <map>
|
||||
|
||||
|
@ -27,11 +28,12 @@ private slots:
|
|||
|
||||
private:
|
||||
void sendJson(const QJsonObject &obj);
|
||||
void sendError(const QString &msg);
|
||||
void sendError(const QString &msg, const QJsonValue &id = QJsonValue());
|
||||
void handleQuery(const QJsonObject &obj);
|
||||
void handleCmd(const QJsonObject &obj);
|
||||
|
||||
QWebSocket *m_socket;
|
||||
const RepoIndex::Manager &m_alpmManager;
|
||||
const RepoIndex::Manager &m_manager;
|
||||
bool m_repoInfoUpdatesRequested;
|
||||
bool m_groupInfoUpdatesRequested;
|
||||
|
||||
|
|
|
@ -52,7 +52,12 @@ Server::Server(const RepoIndex::Manager &alpmManager, const RepoIndex::Config &c
|
|||
}
|
||||
// start listening
|
||||
if(m_server->listen(config.websocketServerListeningAddr(), config.websocketServerListeningPort())) {
|
||||
cerr << shchar << m_server->serverName().toLocal8Bit().data() << " is listening on port " << m_server->serverPort() << endl;
|
||||
if(useShSyntax) {
|
||||
cout << "export REPOINDEX_SERVER_NAME='" << m_server->serverName().toLocal8Bit().data() << '\'' << endl;
|
||||
cout << "export REPOINDEX_SERVER_PORT='" << m_server->serverPort() << '\'' << endl;
|
||||
} else {
|
||||
cout << m_server->serverName().toLocal8Bit().data() << " is listening on port " << m_server->serverPort() << endl;
|
||||
}
|
||||
connect(m_server, &QWebSocketServer::newConnection, this, &Server::incomingConnection);
|
||||
connect(m_server, &QWebSocketServer::closed, this, &Server::closed);
|
||||
} else {
|
||||
|
@ -60,8 +65,6 @@ Server::Server(const RepoIndex::Manager &alpmManager, const RepoIndex::Config &c
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Server::~Server()
|
||||
{
|
||||
m_server->close();
|
||||
|
|
|
@ -115,8 +115,9 @@ PackageDetailAvailability UserRepository::requestsRequired(PackageDetail package
|
|||
return PackageDetailAvailability::Request;
|
||||
case PackageDetail::Dependencies:
|
||||
case PackageDetail::SourceInfo:
|
||||
case PackageDetail::AllAvailable:
|
||||
return PackageDetailAvailability::FullRequest;
|
||||
case PackageDetail::PackageInfo:
|
||||
default:
|
||||
return PackageDetailAvailability::Never;
|
||||
}
|
||||
}
|
||||
|
@ -163,10 +164,21 @@ AurFullPackageReply *UserRepository::requestFullPackageInfo(const QStringList &p
|
|||
}
|
||||
}
|
||||
} catch(const out_of_range &) {
|
||||
replies << m_networkAccessManager.get(QNetworkRequest(m_aurSnapshotPath.arg(packageName)));
|
||||
if(forceUpdate) {
|
||||
replies << m_networkAccessManager.get(QNetworkRequest(m_aurSnapshotPath.arg(packageName)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return new AurFullPackageReply(replies, const_cast<UserRepository *>(this));
|
||||
if(replies.isEmpty()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return new AurFullPackageReply(replies, const_cast<UserRepository *>(this));
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<Package> UserRepository::emptyPackage()
|
||||
{
|
||||
return make_unique<AurPackage>(this);
|
||||
}
|
||||
|
||||
} // namespace Alpm
|
||||
|
|
|
@ -69,6 +69,9 @@ public:
|
|||
AurPackageReply *requestPackageInfo(const QStringList &packageNames, bool forceUpdate = false) const;
|
||||
AurFullPackageReply *requestFullPackageInfo(const QStringList &packageNames, bool forceUpdate = false) const;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<Package> emptyPackage();
|
||||
|
||||
private:
|
||||
QNetworkAccessManager &m_networkAccessManager;
|
||||
static QUrl m_aurRpcUrl;
|
||||
|
|
|
@ -47,6 +47,9 @@
|
|||
<li id="nav_settings"><a id="link_settings" href="#" aria-label="Settings" data-toggle="popover" data-placement="bottom" title="Settings" data-content="TODO"><span class="glyphicon glyphicon-wrench" aria-hidden="true"></span></a></li>
|
||||
<li id="nav_about"><a id="link_settings" href="#" onclick="$('#dlg_about').modal('show'); return false;"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span></a></li>
|
||||
</ul>
|
||||
<form class="navbar-form navbar-right">
|
||||
<button class="btn btn-danger" onclick="repoindex.alpmClient.stopServer();">Stop server</button>
|
||||
</form>
|
||||
<form class="navbar-form navbar-right">
|
||||
<button id="nav_connect" class="btn btn-danger" onclick="repoindex.alpmClient.init();"><span class="glyphicon glyphicon glyphicon-refresh" aria-hidden="true" id="connection_glyphicon"></span> <span id="connection_status">Disconnected</span></button>
|
||||
</form>
|
||||
|
|
|
@ -226,6 +226,14 @@
|
|||
this.scheduleRequest(repoindex.RequestType.GroupInfo, {updates: "true"}, callback);
|
||||
};
|
||||
|
||||
this.stopServer = function() {
|
||||
if(this.isOpen()) {
|
||||
this.socket.send(JSON.stringify({class: "cmd", what: "stop"}));
|
||||
} else {
|
||||
window.alert("Not connected to a server.");
|
||||
}
|
||||
};
|
||||
|
||||
this.checkForUpdates = function(dbName, syncdbNames, callback) {
|
||||
var params = {
|
||||
db: dbName
|
||||
|
|
|
@ -253,7 +253,7 @@
|
|||
if(updates[i1].entries[i2].pkg) {
|
||||
newEntry.applyBasicInfo(updates[i1].entries[i2].pkg, true);
|
||||
if(updates[i1].entries[i2].curVer) {
|
||||
newEntry.info.ver = updates[i1].entries[i2].prevVersion + " → " + (newEntry.info.ver ? newEntry.info.ver : "?");
|
||||
newEntry.info.ver = updates[i1].entries[i2].curVer + " → " + (newEntry.info.ver ? newEntry.info.ver : "?");
|
||||
}
|
||||
// find associated repo entry
|
||||
if((newEntry.repoEntry = repoMgr.entryByName(newEntry.info.repo))) {
|
||||
|
|
Loading…
Reference in New Issue