added previous version to update results; started to work on build order resolver and mingw-w64 installer
This commit is contained in:
parent
b42ef62cd6
commit
8f32dd0da0
|
@ -1,4 +1,5 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "manager.h"
|
||||||
|
|
||||||
#include <c++utilities/conversion/stringconversion.h>
|
#include <c++utilities/conversion/stringconversion.h>
|
||||||
|
|
||||||
|
@ -25,7 +26,9 @@ namespace PackageManagement {
|
||||||
*/
|
*/
|
||||||
ConfigArgs::ConfigArgs(ArgumentParser &parser) :
|
ConfigArgs::ConfigArgs(ArgumentParser &parser) :
|
||||||
helpArg(parser),
|
helpArg(parser),
|
||||||
|
buildOrderArg("build-order", "b", "calculates the build order to build the specified packages"),
|
||||||
serverArg("server", "s", "runs a websocket server providing the web interface with information"),
|
serverArg("server", "s", "runs a websocket server providing the web interface with information"),
|
||||||
|
mingwBundleArg("mingw-w64-bundle", "m", "creates an archive with the runtime-relevant files from the specified mingw-w64-packages and their dependencies"),
|
||||||
repoindexConfArg("repoindex-conf", "c", "specifies the path of the repo index config file (default is /etc/repoindex.conf"),
|
repoindexConfArg("repoindex-conf", "c", "specifies the path of the repo index config file (default is /etc/repoindex.conf"),
|
||||||
rootdirArg("root-dir", "r", "specifies the root directory (default is /)"),
|
rootdirArg("root-dir", "r", "specifies the root directory (default is /)"),
|
||||||
dbpathArg("db-path", "d", "specifies the pacman database path (default is /var/lib/pacman)"),
|
dbpathArg("db-path", "d", "specifies the pacman database path (default is /var/lib/pacman)"),
|
||||||
|
@ -34,10 +37,20 @@ ConfigArgs::ConfigArgs(ArgumentParser &parser) :
|
||||||
websocketPortArg("port", "p", "specifies the listening port for the websocket server, default is 1234"),
|
websocketPortArg("port", "p", "specifies the listening port for the websocket server, default is 1234"),
|
||||||
certFileArg("cert-file", string(), "specifies the SSL certificate"),
|
certFileArg("cert-file", string(), "specifies the SSL certificate"),
|
||||||
keyFileArg("key-file", string(), "specifies the private SSL key"),
|
keyFileArg("key-file", string(), "specifies the private SSL key"),
|
||||||
insecureArg("insecure", string(), "forces the server to run in insecure mode")
|
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")
|
||||||
{
|
{
|
||||||
initializer_list<string> pathValueName = {"path"};
|
const initializer_list<string> pathValueName = {"path"};
|
||||||
|
const initializer_list<string> pkgValueNames = {"package 1", "package 2", "package 3"};
|
||||||
|
buildOrderArg.setDenotesOperation(true);
|
||||||
|
buildOrderArg.setRequiredValueCount(-1);
|
||||||
|
buildOrderArg.setValueNames(pkgValueNames);
|
||||||
serverArg.setDenotesOperation(true);
|
serverArg.setDenotesOperation(true);
|
||||||
|
mingwBundleArg.setDenotesOperation(true);
|
||||||
|
mingwBundleArg.setRequiredValueCount(-1);
|
||||||
|
mingwBundleArg.setValueNames(pkgValueNames);
|
||||||
repoindexConfArg.setCombinable(true);
|
repoindexConfArg.setCombinable(true);
|
||||||
repoindexConfArg.setValueNames(pathValueName);
|
repoindexConfArg.setValueNames(pathValueName);
|
||||||
repoindexConfArg.setRequiredValueCount(1);
|
repoindexConfArg.setRequiredValueCount(1);
|
||||||
|
@ -63,8 +76,18 @@ ConfigArgs::ConfigArgs(ArgumentParser &parser) :
|
||||||
keyFileArg.setValueNames(pathValueName);
|
keyFileArg.setValueNames(pathValueName);
|
||||||
keyFileArg.setRequiredValueCount(1);
|
keyFileArg.setRequiredValueCount(1);
|
||||||
insecureArg.setCombinable(true);
|
insecureArg.setCombinable(true);
|
||||||
serverArg.setSecondaryArguments({&rootdirArg, &dbpathArg, &pacmanConfArg, &certFileArg, &keyFileArg, &insecureArg});
|
aurArg.setCombinable(true);
|
||||||
parser.setMainArguments({&serverArg, &repoindexConfArg, &helpArg});
|
aurArg.setRequiredValueCount(1);
|
||||||
|
aurArg.setValueNames({"enabled/disabled"});
|
||||||
|
verboseArg.setCombinable(true);
|
||||||
|
outputFileArg.setCombinable(true);
|
||||||
|
outputFileArg.setRequired(true);
|
||||||
|
outputFileArg.setRequiredValueCount(1);
|
||||||
|
outputFileArg.setValueNames({"path"});
|
||||||
|
serverArg.setSecondaryArguments({&rootdirArg, &dbpathArg, &pacmanConfArg, &certFileArg, &keyFileArg, &insecureArg, &aurArg});
|
||||||
|
buildOrderArg.setSecondaryArguments({&aurArg, &verboseArg});
|
||||||
|
mingwBundleArg.setSecondaryArguments({&outputFileArg});
|
||||||
|
parser.setMainArguments({&buildOrderArg, &serverArg, &mingwBundleArg, &repoindexConfArg, &repoindexConfArg, &helpArg});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -77,12 +100,15 @@ ConfigArgs::ConfigArgs(ArgumentParser &parser) :
|
||||||
*/
|
*/
|
||||||
Config::Config() :
|
Config::Config() :
|
||||||
m_alpmRootDir(QStringLiteral("/")),
|
m_alpmRootDir(QStringLiteral("/")),
|
||||||
m_alpmDbPath(QStringLiteral("/var/lib/pacman/")),
|
m_alpmDbPath(QStringLiteral("/var/lib/pacman")),
|
||||||
m_pacmanConfFile(QStringLiteral("/etc/pacman.conf")),
|
m_pacmanConfFile(QStringLiteral("/etc/pacman.conf")),
|
||||||
m_websocketServerListeningAddr(QHostAddress::LocalHost),
|
m_websocketServerListeningAddr(QHostAddress::LocalHost),
|
||||||
m_websocketServerListeningPort(1234),
|
m_websocketServerListeningPort(1234),
|
||||||
m_serverInsecure(false),
|
m_serverInsecure(false),
|
||||||
m_reposFromPacmanConf(false)
|
m_reposFromPacmanConf(false),
|
||||||
|
m_aurEnabled(true),
|
||||||
|
m_verbose(false),
|
||||||
|
m_runServer(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -150,6 +176,8 @@ void Config::loadFromConfigFile(const QString &configFilePath)
|
||||||
m_alpmRootDir = alpmObj.value(QStringLiteral("rootDir")).toString(m_alpmRootDir);
|
m_alpmRootDir = alpmObj.value(QStringLiteral("rootDir")).toString(m_alpmRootDir);
|
||||||
m_alpmDbPath = alpmObj.value(QStringLiteral("dbPath")).toString(m_alpmDbPath);
|
m_alpmDbPath = alpmObj.value(QStringLiteral("dbPath")).toString(m_alpmDbPath);
|
||||||
m_pacmanConfFile = alpmObj.value(QStringLiteral("pacmanConfigFile")).toString(m_pacmanConfFile);
|
m_pacmanConfFile = alpmObj.value(QStringLiteral("pacmanConfigFile")).toString(m_pacmanConfFile);
|
||||||
|
auto aurObj = mainObj.value(QStringLiteral("aur")).toObject();
|
||||||
|
m_aurEnabled = aurObj.value(QStringLiteral("enabled")).toBool(m_aurEnabled);
|
||||||
auto serverObj = mainObj.value(QStringLiteral("server")).toObject();
|
auto serverObj = mainObj.value(QStringLiteral("server")).toObject();
|
||||||
assign(m_websocketServerListeningAddr, serverObj.value(QStringLiteral("websocketListeningAddr")).toString());
|
assign(m_websocketServerListeningAddr, serverObj.value(QStringLiteral("websocketListeningAddr")).toString());
|
||||||
assign(m_websocketServerListeningPort, serverObj.value(QStringLiteral("websocketListeningPort")));
|
assign(m_websocketServerListeningPort, serverObj.value(QStringLiteral("websocketListeningPort")));
|
||||||
|
@ -164,7 +192,7 @@ void Config::loadFromConfigFile(const QString &configFilePath)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cerr << "Error: Unable to parse config file \"" << configFilePath.toLocal8Bit().data() << "\": "
|
cerr << "Error: Unable to parse config file \"" << configFilePath.toLocal8Bit().data() << "\": "
|
||||||
<< error.errorString().toLocal8Bit().data() << endl;
|
<< error.errorString().toLocal8Bit().data() << " at character " << error.offset << endl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cerr << "Error: Unable to open config file \"" << configFilePath.toLocal8Bit().data() << "\"." << endl;
|
cerr << "Error: Unable to open config file \"" << configFilePath.toLocal8Bit().data() << "\"." << endl;
|
||||||
|
@ -200,6 +228,16 @@ void Config::loadFromArgs(const ConfigArgs &args)
|
||||||
assign(m_alpmRootDir, args.rootdirArg);
|
assign(m_alpmRootDir, args.rootdirArg);
|
||||||
assign(m_alpmDbPath, args.dbpathArg);
|
assign(m_alpmDbPath, args.dbpathArg);
|
||||||
assign(m_pacmanConfFile, args.pacmanConfArg);
|
assign(m_pacmanConfFile, args.pacmanConfArg);
|
||||||
|
if(args.aurArg.isPresent()) {
|
||||||
|
auto val = args.aurArg.values().front();
|
||||||
|
if(val == "enabled") {
|
||||||
|
m_aurEnabled = true;
|
||||||
|
} else if(val == "disabled") {
|
||||||
|
m_aurEnabled = false;
|
||||||
|
} else {
|
||||||
|
cerr << "Warning: The specified value for the argument --aur-enabled is invalid and will be ignored." << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
assign(m_websocketServerListeningPort, args.websocketPortArg);
|
assign(m_websocketServerListeningPort, args.websocketPortArg);
|
||||||
assign(m_serverCertFile, args.certFileArg);
|
assign(m_serverCertFile, args.certFileArg);
|
||||||
assign(m_serverKeyFile, args.keyFileArg);
|
assign(m_serverKeyFile, args.keyFileArg);
|
||||||
|
@ -207,6 +245,8 @@ void Config::loadFromArgs(const ConfigArgs &args)
|
||||||
if(args.websocketAddrArg.isPresent()) {
|
if(args.websocketAddrArg.isPresent()) {
|
||||||
assign(m_websocketServerListeningAddr, QString::fromLocal8Bit(args.websocketAddrArg.values().front().data(), args.websocketAddrArg.values().front().size()));
|
assign(m_websocketServerListeningAddr, QString::fromLocal8Bit(args.websocketAddrArg.values().front().data(), args.websocketAddrArg.values().front().size()));
|
||||||
}
|
}
|
||||||
|
m_verbose = args.verboseArg.isPresent();
|
||||||
|
m_runServer = args.serverArg.isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -216,15 +256,22 @@ void RepoEntry::load(const QJsonValue &jsonValue)
|
||||||
{
|
{
|
||||||
auto obj = jsonValue.toObject();
|
auto obj = jsonValue.toObject();
|
||||||
m_name = obj.value(QStringLiteral("name")).toString(m_name);
|
m_name = obj.value(QStringLiteral("name")).toString(m_name);
|
||||||
m_dbPath = obj.value(QStringLiteral("dbpath")).toString(m_dbPath);
|
m_dataBaseFile = obj.value(QStringLiteral("dataBaseFile")).toString(m_dataBaseFile);
|
||||||
m_srcPath = obj.value(QStringLiteral("srcpath")).toString(m_srcPath);
|
m_sourceDir = obj.value(QStringLiteral("sourcesDir")).toString(m_sourceDir);
|
||||||
m_pkgPath = obj.value(QStringLiteral("pkgpath")).toString(m_pkgPath);
|
m_packageDir = obj.value(QStringLiteral("packagesDir")).toString(m_packageDir);
|
||||||
for(const auto &server : obj.value(QStringLiteral("servers")).toArray()) {
|
for(const auto &server : obj.value(QStringLiteral("servers")).toArray()) {
|
||||||
auto str = server.toString();
|
auto str = server.toString();
|
||||||
if(!str.isEmpty()) {
|
if(!str.isEmpty()) {
|
||||||
m_servers << str;
|
m_servers << str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for(const auto &upgradeSources : obj.value(QStringLiteral("upgradeSources")).toArray()) {
|
||||||
|
auto str = upgradeSources.toString();
|
||||||
|
if(!str.isEmpty()) {
|
||||||
|
m_upgradeSources << str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_sigLevel = Manager::parseSigLevel(obj.value(QStringLiteral("sigLevel")).toString().toLocal8Bit().data());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Alpm
|
} // namespace Alpm
|
||||||
|
|
|
@ -18,7 +18,9 @@ class ConfigArgs
|
||||||
public:
|
public:
|
||||||
ConfigArgs(ApplicationUtilities::ArgumentParser &parser);
|
ConfigArgs(ApplicationUtilities::ArgumentParser &parser);
|
||||||
ApplicationUtilities::HelpArgument helpArg;
|
ApplicationUtilities::HelpArgument helpArg;
|
||||||
|
ApplicationUtilities::Argument buildOrderArg;
|
||||||
ApplicationUtilities::Argument serverArg;
|
ApplicationUtilities::Argument serverArg;
|
||||||
|
ApplicationUtilities::Argument mingwBundleArg;
|
||||||
ApplicationUtilities::Argument repoindexConfArg;
|
ApplicationUtilities::Argument repoindexConfArg;
|
||||||
ApplicationUtilities::Argument rootdirArg;
|
ApplicationUtilities::Argument rootdirArg;
|
||||||
ApplicationUtilities::Argument dbpathArg;
|
ApplicationUtilities::Argument dbpathArg;
|
||||||
|
@ -28,6 +30,9 @@ public:
|
||||||
ApplicationUtilities::Argument certFileArg;
|
ApplicationUtilities::Argument certFileArg;
|
||||||
ApplicationUtilities::Argument keyFileArg;
|
ApplicationUtilities::Argument keyFileArg;
|
||||||
ApplicationUtilities::Argument insecureArg;
|
ApplicationUtilities::Argument insecureArg;
|
||||||
|
ApplicationUtilities::Argument aurArg;
|
||||||
|
ApplicationUtilities::Argument verboseArg;
|
||||||
|
ApplicationUtilities::Argument outputFileArg;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Config;
|
class Config;
|
||||||
|
@ -36,39 +41,48 @@ class RepoEntry
|
||||||
{
|
{
|
||||||
friend class Config;
|
friend class Config;
|
||||||
public:
|
public:
|
||||||
|
RepoEntry();
|
||||||
const QString &name() const;
|
const QString &name() const;
|
||||||
const QString &dbPath() const;
|
const QString &dataBasePath() const;
|
||||||
const QString &srcPath() const;
|
const QString &sourceDir() const;
|
||||||
const QString &pkgPath() const;
|
const QString &packageDir() const;
|
||||||
const QStringList &servers() const;
|
const QStringList &servers() const;
|
||||||
|
const QStringList &upgradeSources() const;
|
||||||
|
int sigLevel() const;
|
||||||
void load(const QJsonValue &jsonValue);
|
void load(const QJsonValue &jsonValue);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_name;
|
QString m_name;
|
||||||
QString m_dbPath;
|
QString m_dataBaseFile;
|
||||||
QString m_srcPath;
|
QString m_sourceDir;
|
||||||
QString m_pkgPath;
|
QString m_packageDir;
|
||||||
QStringList m_servers;
|
QStringList m_servers;
|
||||||
|
QStringList m_upgradeSources;
|
||||||
|
int m_sigLevel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline RepoEntry::RepoEntry() :
|
||||||
|
m_sigLevel(0)
|
||||||
|
{}
|
||||||
|
|
||||||
inline const QString &RepoEntry::name() const
|
inline const QString &RepoEntry::name() const
|
||||||
{
|
{
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const QString &RepoEntry::dbPath() const
|
inline const QString &RepoEntry::dataBasePath() const
|
||||||
{
|
{
|
||||||
return m_dbPath;
|
return m_dataBaseFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const QString &RepoEntry::srcPath() const
|
inline const QString &RepoEntry::sourceDir() const
|
||||||
{
|
{
|
||||||
return m_srcPath;
|
return m_sourceDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const QString &RepoEntry::pkgPath() const
|
inline const QString &RepoEntry::packageDir() const
|
||||||
{
|
{
|
||||||
return m_pkgPath;
|
return m_packageDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const QStringList &RepoEntry::servers() const
|
inline const QStringList &RepoEntry::servers() const
|
||||||
|
@ -76,6 +90,16 @@ inline const QStringList &RepoEntry::servers() const
|
||||||
return m_servers;
|
return m_servers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const QStringList &RepoEntry::upgradeSources() const
|
||||||
|
{
|
||||||
|
return m_upgradeSources;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int RepoEntry::sigLevel() const
|
||||||
|
{
|
||||||
|
return m_sigLevel;
|
||||||
|
}
|
||||||
|
|
||||||
class Config
|
class Config
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -91,6 +115,9 @@ public:
|
||||||
bool serverInsecure() const;
|
bool serverInsecure() const;
|
||||||
bool reposFromPacmanConf() const;
|
bool reposFromPacmanConf() const;
|
||||||
const QList<RepoEntry> &repoEntries() const;
|
const QList<RepoEntry> &repoEntries() const;
|
||||||
|
bool isAurEnabled() const;
|
||||||
|
bool isVerbose() const;
|
||||||
|
bool runServer() const;
|
||||||
|
|
||||||
void loadFromConfigFile(const QString &args);
|
void loadFromConfigFile(const QString &args);
|
||||||
void loadFromConfigFile(const ConfigArgs &args);
|
void loadFromConfigFile(const ConfigArgs &args);
|
||||||
|
@ -107,9 +134,11 @@ private:
|
||||||
QString m_serverKeyFile;
|
QString m_serverKeyFile;
|
||||||
bool m_serverInsecure;
|
bool m_serverInsecure;
|
||||||
|
|
||||||
bool m_reposFromPacmanConf;
|
|
||||||
QList<RepoEntry> m_repoEntries;
|
QList<RepoEntry> m_repoEntries;
|
||||||
|
bool m_reposFromPacmanConf;
|
||||||
|
bool m_aurEnabled;
|
||||||
|
bool m_verbose;
|
||||||
|
bool m_runServer;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const QString &Config::alpmRootDir() const
|
inline const QString &Config::alpmRootDir() const
|
||||||
|
@ -162,6 +191,21 @@ inline const QList<RepoEntry> &Config::repoEntries() const
|
||||||
return m_repoEntries;
|
return m_repoEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool Config::isAurEnabled() const
|
||||||
|
{
|
||||||
|
return m_aurEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Config::isVerbose() const
|
||||||
|
{
|
||||||
|
return m_verbose;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Config::runServer() const
|
||||||
|
{
|
||||||
|
return m_runServer;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Alpm
|
} // namespace Alpm
|
||||||
|
|
||||||
#endif // ALPM_CONFIG_H
|
#endif // ALPM_CONFIG_H
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
#include "group.h"
|
#include "group.h"
|
||||||
|
#include "updatelookup.h"
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
@ -38,6 +39,20 @@ const QJsonArray &AlpmDataBase::serverUrls() const
|
||||||
return m_serverUrls;
|
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.
|
* \brief Returns the packages of the database.
|
||||||
*/
|
*/
|
||||||
|
@ -95,7 +110,7 @@ QJsonObject AlpmDataBase::groupInfo() const
|
||||||
return groupInfo;
|
return groupInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlpmDataBase::checkForUpgrades(const QList<const AlpmDataBase *> &syncDbs, UpdateLookupResults &results) const
|
void AlpmDataBase::checkForUpgrades(const QList<const AlpmDataBase *> &syncDbs, UpdateLookupResults<AlpmPackage> &results) const
|
||||||
{
|
{
|
||||||
if(syncDbs.isEmpty()) {
|
if(syncDbs.isEmpty()) {
|
||||||
results.noSources = true;
|
results.noSources = true;
|
||||||
|
@ -110,13 +125,13 @@ void AlpmDataBase::checkForUpgrades(const QList<const AlpmDataBase *> &syncDbs,
|
||||||
case PackageVersionComparsion::Equal:
|
case PackageVersionComparsion::Equal:
|
||||||
break; // ignore equal packages
|
break; // ignore equal packages
|
||||||
case PackageVersionComparsion::SoftwareUpgrade:
|
case PackageVersionComparsion::SoftwareUpgrade:
|
||||||
results.newVersions << syncPkg;
|
results.newVersions << makeUpdateResult(syncPkg, dbPkg.second.version());
|
||||||
break;
|
break;
|
||||||
case PackageVersionComparsion::PackageUpgradeOnly:
|
case PackageVersionComparsion::PackageUpgradeOnly:
|
||||||
results.newReleases << syncPkg;
|
results.newReleases << makeUpdateResult(syncPkg, dbPkg.second.version());
|
||||||
break;
|
break;
|
||||||
case PackageVersionComparsion::NewerThenSyncVersion:
|
case PackageVersionComparsion::NewerThenSyncVersion:
|
||||||
results.downgrades << syncPkg;
|
results.downgrades << makeUpdateResult(syncPkg, dbPkg.second.version());
|
||||||
}
|
}
|
||||||
orphaned = false;
|
orphaned = false;
|
||||||
} catch(out_of_range &) {
|
} catch(out_of_range &) {
|
||||||
|
|
139
alpm/database.h
139
alpm/database.h
|
@ -2,7 +2,7 @@
|
||||||
#define ALPM_DATABASE_H
|
#define ALPM_DATABASE_H
|
||||||
|
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "package.h"
|
#include "updatelookup.h"
|
||||||
|
|
||||||
#include <alpm.h>
|
#include <alpm.h>
|
||||||
|
|
||||||
|
@ -13,51 +13,10 @@
|
||||||
|
|
||||||
namespace PackageManagement {
|
namespace PackageManagement {
|
||||||
|
|
||||||
class UpdateLookupResults
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
UpdateLookupResults();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Indicates that there are no upgrade sources available.
|
|
||||||
*/
|
|
||||||
bool noSources;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Packages providing a software upgrade (new version).
|
|
||||||
*/
|
|
||||||
QList<AlpmPackage> newVersions;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Package upgrades only (new release).
|
|
||||||
*/
|
|
||||||
QList<AlpmPackage> newReleases;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Downgrades (older version in sync db).
|
|
||||||
*/
|
|
||||||
QList<AlpmPackage> downgrades;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Orphaned packages (could not be found in any of the sync dbs).
|
|
||||||
*/
|
|
||||||
QList<AlpmPackage> orphaned;
|
|
||||||
|
|
||||||
QStringList warnings;
|
|
||||||
QStringList errors;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Constructs new update lookup results.
|
|
||||||
*/
|
|
||||||
inline UpdateLookupResults::UpdateLookupResults() :
|
|
||||||
noSources(false)
|
|
||||||
{}
|
|
||||||
|
|
||||||
class AlpmDataBase
|
class AlpmDataBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AlpmDataBase(alpm_db_t *dataBase = nullptr);
|
AlpmDataBase(alpm_db_t *dataBase = nullptr, const QString &dbFile = QString(), const QString &srcDir = QString(), const QString &pkgDir = QString());
|
||||||
|
|
||||||
// operators
|
// operators
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
|
@ -67,11 +26,17 @@ public:
|
||||||
// database properties
|
// database properties
|
||||||
alpm_db_t *ptr() const;
|
alpm_db_t *ptr() const;
|
||||||
const char *name() 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_siglevel_t sigLevel() const;
|
||||||
alpm_db_usage_t usage() const;
|
alpm_db_usage_t usage() const;
|
||||||
StringList servers() const;
|
StringList servers() const;
|
||||||
const QJsonArray &serverUrls() const;
|
|
||||||
bool setServers(StringList servers);
|
bool setServers(StringList servers);
|
||||||
|
const QJsonArray &serverUrls() const;
|
||||||
|
bool addServerUrls(const QStringList &urls);
|
||||||
alpm_pkg_t *package(const char *name) const;
|
alpm_pkg_t *package(const char *name) const;
|
||||||
const std::map<QString, AlpmPackage> &packages() const;
|
const std::map<QString, AlpmPackage> &packages() const;
|
||||||
QStringList packageNames() const;
|
QStringList packageNames() const;
|
||||||
|
@ -84,11 +49,16 @@ public:
|
||||||
// upgrade lookup
|
// upgrade lookup
|
||||||
const QStringList &upgradeSources() const;
|
const QStringList &upgradeSources() const;
|
||||||
QStringList &upgradeSources();
|
QStringList &upgradeSources();
|
||||||
void checkForUpgrades(const QList<const AlpmDataBase *> &syncDbs, UpdateLookupResults &results) const;
|
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:
|
private:
|
||||||
alpm_db_t *m_ptr;
|
alpm_db_t *m_ptr;
|
||||||
QStringList m_updateSources;
|
QString m_dbFile;
|
||||||
|
QString m_srcDir;
|
||||||
|
QString m_pkgDir;
|
||||||
|
QStringList m_upgradeSources;
|
||||||
mutable QJsonArray m_serverUrls;
|
mutable QJsonArray m_serverUrls;
|
||||||
mutable std::map<QString, AlpmPackage> m_packages;
|
mutable std::map<QString, AlpmPackage> m_packages;
|
||||||
mutable QJsonArray m_packageNamesJsonArray;
|
mutable QJsonArray m_packageNamesJsonArray;
|
||||||
|
@ -98,8 +68,11 @@ private:
|
||||||
/*!
|
/*!
|
||||||
* \brief Creates a new instance wrapping the specified database struct.
|
* \brief Creates a new instance wrapping the specified database struct.
|
||||||
*/
|
*/
|
||||||
inline AlpmDataBase::AlpmDataBase(alpm_db_t *dataBase) :
|
inline AlpmDataBase::AlpmDataBase(alpm_db_t *dataBase, const QString &dbFile, const QString &srcDir, const QString &pkgDir) :
|
||||||
m_ptr(dataBase)
|
m_ptr(dataBase),
|
||||||
|
m_dbFile(dbFile),
|
||||||
|
m_srcDir(srcDir),
|
||||||
|
m_pkgDir(pkgDir)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -134,6 +107,46 @@ inline const char *AlpmDataBase::name() const
|
||||||
return alpm_db_get_name(m_ptr);
|
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.
|
* \brief Returns the signature level of the database.
|
||||||
*/
|
*/
|
||||||
|
@ -155,7 +168,7 @@ inline StringList AlpmDataBase::servers() const
|
||||||
*/
|
*/
|
||||||
inline bool AlpmDataBase::setServers(StringList servers)
|
inline bool AlpmDataBase::setServers(StringList servers)
|
||||||
{
|
{
|
||||||
return alpm_db_set_servers(m_ptr, servers.begin().ptr()) != 0;
|
return alpm_db_set_servers(m_ptr, servers.begin().ptr()) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -195,7 +208,7 @@ inline PackageList AlpmDataBase::search(StringList terms) const
|
||||||
*/
|
*/
|
||||||
inline const QStringList &AlpmDataBase::upgradeSources() const
|
inline const QStringList &AlpmDataBase::upgradeSources() const
|
||||||
{
|
{
|
||||||
return m_updateSources;
|
return m_upgradeSources;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -203,7 +216,7 @@ inline const QStringList &AlpmDataBase::upgradeSources() const
|
||||||
*/
|
*/
|
||||||
inline QStringList &AlpmDataBase::upgradeSources()
|
inline QStringList &AlpmDataBase::upgradeSources()
|
||||||
{
|
{
|
||||||
return m_updateSources;
|
return m_upgradeSources;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -214,6 +227,30 @@ inline PackageManagement::AlpmDataBase::operator bool() const
|
||||||
return m_ptr != nullptr;
|
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
|
} // namespace Alpm
|
||||||
|
|
||||||
#endif // ALPM_DATABASE_H
|
#endif // ALPM_DATABASE_H
|
||||||
|
|
226
alpm/manager.cpp
226
alpm/manager.cpp
|
@ -8,10 +8,9 @@
|
||||||
#include <c++utilities/conversion/stringconversion.h>
|
#include <c++utilities/conversion/stringconversion.h>
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QSysInfo>
|
#include <QSysInfo>
|
||||||
#include <QtConcurrent/QtConcurrent>
|
#include <QtConcurrent/QtConcurrent>
|
||||||
|
#include <QMutexLocker>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
@ -38,8 +37,7 @@ constexpr int defaultSigLevel = ALPM_SIG_PACKAGE | ALPM_SIG_PACKAGE_OPTIONAL |
|
||||||
* \param rootdir Specifies the root directory.
|
* \param rootdir Specifies the root directory.
|
||||||
* \param dbpath Specifies the database directory.
|
* \param dbpath Specifies the database directory.
|
||||||
*/
|
*/
|
||||||
Manager::Manager(const Config &config, QObject *parent) :
|
Manager::Manager(const Config &config) :
|
||||||
QObject(parent),
|
|
||||||
m_config(config),
|
m_config(config),
|
||||||
m_sigLevel(defaultSigLevel),
|
m_sigLevel(defaultSigLevel),
|
||||||
m_localFileSigLevel(ALPM_SIG_USE_DEFAULT),
|
m_localFileSigLevel(ALPM_SIG_USE_DEFAULT),
|
||||||
|
@ -62,7 +60,7 @@ Manager::~Manager()
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the package with the specified name from the specified database.
|
* \brief Returns the package with the specified name from the specified database.
|
||||||
*/
|
*/
|
||||||
AlpmPackage Manager::packageFromSyncDataBase(const QString &dbName, const QString &pkgName)
|
AlpmPackage Manager::packageFromSyncDataBase(const QString &dbName, const QString &pkgName) const
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if(dbName == QLatin1String("local")) {
|
if(dbName == QLatin1String("local")) {
|
||||||
|
@ -115,7 +113,7 @@ const string &lastValue(const multimap<string, string> &mm, const string &key)
|
||||||
/*!
|
/*!
|
||||||
* \brief Parses a "SigLevel" denotation from pacman config file.
|
* \brief Parses a "SigLevel" denotation from pacman config file.
|
||||||
*/
|
*/
|
||||||
int parseSigLevel(const string &sigLevelStr = string())
|
int Manager::parseSigLevel(const string &sigLevelStr)
|
||||||
{
|
{
|
||||||
int sigLevel = defaultSigLevel;
|
int sigLevel = defaultSigLevel;
|
||||||
// split sig level denotation into parts
|
// split sig level denotation into parts
|
||||||
|
@ -179,7 +177,7 @@ int parseSigLevel(const string &sigLevelStr = string())
|
||||||
/*!
|
/*!
|
||||||
* \brief Parses a "Usage" denotation from pacman config file.
|
* \brief Parses a "Usage" denotation from pacman config file.
|
||||||
*/
|
*/
|
||||||
int parseUsage(const string &usageStr)
|
int Manager::parseUsage(const string &usageStr)
|
||||||
{
|
{
|
||||||
int usage = 0;
|
int usage = 0;
|
||||||
const auto parts = splitString<list<string> >(usageStr, " ");
|
const auto parts = splitString<list<string> >(usageStr, " ");
|
||||||
|
@ -200,9 +198,9 @@ int parseUsage(const string &usageStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Parses the Pacman configuration. Registers the listed sync databases.
|
* \brief Parses and applies the Pacman configuration. Registers the listed sync databases.
|
||||||
*/
|
*/
|
||||||
void Manager::parsePacmanConfig()
|
void Manager::applyPacmanConfig()
|
||||||
{
|
{
|
||||||
// open config file and parse as ini
|
// open config file and parse as ini
|
||||||
try {
|
try {
|
||||||
|
@ -229,7 +227,7 @@ void Manager::parsePacmanConfig()
|
||||||
}
|
}
|
||||||
const auto &specifiedDir = lastValue(options, "CacheDir");
|
const auto &specifiedDir = lastValue(options, "CacheDir");
|
||||||
if(!specifiedDir.empty()) {
|
if(!specifiedDir.empty()) {
|
||||||
m_cacheDir = QString::fromStdString(specifiedDir);
|
m_pacmanCacheDir = QString::fromStdString(specifiedDir);
|
||||||
}
|
}
|
||||||
globalSigLevel = parseSigLevel(lastValue(options, sigLevelKey));
|
globalSigLevel = parseSigLevel(lastValue(options, sigLevelKey));
|
||||||
} catch(const out_of_range &) {
|
} catch(const out_of_range &) {
|
||||||
|
@ -242,9 +240,9 @@ void Manager::parsePacmanConfig()
|
||||||
if(scope.first != "options") {
|
if(scope.first != "options") {
|
||||||
// read and validate database name
|
// read and validate database name
|
||||||
QString dbName = QString::fromLocal8Bit(scope.first.c_str());
|
QString dbName = QString::fromLocal8Bit(scope.first.c_str());
|
||||||
if(dbName == QLatin1String("local")) {
|
if(dbName.compare(QLatin1String("local"), Qt::CaseInsensitive) == 0) {
|
||||||
cerr << "Error: Unable to add database from pacman config: The database name mustn't be \"local\" because this name is reserved for the local database." << endl;
|
cerr << "Error: Unable to add database from pacman config: The database name mustn't be \"local\" because this name is reserved for the local database." << endl;
|
||||||
} else if(dbName.startsWith(QLatin1String("aur"))) {
|
} else if(dbName.startsWith(QLatin1String("aur"), Qt::CaseInsensitive)) {
|
||||||
cerr << "Error: Unable to add database from pacman config: The database name mustn't start with \"aur\" because this name is reserved for the Arch Linux User Repository." << endl;
|
cerr << "Error: Unable to add database from pacman config: The database name mustn't start with \"aur\" because this name is reserved for the Arch Linux User Repository." << endl;
|
||||||
} else if(m_syncDbs.count(dbName)) {
|
} else if(m_syncDbs.count(dbName)) {
|
||||||
cerr << "Error: Unable to add database from pacman config: Database names must be unique. Ignoring second occurance of database \"" << scope.first << "\"." << endl;
|
cerr << "Error: Unable to add database from pacman config: Database names must be unique. Ignoring second occurance of database \"" << scope.first << "\"." << endl;
|
||||||
|
@ -257,9 +255,13 @@ void Manager::parsePacmanConfig()
|
||||||
if(alpm_db_t *db = alpm_register_syncdb(m_handle, scope.first.c_str(), static_cast<alpm_siglevel_t>(sigLevel))) {
|
if(alpm_db_t *db = alpm_register_syncdb(m_handle, scope.first.c_str(), static_cast<alpm_siglevel_t>(sigLevel))) {
|
||||||
// set usage
|
// set usage
|
||||||
if(alpm_db_set_usage(db, static_cast<alpm_db_usage_t>(usage)) == 0) {
|
if(alpm_db_set_usage(db, static_cast<alpm_db_usage_t>(usage)) == 0) {
|
||||||
cerr << "Added database [" << scope.first << "]" << endl;
|
if(m_config.isVerbose() || m_config.runServer()) {
|
||||||
|
cerr << "Added database [" << scope.first << "]" << endl;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cerr << "Warning: Added database [" << scope.first << "] but failed to set usage" << endl;
|
if(m_config.isVerbose() || m_config.runServer()) {
|
||||||
|
cerr << "Warning: Added database [" << scope.first << "] but failed to set usage" << endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// add servers
|
// add servers
|
||||||
for(auto range = scope.second.equal_range("Server"); range.first != range.second; ++range.first) {
|
for(auto range = scope.second.equal_range("Server"); range.first != range.second; ++range.first) {
|
||||||
|
@ -267,7 +269,9 @@ void Manager::parsePacmanConfig()
|
||||||
findAndReplace<string>(url, "$repo", scope.first);
|
findAndReplace<string>(url, "$repo", scope.first);
|
||||||
findAndReplace<string>(url, "$arch", arch);
|
findAndReplace<string>(url, "$arch", arch);
|
||||||
alpm_db_add_server(db, url.c_str());
|
alpm_db_add_server(db, url.c_str());
|
||||||
cerr << "Added server: " << url << endl;
|
if(m_config.isVerbose() || m_config.runServer()) {
|
||||||
|
cerr << "Added server: " << url << endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// add included servers
|
// add included servers
|
||||||
for(auto range = scope.second.equal_range("Include"); range.first != range.second; ++range.first) {
|
for(auto range = scope.second.equal_range("Include"); range.first != range.second; ++range.first) {
|
||||||
|
@ -290,7 +294,9 @@ void Manager::parsePacmanConfig()
|
||||||
findAndReplace<string>(url, "$repo", scope.first);
|
findAndReplace<string>(url, "$repo", scope.first);
|
||||||
findAndReplace<string>(url, "$arch", arch);
|
findAndReplace<string>(url, "$arch", arch);
|
||||||
alpm_db_add_server(db, url.c_str());
|
alpm_db_add_server(db, url.c_str());
|
||||||
cerr << "Added server: " << url << endl;
|
if(m_config.isVerbose() || m_config.runServer()) {
|
||||||
|
cerr << "Added server: " << url << endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (const out_of_range &) {
|
} catch (const out_of_range &) {
|
||||||
cerr << "Warning: Included file \"" << path << "\" has no values." << endl;
|
cerr << "Warning: Included file \"" << path << "\" has no values." << endl;
|
||||||
|
@ -301,15 +307,58 @@ void Manager::parsePacmanConfig()
|
||||||
// -> db is used to upgrade local database
|
// -> db is used to upgrade local database
|
||||||
localDataBase().upgradeSources() << dbName;
|
localDataBase().upgradeSources() << dbName;
|
||||||
}
|
}
|
||||||
m_syncDbs.emplace(dbName, db);
|
m_syncDbs.emplace(dbName, AlpmDataBase(db, QStringLiteral("%1/sync/%2").arg(m_config.alpmDbPath(), dbName)));
|
||||||
} else {
|
} else {
|
||||||
cerr << "Unable to add sync database [" << scope.first << "]" << endl;
|
cerr << "Error: Unable to add sync database [" << scope.first << "]" << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (const ios_base::failure &) {
|
} catch (const ios_base::failure &) {
|
||||||
throw ios_base::failure("An IO exception occured when parsing the config file.");
|
throw ios_base::failure("Error: An IO exception occured when parsing the config file.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Applies the repository index configuration.
|
||||||
|
*/
|
||||||
|
void Manager::applyRepoIndexConfig()
|
||||||
|
{
|
||||||
|
for(const RepoEntry &repoEntry : m_config.repoEntries()) {
|
||||||
|
AlpmDataBase *syncDb;
|
||||||
|
try {
|
||||||
|
syncDb = &m_syncDbs.at(repoEntry.name());
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
syncDb->setPackagesDirectory(repoEntry.packageDir());
|
||||||
|
syncDb->setSourcesDirectory(repoEntry.sourceDir());
|
||||||
|
} catch(const out_of_range &) {
|
||||||
|
if(repoEntry.name().compare(QLatin1String("local"), Qt::CaseInsensitive) == 0) {
|
||||||
|
cerr << "Error: Unable to add database from repo index config: The database name mustn't be \"local\" because this name is reserved for the local database." << endl;
|
||||||
|
} 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 {
|
||||||
|
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()));
|
||||||
|
if(emplaced.second) {
|
||||||
|
syncDb = &emplaced.first->second;
|
||||||
|
if(m_config.isVerbose() || m_config.runServer()) {
|
||||||
|
cerr << "Added database [" << repoEntry.name().toLocal8Bit().data() << "]" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(syncDb) {
|
||||||
|
syncDb->addServerUrls(repoEntry.servers());
|
||||||
|
syncDb->upgradeSources() << repoEntry.upgradeSources();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +378,10 @@ void Manager::unregisterSyncDataBases()
|
||||||
const AlpmDataBase &Manager::localDataBase() const
|
const AlpmDataBase &Manager::localDataBase() const
|
||||||
{
|
{
|
||||||
if(!m_localDb) {
|
if(!m_localDb) {
|
||||||
m_localDb = alpm_get_localdb(m_handle);
|
QMutexLocker locker(&m_localDbMutex);
|
||||||
|
if(!m_localDb) {
|
||||||
|
m_localDb = alpm_get_localdb(m_handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return m_localDb;
|
return m_localDb;
|
||||||
}
|
}
|
||||||
|
@ -365,6 +417,7 @@ QJsonObject Manager::basicRepoInfo(AlpmDataBase db, const QString &name, const Q
|
||||||
repoInfo.insert(QStringLiteral("servers"), db.serverUrls());
|
repoInfo.insert(QStringLiteral("servers"), db.serverUrls());
|
||||||
repoInfo.insert(QStringLiteral("usage"), Utilities::usageStrings(db.usage()));
|
repoInfo.insert(QStringLiteral("usage"), Utilities::usageStrings(db.usage()));
|
||||||
repoInfo.insert(QStringLiteral("sigLevel"), Utilities::sigLevelStrings(db.sigLevel()));
|
repoInfo.insert(QStringLiteral("sigLevel"), Utilities::sigLevelStrings(db.sigLevel()));
|
||||||
|
repoInfo.insert(QStringLiteral("upgradeSources"), QJsonArray::fromStringList(db.upgradeSources()));
|
||||||
repoInfo.insert(QStringLiteral("packages"), db.packageNameJsonArray());
|
repoInfo.insert(QStringLiteral("packages"), db.packageNameJsonArray());
|
||||||
return repoInfo;
|
return repoInfo;
|
||||||
}
|
}
|
||||||
|
@ -378,15 +431,18 @@ QJsonObject Manager::basicRepoInfo(AlpmDataBase db, const QString &name, const Q
|
||||||
const QJsonArray &Manager::basicRepoInfo() const
|
const QJsonArray &Manager::basicRepoInfo() const
|
||||||
{
|
{
|
||||||
if(m_basicRepoInfo.isEmpty()) {
|
if(m_basicRepoInfo.isEmpty()) {
|
||||||
m_basicRepoInfo << basicRepoInfo(localDataBase(), QStringLiteral("local"), QStringLiteral("The local database."));
|
QMutexLocker locker(&m_basicRepoInfoMutex);
|
||||||
auto const &syncDbs = syncDataBases();
|
if(m_basicRepoInfo.isEmpty()) {
|
||||||
for(const auto &syncDb : syncDbs) {
|
m_basicRepoInfo << basicRepoInfo(localDataBase(), QStringLiteral("local"), QStringLiteral("The local database."));
|
||||||
// check if the "sync" database is actually used for syncing
|
auto const &syncDbs = syncDataBases();
|
||||||
auto usage = syncDb.second.usage();
|
for(const auto &syncDb : syncDbs) {
|
||||||
if((usage & ALPM_DB_USAGE_SYNC) || (usage & ALPM_DB_USAGE_INSTALL) || (usage & ALPM_DB_USAGE_UPGRADE)) {
|
// check if the "sync" database is actually used for syncing
|
||||||
m_basicRepoInfo << basicRepoInfo(syncDb.second, syncDb.first, QStringLiteral("The sync database »%1«.").arg(syncDb.first));
|
auto usage = syncDb.second.usage();
|
||||||
} else {
|
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 database »%1«.").arg(syncDb.first));
|
m_basicRepoInfo << basicRepoInfo(syncDb.second, syncDb.first, QStringLiteral("The sync database »%1«.").arg(syncDb.first));
|
||||||
|
} else {
|
||||||
|
m_basicRepoInfo << basicRepoInfo(syncDb.second, syncDb.first, QStringLiteral("The database »%1«.").arg(syncDb.first));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,7 +452,7 @@ const QJsonArray &Manager::basicRepoInfo() const
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns package information for the specified selection of packages.
|
* \brief Returns package information for the specified selection of packages.
|
||||||
*/
|
*/
|
||||||
const QJsonArray Manager::packageInfo(const QJsonArray &pkgSelection, bool full)
|
const QJsonArray Manager::packageInfo(const QJsonArray &pkgSelection, bool full) const
|
||||||
{
|
{
|
||||||
QJsonArray pkgInfos;
|
QJsonArray pkgInfos;
|
||||||
for(const auto &pkgSelJsonVal : pkgSelection) {
|
for(const auto &pkgSelJsonVal : pkgSelection) {
|
||||||
|
@ -426,9 +482,12 @@ const QJsonArray Manager::packageInfo(const QJsonArray &pkgSelection, bool full)
|
||||||
const QJsonArray &Manager::groupInfo() const
|
const QJsonArray &Manager::groupInfo() const
|
||||||
{
|
{
|
||||||
if(m_groupInfo.empty()) {
|
if(m_groupInfo.empty()) {
|
||||||
m_groupInfo << localDataBase().groupInfo();
|
QMutexLocker locker(&m_groupInfoMutex);
|
||||||
for(const auto &db : m_syncDbs) {
|
if(m_groupInfo.empty()) {
|
||||||
m_groupInfo << db.second.groupInfo();
|
m_groupInfo << localDataBase().groupInfo();
|
||||||
|
for(const auto &db : m_syncDbs) {
|
||||||
|
m_groupInfo << db.second.groupInfo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m_groupInfo;
|
return m_groupInfo;
|
||||||
|
@ -468,103 +527,19 @@ AlpmDataBase &Manager::dataBaseByName(const QString &dbName)
|
||||||
* - syncdbs: Array with the names of the databases used as upgrade sources.
|
* - syncdbs: Array with the names of the databases used as upgrade sources.
|
||||||
* If not present, appropriate upgrade sources will be determined automatically.
|
* If not present, appropriate upgrade sources will be determined automatically.
|
||||||
*/
|
*/
|
||||||
QJsonObject Manager::invokeUpgradeLookup(const QJsonObject &request) const
|
void Manager::invokeUpgradeLookup(const QJsonObject &request, UpdateLookupCallback callback) const
|
||||||
{
|
{
|
||||||
QJsonObject result;
|
new UpdateLookup(*this, request, callback); // this object will delete itself
|
||||||
QJsonArray errors;
|
|
||||||
const AlpmDataBase &db = dataBaseByName(request.value(QStringLiteral("db")).toString());
|
|
||||||
QJsonValue syncDbsValue = request.value(QStringLiteral("syncdbs"));
|
|
||||||
if(!db) {
|
|
||||||
errors << QStringLiteral("Database to be checked not found.");
|
|
||||||
} else {
|
|
||||||
QJsonArray warnings;
|
|
||||||
bool searchAur = request.value(QStringLiteral("aur")).toBool(false);
|
|
||||||
if(searchAur) {
|
|
||||||
m_aur.requestPackageInfo(db.packageNames());
|
|
||||||
}
|
|
||||||
const auto results = checkForUpgrades(db, syncDbsValue);
|
|
||||||
if(searchAur || !results.noSources) {
|
|
||||||
QJsonArray softwareUpdates;
|
|
||||||
QJsonArray packageOnlyUpdates;
|
|
||||||
QJsonArray downgrades;
|
|
||||||
QJsonArray orphanedPackages;
|
|
||||||
if(!results.noSources) {
|
|
||||||
for(const auto pkg : results.newVersions) {
|
|
||||||
softwareUpdates << pkg.basicInfo(true);
|
|
||||||
}
|
|
||||||
for(const auto pkg : results.newReleases) {
|
|
||||||
packageOnlyUpdates << pkg.basicInfo(true);
|
|
||||||
}
|
|
||||||
for(const auto pkg : results.downgrades) {
|
|
||||||
downgrades << pkg.basicInfo(true);
|
|
||||||
}
|
|
||||||
for(const auto pkg : results.orphaned) {
|
|
||||||
orphanedPackages << pkg.basicInfo(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!warnings.isEmpty()) {
|
|
||||||
result.insert(QStringLiteral("warnings"), warnings);
|
|
||||||
}
|
|
||||||
result.insert(QStringLiteral("softwareUpdates"), softwareUpdates);
|
|
||||||
result.insert(QStringLiteral("packageOnlyUpdates"), packageOnlyUpdates);
|
|
||||||
result.insert(QStringLiteral("downgrades"), downgrades);
|
|
||||||
result.insert(QStringLiteral("orphanedPackages"), orphanedPackages);
|
|
||||||
} else {
|
|
||||||
errors << QStringLiteral("No update sources associated for database \"%1\".").arg(QString::fromLocal8Bit(db.name()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!errors.isEmpty()) {
|
|
||||||
result.insert(QStringLiteral("errors"), errors);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Checks the specified database for upgrades.
|
|
||||||
*/
|
|
||||||
const UpdateLookupResults Manager::checkForUpgrades(const AlpmDataBase &db, const QJsonValue &syncDbsValue) const
|
|
||||||
{
|
|
||||||
UpdateLookupResults results;
|
|
||||||
const auto &syncDbs = 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 << &(localDataBase());
|
|
||||||
} 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 : db.upgradeSources()) {
|
|
||||||
if(syncDbName == QLatin1String("local")) {
|
|
||||||
syncDbSel << &(localDataBase());
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
syncDbSel << &(syncDbs.at(syncDbName));
|
|
||||||
} catch(out_of_range &) {
|
|
||||||
results.warnings << QStringLiteral("The associated upgrade database \"%1\" can not be found.").arg(syncDbName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
db.checkForUpgrades(syncDbSel, results);
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Checks the specified database for upgrades.
|
* \brief Checks the specified database for upgrades.
|
||||||
*
|
*
|
||||||
* Appropriate upgrade sources will be determined automatically.
|
* Appropriate upgrade sources will be determined automatically; does not check the AUR.
|
||||||
*/
|
*/
|
||||||
const UpdateLookupResults Manager::checkForUpgrades(const AlpmDataBase &db) const
|
const UpdateLookupResults<AlpmPackage> Manager::checkForUpgrades(const AlpmDataBase &db) const
|
||||||
{
|
{
|
||||||
UpdateLookupResults results;
|
UpdateLookupResults<AlpmPackage> results;
|
||||||
QList<const AlpmDataBase *> syncDbSel;
|
QList<const AlpmDataBase *> syncDbSel;
|
||||||
for(const auto &syncDbName : db.upgradeSources()) {
|
for(const auto &syncDbName : db.upgradeSources()) {
|
||||||
try {
|
try {
|
||||||
|
@ -577,11 +552,4 @@ const UpdateLookupResults Manager::checkForUpgrades(const AlpmDataBase &db) cons
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
//void Manager::addTask()
|
|
||||||
//{
|
|
||||||
// QUuid uuid;
|
|
||||||
// while(m_tasks.find(uuid = QUuid::createUuid()) != m_tasks.cend());
|
|
||||||
// m_tasks.emplace(uuid);
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +1,52 @@
|
||||||
#ifndef ALPM_MANAGER_H
|
#ifndef ALPM_MANAGER_H
|
||||||
#define ALPM_MANAGER_H
|
#define ALPM_MANAGER_H
|
||||||
|
|
||||||
#include "package.h"
|
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
|
#include "updatelookup.h"
|
||||||
|
|
||||||
#include "network/aurquery.h"
|
#include "network/aurquery.h"
|
||||||
|
|
||||||
#include <alpm.h>
|
#include <alpm.h>
|
||||||
|
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QJsonObject>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QFuture>
|
#include <QMutex>
|
||||||
#include <QUuid>
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace PackageManagement {
|
namespace PackageManagement {
|
||||||
|
|
||||||
class Config;
|
class Config;
|
||||||
|
template<class Package> class UpdateLookupResults;
|
||||||
|
|
||||||
class Manager : QObject
|
class Manager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Manager(const Config &config, QObject *parent = nullptr);
|
explicit Manager(const Config &config);
|
||||||
Manager(const Manager &other) = delete;
|
Manager(const Manager &other) = delete;
|
||||||
Manager(Manager &&other) = delete;
|
Manager(Manager &&other) = delete;
|
||||||
Manager &operator =(const Manager &other) = delete;
|
Manager &operator =(const Manager &other) = delete;
|
||||||
~Manager();
|
~Manager();
|
||||||
|
|
||||||
// configuration, signature level, etc
|
// configuration, signature level, etc
|
||||||
|
const Config &config() const;
|
||||||
int sigLevel() const;
|
int sigLevel() const;
|
||||||
void setSigLevel(int sigLevel);
|
void setSigLevel(int sigLevel);
|
||||||
int localFileSigLevel() const;
|
int localFileSigLevel() const;
|
||||||
void setLocalFileSigLevel(int sigLevel);
|
void setLocalFileSigLevel(int sigLevel);
|
||||||
const QString &cacheDir() const;
|
const QString &pacmanCacheDir() const;
|
||||||
void parsePacmanConfig();
|
static int parseSigLevel(const std::string &sigLevelStr = std::string());
|
||||||
|
static int parseUsage(const std::string &usageStr);
|
||||||
|
void applyPacmanConfig();
|
||||||
|
void applyRepoIndexConfig();
|
||||||
|
|
||||||
void unregisterSyncDataBases();
|
void unregisterSyncDataBases();
|
||||||
|
const AurQuery &aurQuery() const;
|
||||||
|
AurQuery &aurQuery();
|
||||||
|
|
||||||
// package lookup
|
// package lookup
|
||||||
AlpmPackage packageFromSyncDataBase(const QString &dbName, const QString &pkgName);
|
AlpmPackage packageFromSyncDataBase(const QString &dbName, const QString &pkgName) const;
|
||||||
AlpmPackage packageFromSyncDataBases(const char *name) const;
|
AlpmPackage packageFromSyncDataBases(const char *name) const;
|
||||||
AlpmOwnershipPackage packageFromFile(const char *fileName, bool verifyIntegrity = false);
|
AlpmOwnershipPackage packageFromFile(const char *fileName, bool verifyIntegrity = false);
|
||||||
bool isPackageIgnored(AlpmPackage package) const;
|
bool isPackageIgnored(AlpmPackage package) const;
|
||||||
|
@ -51,18 +58,14 @@ public:
|
||||||
const std::map<QString, AlpmDataBase> &syncDataBases() const;
|
const std::map<QString, AlpmDataBase> &syncDataBases() const;
|
||||||
const AlpmDataBase &dataBaseByName(const QString &dbName) const;
|
const AlpmDataBase &dataBaseByName(const QString &dbName) const;
|
||||||
AlpmDataBase &dataBaseByName(const QString &dbName);
|
AlpmDataBase &dataBaseByName(const QString &dbName);
|
||||||
const UpdateLookupResults checkForUpgrades(const AlpmDataBase &db) const;
|
const UpdateLookupResults<AlpmPackage> checkForUpgrades(const AlpmDataBase &db) const;
|
||||||
|
|
||||||
// asynchronous tasks
|
|
||||||
// void addTask();
|
|
||||||
|
|
||||||
// JSON serialization, handling JSON requests
|
// JSON serialization, handling JSON requests
|
||||||
QJsonObject basicRepoInfo(AlpmDataBase db, const QString &name, const QString &desc = QString()) const;
|
QJsonObject basicRepoInfo(AlpmDataBase db, const QString &name, const QString &desc = QString()) const;
|
||||||
const QJsonArray &basicRepoInfo() const;
|
const QJsonArray &basicRepoInfo() const;
|
||||||
const QJsonArray packageInfo(const QJsonArray &pkgSelection, bool full = true);
|
const QJsonArray packageInfo(const QJsonArray &pkgSelection, bool full = true) const;
|
||||||
const QJsonArray &groupInfo() const;
|
const QJsonArray &groupInfo() const;
|
||||||
QJsonObject invokeUpgradeLookup(const QJsonObject &request) const;
|
void invokeUpgradeLookup(const QJsonObject &request, UpdateLookupCallback callback) const;
|
||||||
const UpdateLookupResults checkForUpgrades(const AlpmDataBase &db, const QJsonValue &syncDbsValue) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
@ -71,16 +74,27 @@ private:
|
||||||
alpm_handle_t *m_handle;
|
alpm_handle_t *m_handle;
|
||||||
int m_sigLevel;
|
int m_sigLevel;
|
||||||
int m_localFileSigLevel;
|
int m_localFileSigLevel;
|
||||||
QString m_cacheDir;
|
QString m_pacmanCacheDir;
|
||||||
QNetworkAccessManager m_networkAccessManager;
|
QNetworkAccessManager m_networkAccessManager;
|
||||||
AurQuery m_aur;
|
AurQuery m_aur;
|
||||||
mutable AlpmDataBase m_localDb;
|
mutable AlpmDataBase m_localDb;
|
||||||
|
mutable QMutex m_localDbMutex;
|
||||||
mutable std::map<QString, AlpmDataBase> m_syncDbs;
|
mutable std::map<QString, AlpmDataBase> m_syncDbs;
|
||||||
mutable QJsonArray m_basicRepoInfo;
|
mutable QJsonArray m_basicRepoInfo;
|
||||||
mutable QJsonArray m_packageInfo;
|
mutable QMutex m_basicRepoInfoMutex;
|
||||||
mutable QJsonArray m_groupInfo;
|
mutable QJsonArray m_groupInfo;
|
||||||
|
mutable QMutex m_groupInfoMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the configuration of the manager.
|
||||||
|
* \remarks The configuration has been specified when constructing the manager.
|
||||||
|
*/
|
||||||
|
inline const Config &Manager::config() const
|
||||||
|
{
|
||||||
|
return m_config;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the signature level.
|
* \brief Returns the signature level.
|
||||||
*
|
*
|
||||||
|
@ -138,12 +152,22 @@ inline bool Manager::isPackageIgnored(AlpmPackage package) const
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the cache directory.
|
* \brief Returns the Pacman cache directory.
|
||||||
* \remarks This is read from the Pacman configuration.
|
* \remarks This is read from the Pacman configuration.
|
||||||
*/
|
*/
|
||||||
inline const QString &Manager::cacheDir() const
|
inline const QString &Manager::pacmanCacheDir() const
|
||||||
{
|
{
|
||||||
return m_cacheDir;
|
return m_pacmanCacheDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const AurQuery &Manager::aurQuery() const
|
||||||
|
{
|
||||||
|
return m_aur;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline AurQuery &Manager::aurQuery()
|
||||||
|
{
|
||||||
|
return m_aur;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
#include "mingwbundle.h"
|
||||||
|
#include "manager.h"
|
||||||
|
|
||||||
|
#include <c++utilities/conversion/stringconversion.h>
|
||||||
|
#include <c++utilities/misc/memory.h>
|
||||||
|
|
||||||
|
#include <KTar>
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QtConcurrent/QtConcurrent>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace PackageManagement {
|
||||||
|
|
||||||
|
const string prefix("mingw-w64-");
|
||||||
|
|
||||||
|
MingwBundle::MingwBundle(const Manager &manager, const ApplicationUtilities::StringVector &packages) :
|
||||||
|
m_manager(manager)
|
||||||
|
{
|
||||||
|
string missing;
|
||||||
|
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(missing.empty()) {
|
||||||
|
m_packages.emplace_back(syncDb.second, pkg);
|
||||||
|
}
|
||||||
|
addDependencies(pkg);
|
||||||
|
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 << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class RelevantFileType
|
||||||
|
{
|
||||||
|
Binary,
|
||||||
|
Translation
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class RelevantFileArch
|
||||||
|
{
|
||||||
|
x86_64,
|
||||||
|
i686
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RelevantFile
|
||||||
|
{
|
||||||
|
RelevantFile(const KArchiveFile *file, const RelevantFileType type, const RelevantFileArch arch) :
|
||||||
|
file(file),
|
||||||
|
fileType(type),
|
||||||
|
arch(arch)
|
||||||
|
{}
|
||||||
|
const KArchiveFile *file;
|
||||||
|
RelevantFileType fileType;
|
||||||
|
RelevantFileArch arch;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PkgFileInfo
|
||||||
|
{
|
||||||
|
PkgFileInfo(const QString &path) : path(path), failure(false) {}
|
||||||
|
QString path;
|
||||||
|
unique_ptr<KTar> archive;
|
||||||
|
list<RelevantFile> relevantFiles;
|
||||||
|
bool failure;
|
||||||
|
};
|
||||||
|
|
||||||
|
void getFiles(PkgFileInfo &pkgFileInfo)
|
||||||
|
{
|
||||||
|
pkgFileInfo.archive = make_unique<KTar>(pkgFileInfo.path);
|
||||||
|
if(pkgFileInfo.archive->open(QIODevice::ReadOnly)) {
|
||||||
|
static const pair<RelevantFileArch, QString> roots[] = {
|
||||||
|
make_pair(RelevantFileArch::x86_64, QStringLiteral("/usr/x86_64-w64-mingw32")),
|
||||||
|
make_pair(RelevantFileArch::i686, QStringLiteral("/usr/i686-w64-mingw32"))
|
||||||
|
};
|
||||||
|
for(const auto &root : roots) {
|
||||||
|
const auto *rootEntry = pkgFileInfo.archive->directory()->entry(root.second);
|
||||||
|
if(rootEntry && rootEntry->isDirectory()) {
|
||||||
|
const auto *rootDir = static_cast<const KArchiveDirectory *>(rootEntry);
|
||||||
|
const auto *binEntry = rootDir->entry(QStringLiteral("bin"));
|
||||||
|
if(binEntry && binEntry->isDirectory()) {
|
||||||
|
const auto *binDir = static_cast<const KArchiveDirectory *>(binEntry);
|
||||||
|
for(const auto &entryName : binDir->entries()) {
|
||||||
|
if(entryName.endsWith(QLatin1String(".exe")) || entryName.endsWith(QLatin1String(".dll"))) {
|
||||||
|
if(const auto *entry = binDir->entry(entryName)) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pkgFileInfo.failure = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MingwBundle::createBundle(const string &path) const
|
||||||
|
{
|
||||||
|
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(pkgFile.isEmpty() || !QFile::exists(pkgFile)) {
|
||||||
|
if(!m_manager.pacmanCacheDir().isEmpty()) {
|
||||||
|
pkgFile = QStringLiteral("%1/%2").arg(m_manager.pacmanCacheDir(), QString::fromLocal8Bit(entry.second.fileName()));
|
||||||
|
}
|
||||||
|
if(pkgFile.isEmpty() || !QFile::exists(pkgFile)) {
|
||||||
|
throw runtime_error("The package file " + string(entry.second.fileName()) + " can't be found.");
|
||||||
|
// TODO: download package from mirror
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pkgFiles.emplace_back(pkgFile);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!missing.empty()) {
|
||||||
|
throw runtime_error("The following dependencies of the " + string(pkg.name()) + " package can not be resolved:" + missing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace PackageManagement
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef PACKAGEMANAGEMENT_MINGWBUNDLE_H
|
||||||
|
#define PACKAGEMANAGEMENT_MINGWBUNDLE_H
|
||||||
|
|
||||||
|
#include "package.h"
|
||||||
|
#include "database.h"
|
||||||
|
|
||||||
|
#include <c++utilities/application/argumentparser.h>
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
namespace PackageManagement {
|
||||||
|
|
||||||
|
class Manager;
|
||||||
|
|
||||||
|
class MingwBundle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MingwBundle(const Manager &manager, const ApplicationUtilities::StringVector &packages);
|
||||||
|
|
||||||
|
void createBundle(const std::string &path) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addDependencies(const AlpmPackage &pkg);
|
||||||
|
|
||||||
|
const Manager &m_manager;
|
||||||
|
std::list<std::pair<const AlpmDataBase &, AlpmPackage> > m_packages;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace PackageManagement
|
||||||
|
|
||||||
|
#endif // PACKAGEMANAGEMENT_MINGWBUNDLE_H
|
218
alpm/package.cpp
218
alpm/package.cpp
|
@ -11,10 +11,93 @@ using namespace ChronoUtilities;
|
||||||
|
|
||||||
namespace PackageManagement {
|
namespace PackageManagement {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \cond
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline QString qstr(const char *str)
|
||||||
|
{
|
||||||
|
return QString::fromLocal8Bit(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QJsonArray qjarry(StringList list)
|
||||||
|
{
|
||||||
|
QJsonArray jsonArray;
|
||||||
|
for(const char *str : list) {
|
||||||
|
jsonArray << qstr(str);
|
||||||
|
}
|
||||||
|
return jsonArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief The PackageVersion class helps parsing package versions.
|
* \brief The PackageVersion class helps parsing package versions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \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.
|
* \brief Constructs a new PackageVersion instance from the specified \a versionStr.
|
||||||
*/
|
*/
|
||||||
|
@ -158,10 +241,12 @@ AurPackage::AurPackage(const QJsonValue &aurJsonValue) :
|
||||||
QJsonObject obj = aurJsonValue.toObject();
|
QJsonObject obj = aurJsonValue.toObject();
|
||||||
m_id = obj.value(QStringLiteral("ID")).toInt(-1);
|
m_id = obj.value(QStringLiteral("ID")).toInt(-1);
|
||||||
m_categoryId = obj.value(QStringLiteral("CategoryID")).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_description = obj.value(QStringLiteral("Description")).toString();
|
||||||
m_upstreamUrl = obj.value(QStringLiteral("URL")).toString();
|
m_upstreamUrl = obj.value(QStringLiteral("URL")).toString();
|
||||||
m_votes = obj.value(QStringLiteral("NumVotes")).toInt(0);
|
m_votes = obj.value(QStringLiteral("NumVotes")).toInt(0);
|
||||||
m_outOfDate = obj.value(QStringLiteral("OutOfDate")).toInt() != 0;
|
m_outOfDate = DateTime::fromTimeStamp(obj.value(QStringLiteral("OutOfDate")).toInt());
|
||||||
m_maintainer = obj.value(QStringLiteral("Maintainer")).toString();
|
m_maintainer = obj.value(QStringLiteral("Maintainer")).toString();
|
||||||
m_firstSubmitted = DateTime::fromTimeStamp(obj.value(QStringLiteral("FirstSubmitted")).toInt());
|
m_firstSubmitted = DateTime::fromTimeStamp(obj.value(QStringLiteral("FirstSubmitted")).toInt());
|
||||||
m_lastModified = DateTime::fromTimeStamp(obj.value(QStringLiteral("LastModified")).toInt());
|
m_lastModified = DateTime::fromTimeStamp(obj.value(QStringLiteral("LastModified")).toInt());
|
||||||
|
@ -169,87 +254,65 @@ AurPackage::AurPackage(const QJsonValue &aurJsonValue) :
|
||||||
m_tarUrl = obj.value(QStringLiteral("URLPath")).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
|
* \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.
|
* information to JSON objects used by the network classes and the web interface.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
|
||||||
* \cond
|
|
||||||
*/
|
|
||||||
|
|
||||||
inline QString qstr(const char *str)
|
|
||||||
{
|
|
||||||
return QString::fromLocal8Bit(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline QJsonArray qjarry(StringList list)
|
|
||||||
{
|
|
||||||
QJsonArray jsonArray;
|
|
||||||
for(const char *str : list) {
|
|
||||||
jsonArray << qstr(str);
|
|
||||||
}
|
|
||||||
return jsonArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns basic information about the packages as JSON object.
|
* \brief Returns basic information about the packages as JSON object.
|
||||||
*/
|
*/
|
||||||
|
@ -264,6 +327,7 @@ QJsonObject AlpmPackage::basicInfo(bool includeRepoAndName) const
|
||||||
packageInfo.insert(QStringLiteral("ver"), qstr(version()));
|
packageInfo.insert(QStringLiteral("ver"), qstr(version()));
|
||||||
packageInfo.insert(QStringLiteral("desc"), qstr(description()));
|
packageInfo.insert(QStringLiteral("desc"), qstr(description()));
|
||||||
packageInfo.insert(QStringLiteral("bdate"), qstr(buildDate().toString().c_str()));
|
packageInfo.insert(QStringLiteral("bdate"), qstr(buildDate().toString().c_str()));
|
||||||
|
packageInfo.insert(QStringLiteral("flagdate"), QStringLiteral("n.a."));
|
||||||
return packageInfo;
|
return packageInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QJsonObject;
|
class QJsonObject;
|
||||||
|
@ -43,6 +44,7 @@ enum class PackageVersionPartComparsion
|
||||||
class PackageVersion
|
class PackageVersion
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
PackageVersion(const QString &versionStr);
|
||||||
PackageVersion(const char *versionStr);
|
PackageVersion(const char *versionStr);
|
||||||
|
|
||||||
static PackageVersionPartComparsion compareParts(const QString &part1, const QString &part2);
|
static PackageVersionPartComparsion compareParts(const QString &part1, const QString &part2);
|
||||||
|
@ -60,39 +62,49 @@ public:
|
||||||
AurPackage(const QJsonValue &aurJsonValue);
|
AurPackage(const QJsonValue &aurJsonValue);
|
||||||
|
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
|
bool hasFullInfo() const;
|
||||||
int id() const;
|
int id() const;
|
||||||
int categoryId() const;
|
int categoryId() const;
|
||||||
const QString &name() const;
|
const QString &name() const;
|
||||||
|
const QString &version() const;
|
||||||
|
template<class Package>
|
||||||
|
PackageVersionComparsion compareVersion(const Package &syncPackage) const;
|
||||||
const QString &description() const;
|
const QString &description() const;
|
||||||
const QString &upstreamUrl() const;
|
const QString &upstreamUrl() const;
|
||||||
int votes() const;
|
int votes() const;
|
||||||
bool isOutOfDate() const;
|
ChronoUtilities::DateTime outOfDate() const;
|
||||||
const QString &maintainer() const;
|
const QString &maintainer() const;
|
||||||
ChronoUtilities::DateTime firstSubmitted() const;
|
ChronoUtilities::DateTime firstSubmitted() const;
|
||||||
ChronoUtilities::DateTime lastModified() const;
|
ChronoUtilities::DateTime lastModified() const;
|
||||||
const QString &license() const;
|
const QString &license() const;
|
||||||
const QString &tarUrl() const;
|
const QString &tarUrl() const;
|
||||||
|
|
||||||
|
// JSON serialization
|
||||||
|
QJsonObject basicInfo(bool includeRepoAndName) const;
|
||||||
|
QJsonObject fullInfo(bool includeRepoAndName = false) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool m_fullInfo;
|
||||||
int m_id;
|
int m_id;
|
||||||
int m_categoryId;
|
int m_categoryId;
|
||||||
QString m_name;
|
QString m_name;
|
||||||
|
QString m_version;
|
||||||
QString m_description;
|
QString m_description;
|
||||||
QString m_upstreamUrl;
|
QString m_upstreamUrl;
|
||||||
int m_votes;
|
int m_votes;
|
||||||
bool m_outOfDate;
|
ChronoUtilities::DateTime m_outOfDate;
|
||||||
QString m_maintainer;
|
QString m_maintainer;
|
||||||
ChronoUtilities::DateTime m_firstSubmitted;
|
ChronoUtilities::DateTime m_firstSubmitted;
|
||||||
ChronoUtilities::DateTime m_lastModified;
|
ChronoUtilities::DateTime m_lastModified;
|
||||||
QString m_license;
|
QString m_license;
|
||||||
QString m_tarUrl;
|
QString m_tarUrl;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Constructs a empty, invalid AUR package.
|
* \brief Constructs a empty, invalid AUR package.
|
||||||
*/
|
*/
|
||||||
inline AurPackage::AurPackage() :
|
inline AurPackage::AurPackage() :
|
||||||
|
m_fullInfo(false),
|
||||||
m_id(-1),
|
m_id(-1),
|
||||||
m_categoryId(-1),
|
m_categoryId(-1),
|
||||||
m_votes(-1),
|
m_votes(-1),
|
||||||
|
@ -107,6 +119,14 @@ inline bool AurPackage::isValid() const
|
||||||
return m_id >= 0;
|
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.
|
* \brief Returns the ID of the package in the AUR.
|
||||||
*/
|
*/
|
||||||
|
@ -131,6 +151,20 @@ inline const QString &AurPackage::name() const
|
||||||
return m_name;
|
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.
|
* \brief Returns the description of the package.
|
||||||
*/
|
*/
|
||||||
|
@ -158,7 +192,7 @@ inline int AurPackage::votes() const
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns wheter the package is flagged as out-of-date.
|
* \brief Returns wheter the package is flagged as out-of-date.
|
||||||
*/
|
*/
|
||||||
inline bool AurPackage::isOutOfDate() const
|
inline ChronoUtilities::DateTime AurPackage::outOfDate() const
|
||||||
{
|
{
|
||||||
return m_outOfDate;
|
return m_outOfDate;
|
||||||
}
|
}
|
||||||
|
@ -209,12 +243,14 @@ public:
|
||||||
AlpmPackage(alpm_pkg_t *package = nullptr);
|
AlpmPackage(alpm_pkg_t *package = nullptr);
|
||||||
|
|
||||||
// package properties
|
// package properties
|
||||||
|
const alpm_pkg_t *ptr() const;
|
||||||
alpm_pkg_t *ptr();
|
alpm_pkg_t *ptr();
|
||||||
bool hasInstallScript() const;
|
bool hasInstallScript() const;
|
||||||
const char *fileName() const;
|
const char *fileName() const;
|
||||||
const char *name() const;
|
const char *name() const;
|
||||||
const char *version() const;
|
const char *version() const;
|
||||||
PackageVersionComparsion compareVersion(const AlpmPackage &syncPackage) const;
|
template<class Package>
|
||||||
|
PackageVersionComparsion compareVersion(const Package &syncPackage) const;
|
||||||
alpm_pkgfrom_t origin() const;
|
alpm_pkgfrom_t origin() const;
|
||||||
const char *description() const;
|
const char *description() const;
|
||||||
const char *upstreamUrl() const;
|
const char *upstreamUrl() const;
|
||||||
|
@ -256,6 +292,11 @@ protected:
|
||||||
alpm_pkg_t *m_ptr;
|
alpm_pkg_t *m_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline uint qHash(const AlpmPackage &key)
|
||||||
|
{
|
||||||
|
return qHash(key.ptr());
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Constructs a new package instance for the specified ALPM \a package.
|
* \brief Constructs a new package instance for the specified ALPM \a package.
|
||||||
*/
|
*/
|
||||||
|
@ -263,6 +304,11 @@ inline AlpmPackage::AlpmPackage(alpm_pkg_t *package) :
|
||||||
m_ptr(package)
|
m_ptr(package)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
inline const alpm_pkg_t *AlpmPackage::ptr() const
|
||||||
|
{
|
||||||
|
return m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
inline alpm_pkg_t *AlpmPackage::ptr()
|
inline alpm_pkg_t *AlpmPackage::ptr()
|
||||||
{
|
{
|
||||||
return m_ptr;
|
return m_ptr;
|
||||||
|
@ -293,7 +339,8 @@ inline const char *AlpmPackage::version() const
|
||||||
*
|
*
|
||||||
* This method distinguishes between software upgrades and package releases. See Alpm::PackageVersionComparsion enum.
|
* This method distinguishes between software upgrades and package releases. See Alpm::PackageVersionComparsion enum.
|
||||||
*/
|
*/
|
||||||
inline PackageVersionComparsion AlpmPackage::compareVersion(const AlpmPackage &syncPackage) const
|
template<class Package>
|
||||||
|
inline PackageVersionComparsion AlpmPackage::compareVersion(const Package &syncPackage) const
|
||||||
{
|
{
|
||||||
return PackageVersion(version()).compare(PackageVersion(syncPackage.version()));
|
return PackageVersion(version()).compare(PackageVersion(syncPackage.version()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,202 @@
|
||||||
|
#include "resolvebuildorder.h"
|
||||||
|
|
||||||
|
#include "manager.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <c++utilities/misc/memory.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace ApplicationUtilities;
|
||||||
|
|
||||||
|
namespace PackageManagement {
|
||||||
|
|
||||||
|
class TaskInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TaskInfo(QString name, bool onlyDependency = false, const QList<TaskInfo *> &deps = QList<TaskInfo *>());
|
||||||
|
|
||||||
|
const QString &name() const;
|
||||||
|
const QList<TaskInfo *> deps() const;
|
||||||
|
void addDep(TaskInfo *dep);
|
||||||
|
bool isDone() const;
|
||||||
|
bool isVisited() const;
|
||||||
|
bool isOnlyDependency() const;
|
||||||
|
void add(QList<TaskInfo *> &results);
|
||||||
|
static void addAll(const QList<TaskInfo *> &tasks, QList<TaskInfo *> &results);
|
||||||
|
static TaskInfo *find(const QList<TaskInfo *> &tasks, const QString &name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_name;
|
||||||
|
QList<TaskInfo *> m_deps;
|
||||||
|
bool m_done;
|
||||||
|
bool m_visited;
|
||||||
|
bool m_onlyDep;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline TaskInfo::TaskInfo(QString name, bool onlyDependency, const QList<TaskInfo *> &deps) :
|
||||||
|
m_name(name),
|
||||||
|
m_deps(deps),
|
||||||
|
m_done(false),
|
||||||
|
m_visited(false),
|
||||||
|
m_onlyDep(onlyDependency)
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline const QString &TaskInfo::name() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const QList<TaskInfo *> TaskInfo::deps() const
|
||||||
|
{
|
||||||
|
return m_deps;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TaskInfo::addDep(TaskInfo *dep)
|
||||||
|
{
|
||||||
|
m_deps << dep;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool TaskInfo::isDone() const
|
||||||
|
{
|
||||||
|
return m_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool TaskInfo::isVisited() const
|
||||||
|
{
|
||||||
|
return m_visited;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool TaskInfo::isOnlyDependency() const
|
||||||
|
{
|
||||||
|
return m_onlyDep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskInfo::add(QList<TaskInfo *> &results)
|
||||||
|
{
|
||||||
|
if(!m_done) {
|
||||||
|
if(m_visited) {
|
||||||
|
throw *this; // cyclic dependency
|
||||||
|
} else {
|
||||||
|
m_visited = true;
|
||||||
|
}
|
||||||
|
for(auto *dep : m_deps) {
|
||||||
|
dep->add(results);
|
||||||
|
}
|
||||||
|
m_done = true;
|
||||||
|
results << this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskInfo::addAll(const QList<TaskInfo *> &tasks, QList<TaskInfo *> &results)
|
||||||
|
{
|
||||||
|
for(auto *task : tasks) {
|
||||||
|
if(!task->m_done) {
|
||||||
|
task->add(results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskInfo *TaskInfo::find(const QList<TaskInfo *> &tasks, const QString &name)
|
||||||
|
{
|
||||||
|
for(auto *task : tasks) {
|
||||||
|
if(task->name() == name) {
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ListType>
|
||||||
|
class DestroyList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DestroyList(ListType &list) :
|
||||||
|
m_list(list)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~DestroyList()
|
||||||
|
{
|
||||||
|
qDeleteAll(m_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ListType &m_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
BuildOrderResolver::BuildOrderResolver(const Manager &manager) :
|
||||||
|
m_manager(manager)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QStringList BuildOrderResolver::resolve(const StringVector &packages) const
|
||||||
|
{
|
||||||
|
cerr << "Getting package information ..." << endl;
|
||||||
|
QList<TaskInfo *> tasks;
|
||||||
|
tasks.reserve(packages.size());
|
||||||
|
try {
|
||||||
|
// add a task for each specified package
|
||||||
|
for(const auto &pkgName : packages) {
|
||||||
|
tasks << new TaskInfo(QString::fromLocal8Bit(pkgName.data()));
|
||||||
|
}
|
||||||
|
// find specified packages and their dependencies
|
||||||
|
for(auto *task : tasks) {
|
||||||
|
addDeps(tasks, task);
|
||||||
|
}
|
||||||
|
cerr << "Relevant packages: ";
|
||||||
|
for(const auto *task : tasks) {
|
||||||
|
cerr << task->name().toLocal8Bit().data() << ' ';
|
||||||
|
}
|
||||||
|
cerr << endl;
|
||||||
|
// topo sort
|
||||||
|
QList<TaskInfo *> results;
|
||||||
|
results.reserve(tasks.size());
|
||||||
|
try {
|
||||||
|
TaskInfo::addAll(tasks, results);
|
||||||
|
QStringList names;
|
||||||
|
names.reserve(results.size());
|
||||||
|
for(const auto *res : results) {
|
||||||
|
names << res->name();
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
} catch (const TaskInfo &cyclic) {
|
||||||
|
throw runtime_error("Can't resolve build order; the package " + cyclic.name().toStdString() + " is a cyclic dependency.");
|
||||||
|
}
|
||||||
|
} catch(...) {
|
||||||
|
qDeleteAll(tasks);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
task->addDep(depTask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stringstream ss;
|
||||||
|
ss << "The package \"" << task->name().toLocal8Bit().data() << "\" could not be found; TODO: search AUR for package, add AUR deps to the packages we want to build";
|
||||||
|
throw runtime_error(ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskInfo *BuildOrderResolver::addDep(QList<TaskInfo *> &tasks, const char *depName) const
|
||||||
|
{
|
||||||
|
if(auto *task = TaskInfo::find(tasks, depName)) {
|
||||||
|
// we've already added a task for this dependency
|
||||||
|
return task;
|
||||||
|
} else {
|
||||||
|
// create new task
|
||||||
|
//task = new TaskInfo(QString::fromLocal8Bit(depName));
|
||||||
|
//tasks << task;
|
||||||
|
//return task;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace PackageManagement
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef PACKAGEMANAGEMENT_RESOLVEBUILDORDER_H
|
||||||
|
#define PACKAGEMANAGEMENT_RESOLVEBUILDORDER_H
|
||||||
|
|
||||||
|
#include <c++utilities/application/argumentparser.h>
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
namespace PackageManagement {
|
||||||
|
|
||||||
|
class Manager;
|
||||||
|
class TaskInfo;
|
||||||
|
|
||||||
|
class BuildOrderResolver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BuildOrderResolver(const Manager &manager);
|
||||||
|
|
||||||
|
QStringList resolve(const ApplicationUtilities::StringVector &packages) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addDeps(QList<TaskInfo *> &tasks, TaskInfo *task) const;
|
||||||
|
TaskInfo *addDep(QList<TaskInfo *> &pkgInfos, const char *depName) const;
|
||||||
|
const Manager &m_manager;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace PackageManagement
|
||||||
|
|
||||||
|
#endif // PACKAGEMANAGEMENT_RESOLVEBUILDORDER_H
|
|
@ -0,0 +1,185 @@
|
||||||
|
#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
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
#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
|
40
main.cpp
40
main.cpp
|
@ -1,6 +1,8 @@
|
||||||
#include "alpm/manager.h"
|
#include "alpm/manager.h"
|
||||||
#include "alpm/utilities.h"
|
#include "alpm/utilities.h"
|
||||||
#include "alpm/config.h"
|
#include "alpm/config.h"
|
||||||
|
#include "alpm/resolvebuildorder.h"
|
||||||
|
#include "alpm/mingwbundle.h"
|
||||||
#include "network/server.h"
|
#include "network/server.h"
|
||||||
|
|
||||||
#include <c++utilities/application/argumentparser.h>
|
#include <c++utilities/application/argumentparser.h>
|
||||||
|
@ -9,6 +11,7 @@
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace ApplicationUtilities;
|
using namespace ApplicationUtilities;
|
||||||
|
@ -33,17 +36,34 @@ int main(int argc, char *argv[])
|
||||||
Config config;
|
Config config;
|
||||||
config.loadFromConfigFile(configArgs);
|
config.loadFromConfigFile(configArgs);
|
||||||
config.loadFromArgs(configArgs);
|
config.loadFromArgs(configArgs);
|
||||||
// run websocket server
|
if(find_if(parser.mainArguments().cbegin(), parser.mainArguments().cend(), [&configArgs] (const Argument *arg) {
|
||||||
if(configArgs.serverArg.isPresent()) {
|
return arg != &configArgs.helpArg && arg->isPresent();
|
||||||
// setup ALPM
|
}) != parser.mainArguments().cend()) {
|
||||||
Manager alpmManager(config);
|
// create app
|
||||||
alpmManager.parsePacmanConfig();
|
|
||||||
// setup the server
|
|
||||||
QCoreApplication application(argc, argv);
|
QCoreApplication application(argc, argv);
|
||||||
Server server(alpmManager, config);
|
// setup ALPM
|
||||||
QObject::connect(&server, &Server::closed, &application, &QCoreApplication::quit);
|
Manager manager(config);
|
||||||
// run Qt loop
|
manager.applyPacmanConfig();
|
||||||
return application.exec();
|
manager.applyRepoIndexConfig();
|
||||||
|
if(configArgs.serverArg.isPresent()) {
|
||||||
|
// setup the server
|
||||||
|
Server server(manager, manager.config());
|
||||||
|
QObject::connect(&server, &Server::closed, &application, &QCoreApplication::quit);
|
||||||
|
// run Qt loop
|
||||||
|
return application.exec();
|
||||||
|
} else if(configArgs.buildOrderArg.isPresent()) {
|
||||||
|
BuildOrderResolver resolver(manager);
|
||||||
|
const QStringList results = resolver.resolve(configArgs.buildOrderArg.values());
|
||||||
|
// print results
|
||||||
|
cout << "Results: ";
|
||||||
|
for(const auto &pkgName : results) {
|
||||||
|
cout << pkgName.toLocal8Bit().data() << ' ';
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
} else if(configArgs.mingwBundleArg.isPresent()) {
|
||||||
|
MingwBundle bundle(manager, configArgs.mingwBundleArg.values());
|
||||||
|
bundle.createBundle(configArgs.outputFileArg.values().front());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cout << "No command line arguments specified. See --help for available commands." << endl;
|
cout << "No command line arguments specified. See --help for available commands." << endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,53 +16,105 @@ using namespace std;
|
||||||
|
|
||||||
namespace PackageManagement {
|
namespace PackageManagement {
|
||||||
|
|
||||||
QUrl AurQuery::m_aur4RequestUrl = QUrl(QStringLiteral("https://aur.archlinux.org/rpc.php"));
|
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) :
|
AurQuery::AurQuery(QNetworkAccessManager &networkAccessManager, QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
m_networkAccessManager(networkAccessManager)
|
m_networkAccessManager(networkAccessManager)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void AurQuery::requestSuggestions(const QString &phrase) const
|
QNetworkReply *AurQuery::requestSuggestions(const QString &phrase) const
|
||||||
{
|
{
|
||||||
auto url = m_aur4RequestUrl;
|
auto url = m_aurRpcUrl;
|
||||||
QUrlQuery query;
|
QUrlQuery query;
|
||||||
query.addQueryItem(QStringLiteral("type"), QStringLiteral("suggest"));
|
query.addQueryItem(rpcRequestTypeKey, rpcRequestTypeSuggest);
|
||||||
query.addQueryItem(QStringLiteral("arg"), phrase);
|
query.addQueryItem(rpcArgKey, phrase);
|
||||||
//auto *reply = m_networkAccessManager.get(QNetworkRequest(url));
|
url.setQuery(query);
|
||||||
//connect(reply, &QNetworkReply::finished, this, &AurEnquiry::suggestionsReceived);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AurQuery::requestPackageInfo(const QStringList &packageNames) const
|
|
||||||
{
|
|
||||||
auto url = m_aur4RequestUrl;
|
|
||||||
QUrlQuery query;
|
|
||||||
query.addQueryItem(QStringLiteral("type"), QStringLiteral("multiinfo"));
|
|
||||||
for(const auto &packageName : packageNames) {
|
|
||||||
query.addQueryItem(QStringLiteral("arg[]"), packageName);
|
|
||||||
}
|
|
||||||
auto *reply = m_networkAccessManager.get(QNetworkRequest(url));
|
auto *reply = m_networkAccessManager.get(QNetworkRequest(url));
|
||||||
reply->setProperty("type", QStringLiteral("packageinfo"));
|
reply->setProperty(requestTypeProp, rpcRequestTypeSuggest);
|
||||||
connect(reply, &QNetworkReply::finished, this, &AurQuery::packageInfoReceived);
|
connect(reply, &QNetworkReply::finished, this, &AurQuery::dataReceived);
|
||||||
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AurQuery::packageInfoReceived()
|
/*!
|
||||||
|
* \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(auto *reply = qobject_cast<QNetworkReply *>(sender())) {
|
||||||
if(reply->error() == QNetworkReply::NoError) {
|
if(reply->error() == QNetworkReply::NoError) {
|
||||||
QJsonParseError error;
|
QJsonParseError error;
|
||||||
const QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &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) {
|
if(error.error == QJsonParseError::NoError) {
|
||||||
const auto results = doc.object().value(QStringLiteral("results")).toArray();
|
const QString requestType = reply->property(requestTypeProp).toString();
|
||||||
for(const auto &result : results) {
|
if(requestType == rpcRequestTypeSuggest) {
|
||||||
AurPackage package(result);
|
emit suggestionsAvailable(reply, doc.array());
|
||||||
if(!package.name().isEmpty()) {
|
} else if(requestType == rpcRequestTypeMultiInfo) {
|
||||||
m_packages.emplace(package.name(), move(package));
|
processPackageInfo(reply, doc.object().value(QStringLiteral("results")).toArray());
|
||||||
}
|
} else {
|
||||||
|
cerr << "Error: Reply has invalid type. (should never happen)" << endl;
|
||||||
}
|
}
|
||||||
emit packageInfoAvailable();
|
|
||||||
} else {
|
} else {
|
||||||
cerr << "Error: Unable to parse JSON received from AUR: " << error.errorString().toLocal8Bit().data() << endl;
|
cerr << "Error: Unable to parse JSON received from AUR: " << error.errorString().toLocal8Bit().data() << " at character " << error.offset << endl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cerr << "Error: Unable to request data from AUR: " << reply->errorString().toLocal8Bit().data() << endl;
|
cerr << "Error: Unable to request data from AUR: " << reply->errorString().toLocal8Bit().data() << endl;
|
||||||
|
@ -70,5 +122,16 @@ void AurQuery::packageInfoReceived()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
} // namespace Alpm
|
||||||
|
|
||||||
|
|
|
@ -9,49 +9,58 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QNetworkAccessManager)
|
QT_FORWARD_DECLARE_CLASS(QNetworkAccessManager)
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QNetworkReply)
|
||||||
|
|
||||||
namespace PackageManagement {
|
namespace PackageManagement {
|
||||||
|
|
||||||
class AurQuery : public QObject
|
class AurQuery : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AurQuery(QNetworkAccessManager &networkAccessManager, QObject *parent = nullptr);
|
AurQuery(QNetworkAccessManager &networkAccessManager, QObject *parent = nullptr);
|
||||||
|
|
||||||
static const QUrl aur4RequestUrl();
|
static const QUrl aurRpcUrl();
|
||||||
static void setAur4RequestUrl(const QUrl &aur4RequestUrl);
|
static void setAurRpcUrl(const QUrl &aurRpcUrl);
|
||||||
|
|
||||||
void requestSuggestions(const QString &phrase) const;
|
QNetworkReply *requestSuggestions(const QString &phrase) const;
|
||||||
void requestPackageInfo(const QStringList &packageNames) 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();
|
std::map<QString, AurPackage> &packages();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void suggestionsAvailable(const QJsonArray &suggestions);
|
void suggestionsAvailable(const QNetworkReply *reply, const QJsonArray &suggestions);
|
||||||
void packageInfoAvailable();
|
void packageInfoAvailable(const QNetworkReply *reply);
|
||||||
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void packageInfoReceived();
|
void dataReceived();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void processPackageInfo(const QNetworkReply *reply, const QJsonArray &results);
|
||||||
|
|
||||||
QNetworkAccessManager &m_networkAccessManager;
|
QNetworkAccessManager &m_networkAccessManager;
|
||||||
std::map<QString, AurPackage> m_packages;
|
std::map<QString, AurPackage> m_packages;
|
||||||
|
|
||||||
static QUrl m_aurRequstUrl;
|
static QUrl m_aurRpcUrl;
|
||||||
static QUrl m_aur4RequestUrl;
|
static QUrl m_aurPkgbuildUrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const QUrl AurQuery::aur4RequestUrl()
|
inline const QUrl AurQuery::aurRpcUrl()
|
||||||
{
|
{
|
||||||
return m_aur4RequestUrl;
|
return m_aurRpcUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void AurQuery::setAur4RequestUrl(const QUrl &aur4Url)
|
inline void AurQuery::setAurRpcUrl(const QUrl &aur4Url)
|
||||||
{
|
{
|
||||||
m_aur4RequestUrl = aur4Url;
|
m_aurRpcUrl = aur4Url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const std::map<QString, AurPackage> &AurQuery::packages() const
|
||||||
|
{
|
||||||
|
return m_packages;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline std::map<QString, AurPackage> &AurQuery::packages()
|
inline std::map<QString, AurPackage> &AurQuery::packages()
|
||||||
{
|
{
|
||||||
return m_packages;
|
return m_packages;
|
||||||
|
|
|
@ -13,7 +13,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace Network {
|
namespace Network {
|
||||||
|
|
||||||
Connection::Connection(PackageManagement::Manager &alpmManager, QWebSocket *socket, QObject *parent) :
|
Connection::Connection(const PackageManagement::Manager &alpmManager, QWebSocket *socket, QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
m_socket(socket),
|
m_socket(socket),
|
||||||
m_alpmManager(alpmManager),
|
m_alpmManager(alpmManager),
|
||||||
|
@ -78,8 +78,8 @@ void Connection::handleQuery(const QJsonObject &obj)
|
||||||
m_groupInfoUpdatesRequested = obj.value(QStringLiteral("updates")).toBool(m_groupInfoUpdatesRequested);
|
m_groupInfoUpdatesRequested = obj.value(QStringLiteral("updates")).toBool(m_groupInfoUpdatesRequested);
|
||||||
sendResults(what, id, m_alpmManager.groupInfo());
|
sendResults(what, id, m_alpmManager.groupInfo());
|
||||||
} else if(what == QLatin1String("checkforupdates")) {
|
} else if(what == QLatin1String("checkforupdates")) {
|
||||||
m_alpmManager.invokeUpgradeLookup(obj);
|
//sendResult(what, id, m_alpmManager.invokeUpgradeLookup(obj));
|
||||||
//m_alpmManager.invokeUpgradeLookup(obj, bind(&Connection::sendResult, this, what, id, placeholders::_1));
|
m_alpmManager.invokeUpgradeLookup(obj, bind(&Connection::sendResult, this, what, id, placeholders::_1));
|
||||||
//m_alpmManager.checkForUpgrades(obj, [this] (const QJsonObject &results) {
|
//m_alpmManager.checkForUpgrades(obj, [this] (const QJsonObject &results) {
|
||||||
// sendResult(what, id, results);
|
// sendResult(what, id, results);
|
||||||
//};
|
//};
|
||||||
|
|
|
@ -18,7 +18,7 @@ class Connection : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Connection(PackageManagement::Manager &alpmManager, QWebSocket *socket, QObject *parent = nullptr);
|
Connection(const PackageManagement::Manager &alpmManager, QWebSocket *socket, QObject *parent = nullptr);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void processTextMessage(const QString &message);
|
void processTextMessage(const QString &message);
|
||||||
|
@ -33,7 +33,7 @@ private:
|
||||||
void handleQuery(const QJsonObject &obj);
|
void handleQuery(const QJsonObject &obj);
|
||||||
|
|
||||||
QWebSocket *m_socket;
|
QWebSocket *m_socket;
|
||||||
PackageManagement::Manager &m_alpmManager;
|
const PackageManagement::Manager &m_alpmManager;
|
||||||
bool m_repoInfoUpdatesRequested;
|
bool m_repoInfoUpdatesRequested;
|
||||||
bool m_groupInfoUpdatesRequested;
|
bool m_groupInfoUpdatesRequested;
|
||||||
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
#include "query.h"
|
|
||||||
|
|
||||||
namespace Network {
|
|
||||||
|
|
||||||
Query::Query(QObject *parent) :
|
|
||||||
QObject(parent)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Network
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
#ifndef NETWORK_QUERY_H
|
|
||||||
#define NETWORK_QUERY_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
namespace Network {
|
|
||||||
|
|
||||||
class Query : public QObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Query(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString m_what;
|
|
||||||
QString m_clientId;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Network
|
|
||||||
|
|
||||||
#endif // NETWORK_QUERY_H
|
|
|
@ -14,7 +14,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace Network {
|
namespace Network {
|
||||||
|
|
||||||
Server::Server(PackageManagement::Manager &alpmManager, const PackageManagement::Config &config, QObject *parent) :
|
Server::Server(const PackageManagement::Manager &alpmManager, const PackageManagement::Config &config, QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
m_server(new QWebSocketServer(QStringLiteral("Repository index server"),
|
m_server(new QWebSocketServer(QStringLiteral("Repository index server"),
|
||||||
config.serverInsecure() ? QWebSocketServer::NonSecureMode : QWebSocketServer::SecureMode,
|
config.serverInsecure() ? QWebSocketServer::NonSecureMode : QWebSocketServer::SecureMode,
|
||||||
|
|
|
@ -22,7 +22,7 @@ class Server : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Server(PackageManagement::Manager &alpmManager, const PackageManagement::Config &config, QObject *parent = nullptr);
|
Server(const PackageManagement::Manager &alpmManager, const PackageManagement::Config &config, QObject *parent = nullptr);
|
||||||
~Server();
|
~Server();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
@ -34,7 +34,7 @@ private slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QWebSocketServer *m_server;
|
QWebSocketServer *m_server;
|
||||||
PackageManagement::Manager &m_alpmManager;
|
const PackageManagement::Manager &m_alpmManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +1,36 @@
|
||||||
{// ALPM related config
|
{
|
||||||
alpm: {
|
"alpm": {
|
||||||
// the root directory for ALPM
|
"rootDir": "/",
|
||||||
//rootDir: "/",
|
"dbPath": "/var/lib/pacman",
|
||||||
|
"pacmanConfigFile": "/etc/pacman.conf"
|
||||||
|
},
|
||||||
|
|
||||||
// the database directory for ALPM
|
"aur": {
|
||||||
//dbPath: "/var/lib/pacman/",
|
"enabled": true
|
||||||
|
},
|
||||||
|
|
||||||
// the pacman config file
|
"server": {
|
||||||
//pacmanConfigFile: "/etc/pacman.conf"
|
"listeningPort": 1234,
|
||||||
},
|
"certFile": "some.cert",
|
||||||
|
"keyFile": "some.key",
|
||||||
|
"insecure": false
|
||||||
|
},
|
||||||
|
|
||||||
// server related config
|
"repos": {
|
||||||
server: {
|
"fromPacmanConfig": true,
|
||||||
// the listening port
|
|
||||||
//listeningPort: 1234,
|
|
||||||
|
|
||||||
// the SSL certificate
|
"add": [
|
||||||
//certFile: "some.cert",
|
{"name": "examplerepo",
|
||||||
|
"dataBaseFile": "path/to/database/file",
|
||||||
// the private SSL key
|
"sourcesDir": "path/to/local/source/dir",
|
||||||
//keyFile: "some.key",
|
"packagesDir": "path/to/local/pkg/dir",
|
||||||
|
"upgradeSources": ["aur"],
|
||||||
// forces the server to run in insecure mode
|
"server": [
|
||||||
//insecure: false
|
"https://some/mirror",
|
||||||
}
|
"https://another/mirror"
|
||||||
|
]
|
||||||
// repositories related config
|
}
|
||||||
repos: {
|
]
|
||||||
// indicates whether the repositories listed in
|
}
|
||||||
// the pacman config file should be loaded
|
|
||||||
//fromPacmanConfig: true,
|
|
||||||
|
|
||||||
// lists additional repos to be loaded
|
|
||||||
add: [
|
|
||||||
/* example repo entry
|
|
||||||
{name: "reponame",
|
|
||||||
dbpath: "path/to/database/file",
|
|
||||||
srcpath: "path/to/local/source/files",
|
|
||||||
pkgpath: "path/to/local/pkg/files",
|
|
||||||
servers: [
|
|
||||||
"https://some/mirror",
|
|
||||||
"https://another/mirror
|
|
||||||
]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ TEMPLATE = app
|
||||||
|
|
||||||
CONFIG += console # enables qDebug()
|
CONFIG += console # enables qDebug()
|
||||||
|
|
||||||
QT += core network websockets
|
QT += core network websockets concurrent KArchive
|
||||||
|
|
||||||
SOURCES += main.cpp \
|
SOURCES += main.cpp \
|
||||||
alpm/manager.cpp \
|
alpm/manager.cpp \
|
||||||
|
@ -23,8 +23,10 @@ SOURCES += main.cpp \
|
||||||
network/connection.cpp \
|
network/connection.cpp \
|
||||||
alpm/group.cpp \
|
alpm/group.cpp \
|
||||||
alpm/config.cpp \
|
alpm/config.cpp \
|
||||||
network/query.cpp \
|
network/aurquery.cpp \
|
||||||
network/aurquery.cpp
|
alpm/updatelookup.cpp \
|
||||||
|
alpm/resolvebuildorder.cpp \
|
||||||
|
alpm/mingwbundle.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
alpm/manager.h \
|
alpm/manager.h \
|
||||||
|
@ -36,8 +38,10 @@ HEADERS += \
|
||||||
network/connection.h \
|
network/connection.h \
|
||||||
alpm/group.h \
|
alpm/group.h \
|
||||||
alpm/config.h \
|
alpm/config.h \
|
||||||
network/query.h \
|
network/aurquery.h \
|
||||||
network/aurquery.h
|
alpm/updatelookup.h \
|
||||||
|
alpm/resolvebuildorder.h \
|
||||||
|
alpm/mingwbundle.h
|
||||||
|
|
||||||
DISTFILES += \
|
DISTFILES += \
|
||||||
README.md \
|
README.md \
|
||||||
|
@ -58,9 +62,9 @@ DISTFILES += \
|
||||||
|
|
||||||
# libs and includepath
|
# libs and includepath
|
||||||
CONFIG(debug, debug|release) {
|
CONFIG(debug, debug|release) {
|
||||||
LIBS += -L../../ -lc++utilitiesd -lalpm
|
LIBS += -L../../ -lc++utilitiesd -lalpm -lKF5Archive
|
||||||
} else {
|
} else {
|
||||||
LIBS += -L../../ -lc++utilities -lalpm
|
LIBS += -L../../ -lc++utilities -lalpm -lKF5Archive
|
||||||
}
|
}
|
||||||
INCLUDEPATH += ../
|
INCLUDEPATH += ../
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,10 @@ span.glyphicon {
|
||||||
.navbar-fixed-top {
|
.navbar-fixed-top {
|
||||||
border-bottom: 5px solid #337ab7;
|
border-bottom: 5px solid #337ab7;
|
||||||
}
|
}
|
||||||
|
.navbar-form {
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Package info
|
* Package info
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
</button>
|
</button>
|
||||||
<a class="navbar-brand" href="#">Repository index</a>
|
<!--<a class="navbar-brand collapsed" href="#">Repository index</a>-->
|
||||||
</div>
|
</div>
|
||||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
<button type="button" class="close" onclick="repoindex.pageManager.hideErrors()" aria-label="Close">
|
<button type="button" class="close" onclick="repoindex.pageManager.hideErrors()" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
<strong>Errors</strong>
|
<strong>Notifications</strong>
|
||||||
<ul id="error_list"></ul>
|
<ul id="error_list"></ul>
|
||||||
</div>
|
</div>
|
||||||
<!-- repositories -->
|
<!-- repositories -->
|
||||||
|
@ -232,8 +232,9 @@
|
||||||
<tr><th>Package count</th><td id="repo_pkgcount"></td></tr>
|
<tr><th>Package count</th><td id="repo_pkgcount"></td></tr>
|
||||||
<tr><th>Usage</th><td id="repo_usage"></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>Signature level</th><td id="repo_siglevel"></td></tr>
|
||||||
|
<tr><th>Upgrade sources</th><td id="repo_upgrade_sources"></td></tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Updates</th>
|
<th>Upgrades</th>
|
||||||
<td><span id="repo_checkforupdates"></span></td>
|
<td><span id="repo_checkforupdates"></span></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
var repoindex = (function(repoindex) {
|
var repoindex = (function(repoindex) {
|
||||||
|
|
||||||
|
repoindex.removeFilterButtonHtml = '<button type="button" class="close" onclick="repoindex.pageManager.applySearchTerm(null, false, true);" aria-label="Close"><span aria-hidden="true">×</span></button>';
|
||||||
|
|
||||||
repoindex.Entry = function(info, enabled) {
|
repoindex.Entry = function(info, enabled) {
|
||||||
// basic initialization
|
// basic initialization
|
||||||
this.info = info;
|
this.info = info;
|
||||||
|
@ -82,15 +84,15 @@
|
||||||
|
|
||||||
// provide functions to apply filter and update UI
|
// provide functions to apply filter and update UI
|
||||||
this.applyFilter = function() {
|
this.applyFilter = function() {
|
||||||
if(this.customSelection) {
|
//if(this.customSelection) {
|
||||||
this.filteredEntries = this.customSelection;
|
// this.filteredEntries = this.customSelection;
|
||||||
} else {
|
//} else {
|
||||||
if((this.filterName || this.filterRepos) && this.filterPred) {
|
if((this.filterName || this.filterRepos) && this.filterPred) {
|
||||||
this.filteredEntries = this.entries.filter(this.filterPred, this);
|
this.filteredEntries = this.relevantEntries().filter(this.filterPred, this);
|
||||||
} else {
|
} else {
|
||||||
this.filteredEntries = this.entries;
|
this.filteredEntries = this.relevantEntries();
|
||||||
}
|
}
|
||||||
}
|
//}
|
||||||
// update pagination (the pageSelected method defined above will be invoked here automatically)
|
// update pagination (the pageSelected method defined above will be invoked here automatically)
|
||||||
this.pagination.entryCount = this.filteredEntries.length;
|
this.pagination.entryCount = this.filteredEntries.length;
|
||||||
this.pagination.update();
|
this.pagination.update();
|
||||||
|
@ -140,17 +142,16 @@
|
||||||
} else {
|
} else {
|
||||||
var entryText = this.customSelection ? (this.filteredEntries.length === 1 ? this.customSelectionName : this.customSelectionNamePlural) : (this.filteredEntries.length === 1 ? this.entryName : this.entryNamePlural);
|
var entryText = this.customSelection ? (this.filteredEntries.length === 1 ? this.customSelectionName : this.customSelectionNamePlural) : (this.filteredEntries.length === 1 ? this.entryName : this.entryNamePlural);
|
||||||
if(this.filterDescr) {
|
if(this.filterDescr) {
|
||||||
var removeFilterButton = '<button type="button" class="close" onclick="repoindex.pageManager.applySearchTerm()" aria-label="Close"><span aria-hidden="true">×</span></button>';
|
|
||||||
if(this.filterName) {
|
if(this.filterName) {
|
||||||
return "<b>" + this.filteredEntries.length + "</b> " + entryText
|
return "<b>" + this.filteredEntries.length + "</b> " + entryText
|
||||||
+ containerText + " "
|
+ containerText + " "
|
||||||
+ repoindex.escapeHtml(this.filterDescr) + " <i>"+ repoindex.escapeHtml(this.filterName) + "</i>."
|
+ repoindex.escapeHtml(this.filterDescr) + " <i>"+ repoindex.escapeHtml(this.filterName) + "</i>."
|
||||||
+ removeFilterButton;
|
+ repoindex.removeFilterButtonHtml;
|
||||||
} else {
|
} else {
|
||||||
return "<b>" + this.filteredEntries.length + "</b> " + entryText
|
return "<b>" + this.filteredEntries.length + "</b> " + entryText
|
||||||
+ containerText + " "
|
+ containerText + " "
|
||||||
+ repoindex.escapeHtml(this.filterDescr) + "."
|
+ repoindex.escapeHtml(this.filterDescr) + "."
|
||||||
+ removeFilterButton;
|
+ repoindex.removeFilterButtonHtml;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return "Showing <b>"
|
return "Showing <b>"
|
||||||
|
|
|
@ -22,13 +22,13 @@
|
||||||
this.initTableRow = function() {
|
this.initTableRow = function() {
|
||||||
var values = [this.info.arch, this.info.repo, this.info.name, this.info.ver, this.info.desc, this.info.bdate, ""];
|
var values = [this.info.arch, this.info.repo, this.info.name, this.info.ver, this.info.desc, this.info.bdate, ""];
|
||||||
for(var i = 0; i < 7; ++i) {
|
for(var i = 0; i < 7; ++i) {
|
||||||
this.rowElement.addCell(values[i]);
|
this.rowElement.addCell(repoindex.makeStr(values[i]));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.initTableRow();
|
this.initTableRow();
|
||||||
|
|
||||||
this.applyBasicInfo = function(info) {
|
this.applyBasicInfo = function(info, noUpdate) {
|
||||||
if(info.repo) this.info.repo = info.repo;
|
if(info.repo) this.info.repo = info.repo;
|
||||||
if(info.name) this.info.name = info.name;
|
if(info.name) this.info.name = info.name;
|
||||||
if(info.arch) this.info.arch = info.arch;
|
if(info.arch) this.info.arch = info.arch;
|
||||||
|
@ -36,10 +36,12 @@
|
||||||
if(info.desc) this.info.desc = info.desc;
|
if(info.desc) this.info.desc = info.desc;
|
||||||
if(info.bdate) this.info.bdate = info.bdate;
|
if(info.bdate) this.info.bdate = info.bdate;
|
||||||
this.info.basic = true;
|
this.info.basic = true;
|
||||||
this.updateTableRow();
|
if(!noUpdate) {
|
||||||
|
this.updateTableRow();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.applyFullInfo = function(info) {
|
this.applyFullInfo = function(info, noUpdate) {
|
||||||
this.applyBasicInfo(info);
|
this.applyBasicInfo(info);
|
||||||
if(info.idate) this.info.idate = info.idate;
|
if(info.idate) this.info.idate = info.idate;
|
||||||
if(info.isize) this.info.isize = info.isize;
|
if(info.isize) this.info.isize = info.isize;
|
||||||
|
@ -60,7 +62,9 @@
|
||||||
if(info.file) this.info.file = info.file;
|
if(info.file) this.info.file = info.file;
|
||||||
if(info.files) this.info.files = info.files;
|
if(info.files) this.info.files = info.files;
|
||||||
this.info.full = true;
|
this.info.full = true;
|
||||||
this.updateTableRow();
|
if(!noUpdate) {
|
||||||
|
this.updateTableRow();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,13 +86,13 @@
|
||||||
this.addEntry = function(repoName, packageName) {
|
this.addEntry = function(repoName, packageName) {
|
||||||
var packageInfo = {
|
var packageInfo = {
|
||||||
index: this.entries.length,
|
index: this.entries.length,
|
||||||
arch: "",
|
arch: undefined,
|
||||||
repo: repoName,
|
repo: repoName,
|
||||||
name: packageName,
|
name: packageName,
|
||||||
version: "",
|
version: undefined,
|
||||||
desc: "",
|
desc: undefined,
|
||||||
builddate: "",
|
builddate: undefined,
|
||||||
flagdate: "",
|
flagdate: undefined,
|
||||||
received: false
|
received: false
|
||||||
};
|
};
|
||||||
this.entries.push(new PackageEntry(packageInfo));
|
this.entries.push(new PackageEntry(packageInfo));
|
||||||
|
@ -169,7 +173,7 @@
|
||||||
if(i.url) {
|
if(i.url) {
|
||||||
repoindex.setLink("pkg_url", i.url, i.url, window.open);
|
repoindex.setLink("pkg_url", i.url, i.url, window.open);
|
||||||
} else {
|
} else {
|
||||||
repoindex.setText("pkg_url", "none");
|
repoindex.setText("pkg_url", "unknown");
|
||||||
}
|
}
|
||||||
repoindex.setText("pkg_lic", repoindex.makeArray(i.lic));
|
repoindex.setText("pkg_lic", repoindex.makeArray(i.lic));
|
||||||
repoindex.setPackageNames("pkg_grp", repoindex.pack(i.grp), repoindex.Pages.Groups);
|
repoindex.setPackageNames("pkg_grp", repoindex.pack(i.grp), repoindex.Pages.Groups);
|
||||||
|
@ -208,7 +212,15 @@
|
||||||
entry.applyFullInfo(info);
|
entry.applyFullInfo(info);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
repoindex.pageManager.addError("Error: " + info.error);
|
var errorMsg;
|
||||||
|
switch(info.error) {
|
||||||
|
case "na":
|
||||||
|
errorMsg = "The server can't find the requested (full) package info."
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errorMsg = "The server can't deliver the requested (full) package info."
|
||||||
|
};
|
||||||
|
repoindex.pageManager.addError("Error: " + errorMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// set properties (again) to actually show applied info
|
// set properties (again) to actually show applied info
|
||||||
|
@ -260,8 +272,9 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
this.showMirrorsForIndex = function(entryIndex) {
|
this.showMirrorsForIndex = function(entryIndex) {
|
||||||
if(entryIndex >= 0 && entryIndex < this.entries.length) {
|
var entry = this.entryByIndex(entryIndex);
|
||||||
var info = this.entries[entryIndex].info;
|
if(entry) {
|
||||||
|
var info = entry.info;
|
||||||
repoindex.setText("title_mirror_selection", "Mirrors for package <i>" + repoindex.escapeHtml(info.name) + "</i>", true);
|
repoindex.setText("title_mirror_selection", "Mirrors for package <i>" + repoindex.escapeHtml(info.name) + "</i>", true);
|
||||||
var listMirrorSelection = document.getElementById("list_mirror_selection");
|
var listMirrorSelection = document.getElementById("list_mirror_selection");
|
||||||
listMirrorSelection.wipeChildren();
|
listMirrorSelection.wipeChildren();
|
||||||
|
@ -286,19 +299,29 @@
|
||||||
listMirrorSelection.appendChild(liElement);
|
listMirrorSelection.appendChild(liElement);
|
||||||
}
|
}
|
||||||
mirrorsAvailable = 1;
|
mirrorsAvailable = 1;
|
||||||
} else if(info.repo === "local") {
|
|
||||||
mirrorsAvailable = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(mirrorsAvailable === 1) {
|
|
||||||
repoindex.setText("status_mirror_selection", "Select a mirror:");
|
|
||||||
} else if(mirrorsAvailable === -1) {
|
|
||||||
repoindex.setText("status_mirror_selection", "The package entry belongs to the <i>local</i> database. Hence there are no mirrors available.", true);
|
|
||||||
} else {
|
|
||||||
repoindex.setText("status_mirror_selection", "No mirrors available.");
|
|
||||||
}
|
|
||||||
$("#dlg_mirror_selection").modal("show");
|
|
||||||
}
|
}
|
||||||
|
if(mirrorsAvailable !== 1) {
|
||||||
|
// no mirrors available?
|
||||||
|
if(info.repo === "local" || info.repo === "LOCAL") {
|
||||||
|
// no surprise because its an package from the local database
|
||||||
|
mirrorsAvailable = -1;
|
||||||
|
} else if(info.repo === "aur" || info.repo === "AUR") {
|
||||||
|
// no surprise because its an AUR package
|
||||||
|
mirrorsAvailable = -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(mirrorsAvailable === 1) {
|
||||||
|
repoindex.setText("status_mirror_selection", "Select a mirror:");
|
||||||
|
} else if(mirrorsAvailable === -1) {
|
||||||
|
repoindex.setText("status_mirror_selection", "The package belongs to the <i>local</i> database. Hence there are no mirrors available.", true);
|
||||||
|
} else if(mirrorsAvailable === -2) {
|
||||||
|
repoindex.setText("status_mirror_selection", "The package is from the <i>Arch Linux User Repository</i>. Hence there are no mirrors available.", true);
|
||||||
|
} else {
|
||||||
|
repoindex.setText("status_mirror_selection", "No mirrors available.");
|
||||||
|
}
|
||||||
|
$("#dlg_mirror_selection").modal("show");
|
||||||
};
|
};
|
||||||
|
|
||||||
this.showPackageNotFound = function(repo, name) {
|
this.showPackageNotFound = function(repo, name) {
|
||||||
|
|
|
@ -234,7 +234,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
// provide a function to apply an entered search term
|
// provide a function to apply an entered search term
|
||||||
this.applySearchTerm = function(searchTerm, exact) {
|
this.applySearchTerm = function(searchTerm, exact, reset) {
|
||||||
var mgr = undefined;
|
var mgr = undefined;
|
||||||
switch(this.currentPage) {
|
switch(this.currentPage) {
|
||||||
case repoindex.Pages.Packages:
|
case repoindex.Pages.Packages:
|
||||||
|
@ -250,7 +250,9 @@
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
if(mgr) {
|
if(mgr) {
|
||||||
mgr.customSelection = undefined;
|
if(reset) {
|
||||||
|
mgr.customSelection = undefined;
|
||||||
|
}
|
||||||
mgr.filterName = searchTerm;
|
mgr.filterName = searchTerm;
|
||||||
mgr.filterNameExact = exact;
|
mgr.filterNameExact = exact;
|
||||||
mgr.filterDescr = searchTerm ? (exact ? "with the name" : "for the search term") : undefined;
|
mgr.filterDescr = searchTerm ? (exact ? "with the name" : "for the search term") : undefined;
|
||||||
|
|
|
@ -175,6 +175,7 @@
|
||||||
repoindex.setText("repo_pkgcount", i.packages.length);
|
repoindex.setText("repo_pkgcount", i.packages.length);
|
||||||
repoindex.setText("repo_usage", repoindex.makeArray(i.usage, ", "));
|
repoindex.setText("repo_usage", repoindex.makeArray(i.usage, ", "));
|
||||||
repoindex.setText("repo_siglevel", repoindex.makeArray(i.sigLevel, ", "));
|
repoindex.setText("repo_siglevel", repoindex.makeArray(i.sigLevel, ", "));
|
||||||
|
repoindex.setText("repo_upgrade_sources", repoindex.makeArray(i.upgradeSources, ", "));
|
||||||
var invokeUpdateLookupParams = {repo: i.name, invoke: "updatelookup"};
|
var invokeUpdateLookupParams = {repo: i.name, invoke: "updatelookup"};
|
||||||
repoindex.setDownloadButton("repo_checkforupdates", "check for updates", repoindex.makeHash(repoindex.Pages.Repositories, invokeUpdateLookupParams, true), function() {
|
repoindex.setDownloadButton("repo_checkforupdates", "check for updates", repoindex.makeHash(repoindex.Pages.Repositories, invokeUpdateLookupParams, true), function() {
|
||||||
repoindex.pageManager.repoManager.showAvailableUpdates(i.name);
|
repoindex.pageManager.repoManager.showAvailableUpdates(i.name);
|
||||||
|
@ -241,7 +242,15 @@
|
||||||
for(var i2 = 0; i2 < updates[i1].entries.length; ++i2) {
|
for(var i2 = 0; i2 < updates[i1].entries.length; ++i2) {
|
||||||
var newEntry = pkgMgr.createCustomEntry(updates[i1].color);
|
var newEntry = pkgMgr.createCustomEntry(updates[i1].color);
|
||||||
newEntry.info.index = updateEntries.length;
|
newEntry.info.index = updateEntries.length;
|
||||||
newEntry.applyBasicInfo(updates[i1].entries[i2]);
|
if(updates[i1].entries[i2].pkg) {
|
||||||
|
newEntry.applyBasicInfo(updates[i1].entries[i2].pkg, true);
|
||||||
|
if(updates[i1].entries[i2].prevVersion) {
|
||||||
|
newEntry.info.ver = updates[i1].entries[i2].prevVersion + " → " + (newEntry.info.ver ? newEntry.info.ver : "?");
|
||||||
|
}
|
||||||
|
newEntry.updateTableRow();
|
||||||
|
} else {
|
||||||
|
newEntry.applyBasicInfo(updates[i1].entries[i2]);
|
||||||
|
}
|
||||||
updateEntries.push(newEntry);
|
updateEntries.push(newEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,14 +260,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// show updates via package manager
|
// show updates via package manager
|
||||||
|
pkgMgr.filterName = undefined;
|
||||||
pkgMgr.customSelection = updateEntries;
|
pkgMgr.customSelection = updateEntries;
|
||||||
pkgMgr.customSelectionName = "upgrade";
|
pkgMgr.customSelectionName = "upgrade";
|
||||||
pkgMgr.customSelectionNamePlural = "upgrades";
|
pkgMgr.customSelectionNamePlural = "upgrades";
|
||||||
var quandityInfo = repoindex.makeQuandityInfo(updates);
|
var quandityInfo = repoindex.makeQuandityInfo(updates);
|
||||||
if(quandityInfo) {
|
if(quandityInfo) {
|
||||||
pkgMgr.customSelectionInfoText = "Updates for the repository <i>" + repoindex.escapeHtml(repo) + "</i>: " + quandityInfo;
|
pkgMgr.customSelectionInfoText = "Updates for the repository <i>"
|
||||||
|
+ repoindex.escapeHtml(repo)
|
||||||
|
+ "</i>: " + quandityInfo
|
||||||
|
+ repoindex.removeFilterButtonHtml;
|
||||||
}
|
}
|
||||||
pkgMgr.filterName = repo;
|
|
||||||
pkgMgr.filterDescr = "for the repository"
|
pkgMgr.filterDescr = "for the repository"
|
||||||
pkgMgr.invalidate();
|
pkgMgr.invalidate();
|
||||||
repoindex.pageManager.setPage(repoindex.Pages.Packages);
|
repoindex.pageManager.setPage(repoindex.Pages.Packages);
|
||||||
|
|
|
@ -212,8 +212,8 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
repoindex.makeStr = function(str) {
|
repoindex.makeStr = function(str, na) {
|
||||||
return str ? str : "";
|
return str ? str : (na ? na : "unknown");
|
||||||
};
|
};
|
||||||
|
|
||||||
repoindex.makeArray = function(array, separator) {
|
repoindex.makeArray = function(array, separator) {
|
||||||
|
@ -234,7 +234,7 @@
|
||||||
return (sizeInByte / 1099511627776.0).toFixed(2) + " TiB";
|
return (sizeInByte / 1099511627776.0).toFixed(2) + " TiB";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "unknown";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue