added suggestions lookup, added src info parser
This commit is contained in:
parent
0d20332542
commit
715633c96e
|
@ -58,8 +58,8 @@ PackageLoader::PackageLoader(AlpmDatabase *db)
|
|||
/*!
|
||||
* \brief Creates a new instance wrapping the specified database struct.
|
||||
*/
|
||||
RepoIndex::AlpmDatabase::AlpmDatabase(alpm_db_t *dataBase, const QString &dbPath, QObject *parent) :
|
||||
Repository(QString::fromLocal8Bit(alpm_db_get_name(dataBase)), parent),
|
||||
RepoIndex::AlpmDatabase::AlpmDatabase(alpm_db_t *dataBase, const QString &dbPath, uint32 index, QObject *parent) :
|
||||
Repository(QString::fromLocal8Bit(alpm_db_get_name(dataBase)), index, parent),
|
||||
m_ptr(dataBase),
|
||||
m_dbFile(QStringLiteral("%1/sync/%2").arg(dbPath, m_name))
|
||||
{}
|
||||
|
|
|
@ -35,8 +35,9 @@ inline QFuture<void> &PackageLoader::future()
|
|||
class AlpmDatabase : public Repository
|
||||
{
|
||||
friend class EmplacePackage;
|
||||
|
||||
public:
|
||||
explicit AlpmDatabase(alpm_db_t *dataBase, const QString &dbPath, QObject *parent = nullptr);
|
||||
explicit AlpmDatabase(alpm_db_t *dataBase, const QString &dbPath, uint32 index = invalidIndex, QObject *parent = nullptr);
|
||||
PackageLoader *init();
|
||||
// explicit AlpmDatabase(const QString &dataBaseFile, QObject *parent = nullptr);
|
||||
|
||||
|
@ -112,7 +113,7 @@ inline bool AlpmDatabase::setServers(StringList servers)
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Performs a search using the build in ALPM function.
|
||||
* \brief Performs a search using the build-in ALPM function.
|
||||
*/
|
||||
inline PackageList AlpmDatabase::search(StringList terms) const
|
||||
{
|
||||
|
|
|
@ -37,6 +37,13 @@ AurPackage::AurPackage(const QJsonValue &aurJsonValue, UserRepository *repositor
|
|||
m_tarUrl = obj.value(QStringLiteral("URLPath")).toString();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates a new instance where only the name is known.
|
||||
*/
|
||||
AurPackage::AurPackage(const QString &name, UserRepository *repository) :
|
||||
Package(name, repository)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Creates a new, empty instance.
|
||||
* \remarks The only purpose of this c'tor is to use it with restoreFromCacheStream().
|
||||
|
|
|
@ -10,8 +10,9 @@ class UserRepository;
|
|||
class AurPackage : public Package
|
||||
{
|
||||
public:
|
||||
AurPackage(const QJsonValue &aurJsonValue, UserRepository *repository);
|
||||
AurPackage(UserRepository *repository);
|
||||
explicit AurPackage(const QJsonValue &aurJsonValue, UserRepository *repository);
|
||||
explicit AurPackage(const QString &name, UserRepository *repository);
|
||||
explicit AurPackage(UserRepository *repository);
|
||||
};
|
||||
|
||||
} // namespace PackageManagement
|
||||
|
|
|
@ -49,6 +49,8 @@ ConfigArgs::ConfigArgs(ArgumentParser &parser) :
|
|||
targetNameArg("target-name", "n", "specifies the name of the target archive"),
|
||||
targetFormatArg("target-format", "e", "specifies the format of the target archive"),
|
||||
iconThemesArg("icon-packages", "i", "specifies the names of the icon packages to include"),
|
||||
defaultIconThemeArg("default-icon-theme", string(), "specifies the name of the default icon theme (should be included in --icon-packages)"),
|
||||
extraPackagesArg("extra-packages", string(), "specifies extra packages to be included"),
|
||||
shSyntaxArg("sh-syntax", string(), "prints the output using shell syntax: export REPOINDEX_RESULTS=('res1' 'res2' 'res3') or export REPOINDEX_ERROR='some error message'"),
|
||||
repoArg("repo", string(), "specifies the repository")
|
||||
{
|
||||
|
@ -110,13 +112,19 @@ ConfigArgs::ConfigArgs(ArgumentParser &parser) :
|
|||
iconThemesArg.setCombinable(true);
|
||||
iconThemesArg.setRequiredValueCount(-1);
|
||||
iconThemesArg.setValueNames(pkgValueNames);
|
||||
defaultIconThemeArg.setCombinable(true);
|
||||
defaultIconThemeArg.setRequiredValueCount(1);
|
||||
defaultIconThemeArg.setValueNames({"theme name"});
|
||||
extraPackagesArg.setCombinable(true);
|
||||
extraPackagesArg.setRequiredValueCount(-1);
|
||||
extraPackagesArg.setValueNames(pkgValueNames);
|
||||
shSyntaxArg.setCombinable(true);
|
||||
repoArg.setRequiredValueCount(1);
|
||||
repoArg.setValueNames({"repo name"});
|
||||
serverArg.setSecondaryArguments({&rootdirArg, &dbpathArg, &pacmanConfArg, &certFileArg, &keyFileArg, &websocketAddrArg, &websocketPortArg, &insecureArg, &aurArg, &shSyntaxArg});
|
||||
upgradeLookupArg.setSecondaryArguments({&shSyntaxArg});
|
||||
buildOrderArg.setSecondaryArguments({&aurArg, &verboseArg, &shSyntaxArg});
|
||||
mingwBundleArg.setSecondaryArguments({&targetDirArg, &targetNameArg, &targetFormatArg, &iconThemesArg});
|
||||
mingwBundleArg.setSecondaryArguments({&targetDirArg, &targetNameArg, &targetFormatArg, &iconThemesArg, &defaultIconThemeArg, &extraPackagesArg});
|
||||
parser.setMainArguments({&buildOrderArg, &upgradeLookupArg, &serverArg, &mingwBundleArg, &repoindexConfArg, &repoindexConfArg, &helpArg});
|
||||
}
|
||||
|
||||
|
@ -132,6 +140,7 @@ Config::Config() :
|
|||
m_alpmRootDir(QStringLiteral("/")),
|
||||
m_alpmDbPath(QStringLiteral("/var/lib/pacman")),
|
||||
m_pacmanConfFile(QStringLiteral("/etc/pacman.conf")),
|
||||
m_cacheDir(QStringLiteral(".")),
|
||||
m_websocketServerListeningAddr(QHostAddress::LocalHost),
|
||||
m_websocketServerListeningPort(1234),
|
||||
m_serverInsecure(false),
|
||||
|
|
|
@ -40,6 +40,8 @@ public:
|
|||
ApplicationUtilities::Argument targetNameArg;
|
||||
ApplicationUtilities::Argument targetFormatArg;
|
||||
ApplicationUtilities::Argument iconThemesArg;
|
||||
ApplicationUtilities::Argument defaultIconThemeArg;
|
||||
ApplicationUtilities::Argument extraPackagesArg;
|
||||
ApplicationUtilities::Argument shSyntaxArg;
|
||||
ApplicationUtilities::Argument repoArg;
|
||||
};
|
||||
|
|
175
alpm/manager.cpp
175
alpm/manager.cpp
|
@ -1,8 +1,8 @@
|
|||
#include "./manager.h"
|
||||
#include "./alpmdatabase.h"
|
||||
#include "./utilities.h"
|
||||
#include "./list.h"
|
||||
#include "./config.h"
|
||||
#include "./alpmdatabase.h"
|
||||
|
||||
#include "../network/userrepository.h"
|
||||
|
||||
|
@ -63,11 +63,7 @@ Manager::Manager(const Config &config) :
|
|||
m_sigLevel(defaultSigLevel),
|
||||
m_localFileSigLevel(ALPM_SIG_USE_DEFAULT)
|
||||
{
|
||||
alpm_errno_t err;
|
||||
if(!(m_handle = alpm_initialize(config.alpmRootDir().toLocal8Bit().data(), config.alpmDbPath().toLocal8Bit().data(), &err))) {
|
||||
throw runtime_error(string("Cannot initialize ALPM: ") + alpm_strerror(err));
|
||||
}
|
||||
m_localDb = make_unique<AlpmDatabase>(alpm_get_localdb(m_handle), config.alpmDbPath());
|
||||
initAlpmHandle();
|
||||
if(config.isAurEnabled()) {
|
||||
m_userRepo = make_unique<UserRepository>(m_networkAccessManager);
|
||||
}
|
||||
|
@ -81,7 +77,7 @@ Manager::~Manager()
|
|||
if(m_writeCacheBeforeGone) {
|
||||
writeCache();
|
||||
}
|
||||
alpm_release(m_handle);
|
||||
cleanupAlpm();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -289,9 +285,9 @@ int Manager::parseUsage(const string &usageStr)
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Parses and applies the Pacman configuration. Registers the listed sync databases.
|
||||
* \brief Registers sync databases listed in the Pacman config file. Also reads the cache dir.
|
||||
*/
|
||||
void Manager::applyPacmanConfig()
|
||||
void Manager::registerDataBasesFromPacmanConfig()
|
||||
{
|
||||
// open config file and parse as ini
|
||||
try {
|
||||
|
@ -309,21 +305,21 @@ void Manager::applyPacmanConfig()
|
|||
// read relevant options
|
||||
static const string sigLevelKey("SigLevel");
|
||||
static const string usageKey("Usage");
|
||||
int globalSigLevel;
|
||||
try {
|
||||
const auto &options = config.at("options");
|
||||
const auto &specifiedArch = lastValue(options, "Architecture");
|
||||
if(!specifiedArch.empty() && specifiedArch != "auto") {
|
||||
arch = specifiedArch;
|
||||
int globalSigLevel = defaultSigLevel;
|
||||
for(auto &scope : config) {
|
||||
if(scope.first == "options") {
|
||||
// iterate through all "config" scopes (just to cover the case that there are multiple "options" scopes)
|
||||
const auto &options = scope.second;
|
||||
const auto &specifiedArch = lastValue(options, "Architecture");
|
||||
if(!specifiedArch.empty() && specifiedArch != "auto") {
|
||||
arch = specifiedArch;
|
||||
}
|
||||
const auto &specifiedDir = lastValue(options, "CacheDir");
|
||||
if(!specifiedDir.empty()) {
|
||||
m_pacmanCacheDir = QString::fromStdString(specifiedDir);
|
||||
}
|
||||
globalSigLevel = parseSigLevel(lastValue(options, sigLevelKey));
|
||||
}
|
||||
const auto &specifiedDir = lastValue(options, "CacheDir");
|
||||
if(!specifiedDir.empty()) {
|
||||
m_pacmanCacheDir = QString::fromStdString(specifiedDir);
|
||||
}
|
||||
globalSigLevel = parseSigLevel(lastValue(options, sigLevelKey));
|
||||
} catch(const out_of_range &) {
|
||||
// no options specified
|
||||
globalSigLevel = defaultSigLevel;
|
||||
}
|
||||
// register sync databases
|
||||
unordered_map<string, IniFile> includedInis;
|
||||
|
@ -347,7 +343,7 @@ void Manager::applyPacmanConfig()
|
|||
// set usage
|
||||
if(alpm_db_set_usage(db, static_cast<alpm_db_usage_t>(usage)) == 0) {
|
||||
if(m_config.isVerbose() || m_config.runServer()) {
|
||||
cerr << shchar << "Added database [" << scope.first << "]" << endl;
|
||||
cerr << shchar << "Added database [" << scope.first << ']' << endl;
|
||||
}
|
||||
} else {
|
||||
if(m_config.isVerbose() || m_config.runServer()) {
|
||||
|
@ -379,28 +375,31 @@ void Manager::applyPacmanConfig()
|
|||
}
|
||||
}
|
||||
try {
|
||||
const auto &includedScope = includedIni.data().at(string());
|
||||
for(auto range = includedScope.equal_range("Server"); range.first != range.second; ++range.first) {
|
||||
string url = range.first->second;
|
||||
findAndReplace<string>(url, "$repo", scope.first);
|
||||
findAndReplace<string>(url, "$arch", arch);
|
||||
alpm_db_add_server(db, url.c_str());
|
||||
if(m_config.isVerbose() || m_config.runServer()) {
|
||||
cerr << shchar << "Added server: " << url << endl;
|
||||
for(auto &scope : includedIni.data()) {
|
||||
if(scope.first.empty()) {
|
||||
for(auto range = scope.second.equal_range("Server"); range.first != range.second; ++range.first) {
|
||||
string url = range.first->second;
|
||||
findAndReplace<string>(url, "$repo", scope.first);
|
||||
findAndReplace<string>(url, "$arch", arch);
|
||||
alpm_db_add_server(db, url.c_str());
|
||||
if(m_config.isVerbose() || m_config.runServer()) {
|
||||
cerr << shchar << "Added server: " << url << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const out_of_range &) {
|
||||
cerr << shchar << "Warning: Included file \"" << path << "\" has no values." << endl;
|
||||
}
|
||||
}
|
||||
auto emplaced = m_syncDbs.emplace(dbName, make_unique<AlpmDatabase>(db, m_config.alpmDbPath()));
|
||||
// add sync db to internal map
|
||||
// add sync db to internal map (use as index size + 1 because the local database has index 0)
|
||||
auto emplaced = m_syncDbs.emplace(dbName, make_unique<AlpmDatabase>(db, m_config.alpmDbPath(), m_syncDbs.size() + 1));
|
||||
if(usage & ALPM_DB_USAGE_UPGRADE) {
|
||||
// -> db is used to upgrade local database
|
||||
localDataBase()->upgradeSources() << emplaced.first->second.get();
|
||||
}
|
||||
} else {
|
||||
cerr << shchar << "Error: Unable to add sync database [" << scope.first << "]" << endl;
|
||||
cerr << shchar << "Error: Unable to add sync database [" << scope.first << ']' << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -411,16 +410,16 @@ void Manager::applyPacmanConfig()
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Applies the repository index configuration.
|
||||
* \brief Registers sync databases listed in the repository index configuration.
|
||||
*/
|
||||
void Manager::applyRepoIndexConfig()
|
||||
void Manager::registerDatabasesFromRepoIndexConfig()
|
||||
{
|
||||
// check whether an entry already exists, if not create a new one
|
||||
for(const RepoEntry &repoEntry : m_config.repoEntries()) {
|
||||
AlpmDatabase *syncDb = nullptr;
|
||||
try {
|
||||
syncDb = m_syncDbs.at(repoEntry.name()).get();
|
||||
cerr << shchar << "Applying config for database [" << syncDb->name() << "]" << endl;
|
||||
cerr << shchar << "Applying config for database [" << syncDb->name() << ']' << endl;
|
||||
if(!repoEntry.dataBasePath().isEmpty()) {
|
||||
cerr << shchar << "Warning: Can't use data base path specified in repo index config because the repo \""
|
||||
<< repoEntry.name() << "\" has already been added from the Pacman config." << endl;
|
||||
|
@ -439,13 +438,13 @@ void Manager::applyRepoIndexConfig()
|
|||
} else {
|
||||
// TODO: database path
|
||||
auto *db = alpm_register_syncdb(m_handle, repoEntry.name().toLocal8Bit().data(), static_cast<alpm_siglevel_t>(repoEntry.sigLevel()));
|
||||
auto emplaced = m_syncDbs.emplace(repoEntry.name(), make_unique<AlpmDatabase>(db, m_config.alpmDbPath()));
|
||||
auto emplaced = m_syncDbs.emplace(repoEntry.name(), make_unique<AlpmDatabase>(db, m_config.alpmDbPath(), m_syncDbs.size() + 1));
|
||||
if(emplaced.second) {
|
||||
syncDb = emplaced.first->second.get();
|
||||
syncDb->setSourcesDirectory(repoEntry.sourceDir());
|
||||
syncDb->setPackagesDirectory(repoEntry.packageDir());
|
||||
if(m_config.isVerbose() || m_config.runServer()) {
|
||||
cerr << shchar << "Added database [" << repoEntry.name() << "]" << endl;
|
||||
cerr << shchar << "Added database [" << repoEntry.name() << ']' << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -556,7 +555,7 @@ void Manager::unregisterSyncDataBases()
|
|||
* \brief Returns a list of all sync databases.
|
||||
* \remarks Sync databases must be registered with parsePacmanConfig() before.
|
||||
*/
|
||||
const map<QString, unique_ptr<AlpmDatabase> > &Manager::syncDatabases() const
|
||||
const std::map<QString, std::unique_ptr<AlpmDatabase> > &Manager::syncDatabases() const
|
||||
{
|
||||
return m_syncDbs; // m_syncDbs has been filled when the databases were registered
|
||||
}
|
||||
|
@ -567,26 +566,26 @@ const map<QString, unique_ptr<AlpmDatabase> > &Manager::syncDatabases() const
|
|||
* The results include the local database ("local") and the names of
|
||||
* the registered sync databases.
|
||||
*/
|
||||
const QJsonArray &Manager::basicRepoInfo() const
|
||||
const QJsonObject &Manager::basicRepoInfo() const
|
||||
{
|
||||
if(m_basicRepoInfo.isEmpty()) {
|
||||
QMutexLocker locker(&m_basicRepoInfoMutex);
|
||||
if(m_basicRepoInfo.isEmpty()) {
|
||||
// add local data base
|
||||
m_basicRepoInfo << localDataBase()->basicInfo();
|
||||
m_basicRepoInfo.insert(localDataBase()->name(), localDataBase()->basicInfo());
|
||||
// add sync data bases
|
||||
for(const auto &syncDb : syncDatabases()) {
|
||||
// check if the "sync" database is actually used for syncing
|
||||
auto usage = syncDb.second->usage();
|
||||
if((usage & ALPM_DB_USAGE_SYNC) || (usage & ALPM_DB_USAGE_INSTALL) || (usage & ALPM_DB_USAGE_UPGRADE)) {
|
||||
m_basicRepoInfo << syncDb.second->basicInfo();
|
||||
m_basicRepoInfo.insert(syncDb.first, syncDb.second->basicInfo());
|
||||
} else {
|
||||
m_basicRepoInfo << syncDb.second->basicInfo();
|
||||
m_basicRepoInfo.insert(syncDb.first, syncDb.second->basicInfo());
|
||||
}
|
||||
}
|
||||
// add AUR
|
||||
if(config().isAurEnabled()) {
|
||||
m_basicRepoInfo << userRepository()->basicInfo();
|
||||
if(userRepository()) {
|
||||
m_basicRepoInfo.insert(userRepository()->name(), userRepository()->basicInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -596,28 +595,33 @@ const QJsonArray &Manager::basicRepoInfo() const
|
|||
/*!
|
||||
* \brief Returns package information for the specified selection of packages.
|
||||
*/
|
||||
const QJsonArray Manager::packageInfo(const QJsonObject &pkgSelection, bool full) const
|
||||
const QJsonArray Manager::packageInfo(const QJsonObject &pkgSelection, PackageInfoPart part) const
|
||||
{
|
||||
QJsonArray pkgInfos;
|
||||
QJsonArray results;
|
||||
for(auto i = pkgSelection.constBegin(), end = pkgSelection.constEnd(); i != end; ++i) {
|
||||
if(auto *repo = repositoryByName(i.key())) {
|
||||
for(const auto &entry : i.value().toArray()) {
|
||||
const auto entryObj = entry.toObject();
|
||||
const auto pkgName = entryObj.value(QStringLiteral("name")).toString();
|
||||
if(!pkgName.isEmpty()) {
|
||||
QJsonObject pkgInfo;
|
||||
QJsonObject res;
|
||||
if(auto *pkg = repo->packageByName(pkgName)) {
|
||||
pkgInfo = full ? pkg->fullInfo() : pkg->basicInfo();
|
||||
if(part & Basics) {
|
||||
res.insert(QStringLiteral("basics"), pkg->basicInfo());
|
||||
}
|
||||
if(part & Details) {
|
||||
res.insert(QStringLiteral("details"), pkg->detailedInfo());
|
||||
}
|
||||
} else {
|
||||
pkgInfo.insert(QStringLiteral("error"), QStringLiteral("na"));
|
||||
res.insert(QStringLiteral("error"), QStringLiteral("na"));
|
||||
}
|
||||
pkgInfo.insert(QStringLiteral("name"), pkgName);
|
||||
pkgInfo.insert(QStringLiteral("repo"), repo->name());
|
||||
res.insert(QStringLiteral("name"), pkgName);
|
||||
res.insert(QStringLiteral("repo"), repo->name());
|
||||
const auto index = entryObj.value(QStringLiteral("index"));
|
||||
if(!index.isNull() && !index.isUndefined()) {
|
||||
pkgInfo.insert(QStringLiteral("index"), index);
|
||||
res.insert(QStringLiteral("index"), index);
|
||||
}
|
||||
pkgInfos << pkgInfo;
|
||||
results << res;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -625,11 +629,11 @@ const QJsonArray Manager::packageInfo(const QJsonObject &pkgSelection, bool full
|
|||
QJsonObject errorObj;
|
||||
errorObj.insert(QStringLiteral("repo"), i.key());
|
||||
errorObj.insert(QStringLiteral("error"), QStringLiteral("na"));
|
||||
pkgInfos << errorObj;
|
||||
results << errorObj;
|
||||
}
|
||||
|
||||
}
|
||||
return pkgInfos;
|
||||
return results;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -649,6 +653,33 @@ const QJsonArray &Manager::groupInfo() const
|
|||
return m_groupInfo;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initiates the ALPM library handle and databases.
|
||||
* \remarks Do not call this function, if ALPM is already initiated.
|
||||
*/
|
||||
void Manager::initAlpmHandle()
|
||||
{
|
||||
alpm_errno_t err;
|
||||
if(!(m_handle = alpm_initialize(config().alpmRootDir().toLocal8Bit().data(), config().alpmDbPath().toLocal8Bit().data(), &err))) {
|
||||
throw runtime_error(string("Cannot initialize ALPM: ") + alpm_strerror(err));
|
||||
}
|
||||
m_localDb = make_unique<AlpmDatabase>(alpm_get_localdb(m_handle), config().alpmDbPath(), 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Frees the ALPM library handle and databases.
|
||||
* \remarks Do not call any ALPM related methods except initAlpmHandle() to reinit ALPM.
|
||||
*/
|
||||
void Manager::cleanupAlpm()
|
||||
{
|
||||
if(m_handle) {
|
||||
alpm_release(m_handle);
|
||||
m_handle = 0;
|
||||
m_localDb.reset();
|
||||
m_syncDbs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the ALPM database with the specified name.
|
||||
*/
|
||||
|
@ -717,34 +748,6 @@ Repository *Manager::repositoryByName(const QString &name)
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns a list of all repositories excluding the local database.
|
||||
*/
|
||||
QList<const Repository *> Manager::repositories() const
|
||||
{
|
||||
QList<const Repository *> repos;
|
||||
repos.reserve(m_syncDbs.size() + 1);
|
||||
for(const auto &dbEntry : m_syncDbs) {
|
||||
repos << dbEntry.second.get();
|
||||
}
|
||||
repos << m_userRepo.get();
|
||||
return repos;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns a list of all repositories excluding the local database.
|
||||
*/
|
||||
QList<Repository *> Manager::repositories()
|
||||
{
|
||||
QList<Repository *> repos;
|
||||
repos.reserve(m_syncDbs.size() + 1);
|
||||
for(auto &dbEntry : m_syncDbs) {
|
||||
repos << dbEntry.second.get();
|
||||
}
|
||||
repos << m_userRepo.get();
|
||||
return repos;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks the specified database for upgrades.
|
||||
*
|
||||
|
|
|
@ -23,6 +23,13 @@ class AlpmDatabase;
|
|||
class Manager
|
||||
{
|
||||
public:
|
||||
enum PackageInfoPart {
|
||||
None = 0x0,
|
||||
Basics = 0x1,
|
||||
Details = 0x2,
|
||||
};
|
||||
Q_DECLARE_FLAGS(PackageInfoParts, PackageInfoPart)
|
||||
|
||||
explicit Manager(const Config &config);
|
||||
Manager(const Manager &other) = delete;
|
||||
Manager(Manager &&other) = delete;
|
||||
|
@ -40,8 +47,10 @@ public:
|
|||
const QString &pacmanCacheDir() const;
|
||||
static int parseSigLevel(const std::string &sigLevelStr = std::string());
|
||||
static int parseUsage(const std::string &usageStr);
|
||||
void applyPacmanConfig();
|
||||
void applyRepoIndexConfig();
|
||||
void initAlpmHandle();
|
||||
void cleanupAlpm();
|
||||
void registerDataBasesFromPacmanConfig();
|
||||
void registerDatabasesFromRepoIndexConfig();
|
||||
void initAlpmDataBases(bool computeRequiredBy);
|
||||
void writeCache();
|
||||
void restoreCache();
|
||||
|
@ -69,19 +78,15 @@ public:
|
|||
Repository *repositoryByName(const QString &name);
|
||||
const UserRepository *userRepository() const;
|
||||
UserRepository *userRepository();
|
||||
QList<const Repository *> repositories() const;
|
||||
QList<Repository *> repositories();
|
||||
const UpgradeLookupResults checkForUpgrades(AlpmDatabase *db) const;
|
||||
|
||||
// JSON serialization, handling JSON requests
|
||||
const QJsonObject basicRepoInfo(const Repository *packageSource) const;
|
||||
const QJsonArray &basicRepoInfo() const;
|
||||
const QJsonArray packageInfo(const QJsonObject &pkgSelection, bool full = true) const;
|
||||
const QJsonObject &basicRepoInfo() const;
|
||||
const QJsonArray packageInfo(const QJsonObject &pkgSelection, PackageInfoPart part) const;
|
||||
const QJsonArray &groupInfo() const;
|
||||
|
||||
private:
|
||||
void cleanup();
|
||||
|
||||
const Config &m_config;
|
||||
bool m_writeCacheBeforeGone;
|
||||
alpm_handle_t *m_handle;
|
||||
|
@ -92,12 +97,14 @@ private:
|
|||
std::unique_ptr<UserRepository> m_userRepo;
|
||||
std::unique_ptr<AlpmDatabase> m_localDb;
|
||||
std::map<QString, std::unique_ptr<AlpmDatabase> > m_syncDbs;
|
||||
mutable QJsonArray m_basicRepoInfo;
|
||||
mutable QJsonObject m_basicRepoInfo;
|
||||
mutable QMutex m_basicRepoInfoMutex;
|
||||
mutable QJsonArray m_groupInfo;
|
||||
mutable QMutex m_groupInfoMutex;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(Manager::PackageInfoParts)
|
||||
|
||||
/*!
|
||||
* \brief Returns the configuration of the manager.
|
||||
* \remarks The configuration has been specified when constructing the manager.
|
||||
|
|
|
@ -27,8 +27,9 @@ using namespace Utilities;
|
|||
|
||||
const string prefix("mingw-w64-");
|
||||
|
||||
MingwBundle::MingwBundle(const Manager &manager, const ApplicationUtilities::StringVector &packages, const ApplicationUtilities::StringVector &iconPackages) :
|
||||
m_manager(manager)
|
||||
MingwBundle::MingwBundle(Manager &manager, const ApplicationUtilities::StringVector &packages, const ApplicationUtilities::StringVector &iconPackages, const ApplicationUtilities::StringVector &extraPackages) :
|
||||
m_manager(manager),
|
||||
m_extraPackages(extraPackages)
|
||||
{
|
||||
cerr << shchar << "Resolving dependencies ..." << endl;
|
||||
string missing;
|
||||
|
@ -36,7 +37,8 @@ MingwBundle::MingwBundle(const Manager &manager, const ApplicationUtilities::Str
|
|||
for(const auto &pkgName : packages) {
|
||||
bool found = false;
|
||||
for(const auto &syncDb : manager.syncDatabases()) {
|
||||
if(auto *pkg = syncDb.second->packageByName(QString::fromLocal8Bit(ConversionUtilities::startsWith(pkgName, prefix) ? pkgName.data() : (prefix + pkgName).data()))) {
|
||||
const Dependency dep(QString::fromLocal8Bit(ConversionUtilities::startsWith(pkgName, prefix) ? pkgName.data() : (prefix + pkgName).data()));
|
||||
if(auto *pkg = syncDb.second->packageProviding(dep)) {
|
||||
if(missing.empty()) {
|
||||
decltype(m_packages)::value_type entry(syncDb.second.get(), pkg);
|
||||
if(find(m_packages.cbegin(), m_packages.cend(), entry) == m_packages.cend()) {
|
||||
|
@ -120,7 +122,8 @@ enum class RelevantFileType
|
|||
Translation,
|
||||
QtTranslation,
|
||||
QtPlugin,
|
||||
Icon
|
||||
IconTheme,
|
||||
ConfigFile
|
||||
};
|
||||
|
||||
enum class RelevantFileArch
|
||||
|
@ -133,12 +136,14 @@ enum class RelevantFileArch
|
|||
struct RelevantFile
|
||||
{
|
||||
RelevantFile(const KArchiveFile *file, const RelevantFileType type, const RelevantFileArch arch, const QString &subDir = QString()) :
|
||||
file(file),
|
||||
name(file->name()),
|
||||
data(file->data()),
|
||||
fileType(type),
|
||||
arch(arch),
|
||||
subDir(subDir)
|
||||
{}
|
||||
const KArchiveFile *file;
|
||||
QString name;
|
||||
QByteArray data;
|
||||
RelevantFileType fileType;
|
||||
RelevantFileArch arch;
|
||||
QString subDir;
|
||||
|
@ -191,8 +196,7 @@ void getFiles(PkgFileInfo &pkgFileInfo)
|
|||
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);
|
||||
pkgFileInfo.relevantFiles.emplace_back(static_cast<const KArchiveFile *>(entry), RelevantFileType::Binary, root.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -214,8 +218,7 @@ void getFiles(PkgFileInfo &pkgFileInfo)
|
|||
for(const auto &entryName : categoryDir->entries()) {
|
||||
if(const auto *pluginEntry = categoryDir->entry(entryName)) {
|
||||
if(pluginEntry->isFile()) {
|
||||
const auto *pluginFile = static_cast<const KArchiveFile *>(pluginEntry);
|
||||
pkgFileInfo.relevantFiles.emplace_back(pluginFile, RelevantFileType::QtPlugin, root.first, categoryDir->name());
|
||||
pkgFileInfo.relevantFiles.emplace_back(static_cast<const KArchiveFile *>(pluginEntry), RelevantFileType::QtPlugin, root.first, categoryDir->name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -237,8 +240,7 @@ void getFiles(PkgFileInfo &pkgFileInfo)
|
|||
if(entryName.endsWith(QLatin1String(".qm"))) {
|
||||
if(const auto *qmEntry = trDir->entry(entryName)) {
|
||||
if(qmEntry->isFile()) {
|
||||
const auto *qmFile = static_cast<const KArchiveFile *>(qmEntry);
|
||||
pkgFileInfo.relevantFiles.emplace_back(qmFile, RelevantFileType::QtTranslation, root.first);
|
||||
pkgFileInfo.relevantFiles.emplace_back(static_cast<const KArchiveFile *>(qmEntry), RelevantFileType::QtTranslation, root.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -249,6 +251,34 @@ void getFiles(PkgFileInfo &pkgFileInfo)
|
|||
const auto *appEntry = shareDir->entry(pkgFileInfo.name);
|
||||
if(appEntry && appEntry->isDirectory()) {
|
||||
const auto *appDir = static_cast<const KArchiveDirectory *>(appEntry);
|
||||
for(const auto &entryName : appDir->entries()) {
|
||||
const auto *entry = appDir->entry(entryName);
|
||||
if(entry->isFile()) {
|
||||
pkgFileInfo.relevantFiles.emplace_back(static_cast<const KArchiveFile *>(entry), RelevantFileType::ConfigFile, root.first);
|
||||
} else {
|
||||
const auto subDir = static_cast<const KArchiveDirectory *>(entry);
|
||||
if(entryName == QLatin1String("translations")) {
|
||||
for(const auto &entryName : subDir->entries()) {
|
||||
if(entryName.endsWith(QLatin1String(".qm"))) {
|
||||
if(const auto *qmEntry = subDir->entry(entryName)) {
|
||||
if(qmEntry->isFile()) {
|
||||
pkgFileInfo.relevantFiles.emplace_back(static_cast<const KArchiveFile *>(qmEntry), RelevantFileType::Translation, root.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(const auto &entryName : subDir->entries()) {
|
||||
if(const auto *configEntry = subDir->entry(entryName)) {
|
||||
if(configEntry->isFile()) {
|
||||
pkgFileInfo.relevantFiles.emplace_back(static_cast<const KArchiveFile *>(configEntry), RelevantFileType::ConfigFile, root.first, subDir->name());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
const auto *trEntry = appDir->entry(QStringLiteral("translations"));
|
||||
if(trEntry && trEntry->isDirectory()) {
|
||||
const auto trDir = static_cast<const KArchiveDirectory *>(trEntry);
|
||||
|
@ -263,6 +293,7 @@ void getFiles(PkgFileInfo &pkgFileInfo)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -274,7 +305,7 @@ void getFiles(PkgFileInfo &pkgFileInfo)
|
|||
for(const auto &themeName : iconsDir->entries()) {
|
||||
const auto *themeEntry = iconsDir->entry(themeName);
|
||||
if(themeEntry && themeEntry->isDirectory()) {
|
||||
addEntries(pkgFileInfo, RelevantFileType::Icon, static_cast<const KArchiveDirectory *>(themeEntry));
|
||||
addEntries(pkgFileInfo, RelevantFileType::IconTheme, static_cast<const KArchiveDirectory *>(themeEntry));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -283,7 +314,68 @@ void getFiles(PkgFileInfo &pkgFileInfo)
|
|||
}
|
||||
}
|
||||
|
||||
void MingwBundle::createBundle(const string &targetDir, const string &targetName, const string &targetFormat) const
|
||||
void makeArchive(const list<PkgFileInfo> &pkgFiles, const QByteArray &pkgList, const QByteArray &indexFile, RelevantFileArch arch, const QString &root, const string &targetDir, const string &targetName, const string &targetFormat)
|
||||
{
|
||||
QString targetPath = qstr(targetDir) % QChar('/') % root % QChar('-') % qstr(targetName) % QChar('.') % qstr(targetFormat);
|
||||
cerr << shchar << "Making archive \"" << targetPath.toLocal8Bit().data() << "\" ..." << endl;
|
||||
unique_ptr<KArchive> targetArchive;
|
||||
if(targetFormat == "7z") {
|
||||
targetArchive = make_unique<K7Zip>(targetPath);
|
||||
} else if(targetFormat == "zip") {
|
||||
targetArchive = make_unique<KZip>(targetPath);
|
||||
} else if(ConversionUtilities::startsWith<string>(targetFormat, "tar")) {
|
||||
targetArchive = make_unique<KTar>(targetPath);
|
||||
} else {
|
||||
throw runtime_error("Specified archive format \"" + targetFormat + "\" is unknown.");
|
||||
}
|
||||
if(targetArchive->open(QIODevice::WriteOnly)) {
|
||||
// add package list
|
||||
if(!pkgList.isEmpty()) {
|
||||
targetArchive->writeFile(root % QStringLiteral("/var/lib/repoindex/packages.list"), pkgList, 0100644);
|
||||
}
|
||||
// set default icon theme
|
||||
if(!indexFile.isEmpty()) {
|
||||
targetArchive->writeFile(root % QStringLiteral("/share/icons/default/index.theme"), indexFile, 0100644);
|
||||
}
|
||||
// add relevant files from packages
|
||||
for(const auto &pkgFile : pkgFiles) {
|
||||
for(const RelevantFile &relevantFile : pkgFile.relevantFiles) {
|
||||
if(relevantFile.arch == RelevantFileArch::Any || relevantFile.arch == arch) {
|
||||
switch(relevantFile.fileType) {
|
||||
case RelevantFileType::Binary:
|
||||
targetArchive->writeFile(root % QStringLiteral("/bin/") % relevantFile.name, relevantFile.data, 0100755);
|
||||
break;
|
||||
case RelevantFileType::Translation:
|
||||
targetArchive->writeFile(root % QStringLiteral("/share/") % pkgFile.name % QStringLiteral("/translations/") % relevantFile.name, relevantFile.data, 0100644);
|
||||
break;
|
||||
case RelevantFileType::QtTranslation:
|
||||
targetArchive->writeFile(root % QStringLiteral("/share/qt/translations/") % relevantFile.name, relevantFile.data, 0100644);
|
||||
break;
|
||||
case RelevantFileType::QtPlugin:
|
||||
targetArchive->writeFile(root % QStringLiteral("/bin/") % relevantFile.subDir % QChar('/') % relevantFile.name, relevantFile.data, 0100755);
|
||||
break;
|
||||
case RelevantFileType::IconTheme:
|
||||
targetArchive->writeFile(root % QStringLiteral("/share/icons/") % relevantFile.subDir % QChar('/') % relevantFile.name, relevantFile.data, 0100644);
|
||||
break;
|
||||
case RelevantFileType::ConfigFile:
|
||||
if(relevantFile.subDir.isEmpty()) {
|
||||
targetArchive->writeFile(root % QStringLiteral("/share/") % pkgFile.name % QChar('/') % relevantFile.name, relevantFile.data, 0100644);
|
||||
} else {
|
||||
targetArchive->writeFile(root % QStringLiteral("/share/") % pkgFile.name % QChar('/') % relevantFile.subDir % QChar('/') % relevantFile.name, relevantFile.data, 0100644);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(targetArchive->device()) {
|
||||
cerr << shchar << "Error: Unable to open target archive: " << targetArchive->device()->errorString().toLocal8Bit().data() << endl;
|
||||
} else {
|
||||
cerr << shchar << "Error: Unable to open target archive." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void MingwBundle::createBundle(const string &targetDir, const string &targetName, const string &targetFormat, const string &defaultIconTheme) const
|
||||
{
|
||||
cerr << shchar << "Gathering relevant files ..." << endl;
|
||||
// get package files
|
||||
|
@ -304,6 +396,15 @@ void MingwBundle::createBundle(const string &targetDir, const string &targetName
|
|||
}
|
||||
pkgFiles.emplace_back(entry.second->name().startsWith(QLatin1String("mingw-w64-")) ? entry.second->name().mid(10) : entry.second->name(), pkgFile);
|
||||
}
|
||||
for(const auto &pkgFileStdStr : m_extraPackages) {
|
||||
QString pkgFile = QString::fromLocal8Bit(pkgFileStdStr.data());
|
||||
if(QFile::exists(pkgFile)) {
|
||||
const auto pkg = m_manager.packageFromFile(pkgFileStdStr.data()); // do not catch the exception here
|
||||
pkgFiles.emplace_back(pkg->name().startsWith(QLatin1String("mingw-w64-")) ? pkg->name().mid(10) : pkg->name(), pkgFile);
|
||||
} else {
|
||||
throw runtime_error("The specified extra package \"" + pkgFileStdStr + "\" can't be found.");
|
||||
}
|
||||
}
|
||||
// get relevant files from packages
|
||||
QtConcurrent::blockingMap(pkgFiles, getFiles);
|
||||
// check whether all packages could be opened
|
||||
|
@ -325,59 +426,18 @@ void MingwBundle::createBundle(const string &targetDir, const string &targetName
|
|||
QJsonDocument pkgList;
|
||||
pkgList.setArray(pkgArray);
|
||||
QByteArray pkgListBytes = pkgList.toJson();
|
||||
// make target archive
|
||||
static const QString user(QStringLiteral("root"));
|
||||
static const QString &group = user;
|
||||
static const pair<RelevantFileArch, QString> roots[] = {
|
||||
make_pair(RelevantFileArch::x86_64, QStringLiteral("x86_64-w64-mingw32")),
|
||||
make_pair(RelevantFileArch::i686, QStringLiteral("i686-w64-mingw32"))
|
||||
};
|
||||
for(const auto &root : roots) {
|
||||
QString targetPath = qstr(targetDir) % QChar('/') % root.second % QChar('-') % qstr(targetName) % QChar('.') % qstr(targetFormat);
|
||||
cerr << shchar << "Making archive \"" << targetPath.toLocal8Bit().data() << "\" ..." << endl;
|
||||
unique_ptr<KArchive> targetArchive;
|
||||
if(targetFormat == "7z") {
|
||||
targetArchive = make_unique<K7Zip>(targetPath);
|
||||
} else if(targetFormat == "zip") {
|
||||
targetArchive = make_unique<KZip>(targetPath);
|
||||
} else if(ConversionUtilities::startsWith<string>(targetFormat, "tar")) {
|
||||
targetArchive = make_unique<KTar>(targetPath);
|
||||
} else {
|
||||
throw runtime_error("Specified archive format \"" + targetFormat + "\" is unknown.");
|
||||
}
|
||||
if(targetArchive->open(QIODevice::WriteOnly)) {
|
||||
// add package list
|
||||
targetArchive->writeFile(root.second % QStringLiteral("/var/lib/repoindex/packages.list"), pkgListBytes, 0100644, user, group);
|
||||
// add relevant files from packages
|
||||
for(const auto &pkgFile : pkgFiles) {
|
||||
for(const RelevantFile &relevantFile : pkgFile.relevantFiles) {
|
||||
if(relevantFile.arch == RelevantFileArch::Any || relevantFile.arch == root.first) {
|
||||
switch(relevantFile.fileType) {
|
||||
case RelevantFileType::Binary:
|
||||
targetArchive->writeFile(root.second % QStringLiteral("/bin/") % relevantFile.file->name(), relevantFile.file->data(), 0100755, user, group);
|
||||
break;
|
||||
case RelevantFileType::Translation:
|
||||
targetArchive->writeFile(root.second % QStringLiteral("/share/") % pkgFile.name % QStringLiteral("/translations/") % relevantFile.file->name(), relevantFile.file->data(), 0100644, user, group);
|
||||
break;
|
||||
case RelevantFileType::QtTranslation:
|
||||
targetArchive->writeFile(root.second % QStringLiteral("/share/qt/translations/") % relevantFile.file->name(), relevantFile.file->data(), 0100644, user, group);
|
||||
break;
|
||||
case RelevantFileType::QtPlugin:
|
||||
targetArchive->writeFile(root.second % QStringLiteral("/bin/") % relevantFile.subDir % QChar('/') % relevantFile.file->name(), relevantFile.file->data(), 0100755, user, group);
|
||||
break;
|
||||
case RelevantFileType::Icon:
|
||||
targetArchive->writeFile(root.second % QStringLiteral("/share/icons/") % relevantFile.subDir % QChar('/') % relevantFile.file->name(), relevantFile.file->data(), 0100644, user, group);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(targetArchive->device()) {
|
||||
throw runtime_error("Unable to open target archive: " + string(targetArchive->device()->errorString().toLocal8Bit().data()));
|
||||
} else {
|
||||
throw runtime_error("Unable to open target archive.");
|
||||
}
|
||||
QByteArray indexFileBytes;
|
||||
if(!defaultIconTheme.empty()) {
|
||||
indexFileBytes.reserve(23 + defaultIconTheme.size());
|
||||
indexFileBytes.append("[Icon Theme]\nInherits=");
|
||||
indexFileBytes.append(defaultIconTheme.data());
|
||||
indexFileBytes.append('\n');
|
||||
}
|
||||
// make target archive
|
||||
auto run1 = QtConcurrent::run(bind(makeArchive, ref(pkgFiles), ref(pkgListBytes), ref(indexFileBytes), RelevantFileArch::x86_64, QStringLiteral("x86_64-w64-mingw32"), ref(targetDir), ref(targetName), ref(targetFormat)));
|
||||
auto run2 = QtConcurrent::run(bind(makeArchive, ref(pkgFiles), ref(pkgListBytes), ref(indexFileBytes), RelevantFileArch::i686, QStringLiteral("i686-w64-mingw32"), ref(targetDir), ref(targetName), ref(targetFormat)));
|
||||
run1.waitForFinished();
|
||||
run2.waitForFinished();
|
||||
}
|
||||
|
||||
} // namespace PackageManagement
|
||||
|
|
|
@ -15,15 +15,16 @@ class Manager;
|
|||
class MingwBundle
|
||||
{
|
||||
public:
|
||||
MingwBundle(const Manager &manager, const ApplicationUtilities::StringVector &packages, const ApplicationUtilities::StringVector &iconPackages);
|
||||
MingwBundle(Manager &manager, const ApplicationUtilities::StringVector &packages, const ApplicationUtilities::StringVector &iconPackages, const ApplicationUtilities::StringVector &extraPackages);
|
||||
|
||||
void createBundle(const std::string &targetDir, const std::string &targetName, const std::string &targetFormat) const;
|
||||
void createBundle(const std::string &targetDir, const std::string &targetName, const std::string &targetFormat, const std::string &defaultIconTheme) const;
|
||||
|
||||
private:
|
||||
void addDependencies(const Package *pkg);
|
||||
|
||||
const Manager &m_manager;
|
||||
Manager &m_manager;
|
||||
std::list<std::pair<const AlpmDatabase *, const Package *> > m_packages;
|
||||
const ApplicationUtilities::StringVector &m_extraPackages;
|
||||
};
|
||||
|
||||
} // namespace PackageManagement
|
||||
|
|
154
alpm/package.cpp
154
alpm/package.cpp
|
@ -1,4 +1,4 @@
|
|||
#include "./package.h"
|
||||
#include "./package.h"
|
||||
#include "./alpmdatabase.h"
|
||||
#include "./utilities.h"
|
||||
#include "./repository.h"
|
||||
|
@ -10,6 +10,7 @@
|
|||
#include <QJsonDocument>
|
||||
#include <QVariant>
|
||||
#include <QDataStream>
|
||||
#include <QStringBuilder>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
@ -32,6 +33,7 @@ namespace RepoIndex {
|
|||
Package::Package(const QString &name, Repository *repository) :
|
||||
m_origin(PackageOrigin::Unknown),
|
||||
m_repository(repository),
|
||||
m_timeStamp(DateTime::now()),
|
||||
m_hasGeneralInfo(false),
|
||||
m_name(name),
|
||||
m_requiredByComputed(false),
|
||||
|
@ -293,7 +295,7 @@ using namespace Utilities;
|
|||
*/
|
||||
QJsonObject Package::basicInfo(bool includeRepoAndName) const
|
||||
{
|
||||
QJsonObject info;
|
||||
QJsonObject info;
|
||||
if(includeRepoAndName) {
|
||||
if(repository()) {
|
||||
put(info, QStringLiteral("repo"), repository()->name());
|
||||
|
@ -312,24 +314,11 @@ QJsonObject Package::basicInfo(bool includeRepoAndName) const
|
|||
/*!
|
||||
* \brief Returns full information about the package as JSON object.
|
||||
*/
|
||||
QJsonObject Package::fullInfo(bool includeRepoAndName) const
|
||||
QJsonObject Package::detailedInfo() const
|
||||
{
|
||||
QJsonObject info;
|
||||
if(includeRepoAndName) {
|
||||
if(repository()) {
|
||||
put(info, QStringLiteral("repo"), repository()->name());
|
||||
}
|
||||
put(info, QStringLiteral("name"), name());
|
||||
}
|
||||
put(info, QStringLiteral("build_avail"), hasBuildRelatedMetaData());
|
||||
put(info, QStringLiteral("src_avail"), hasSourceRelatedMetaData());
|
||||
put(info, QStringLiteral("archs"), architectures());
|
||||
put(info, QStringLiteral("arch"), buildArchitecture());
|
||||
put(info, QStringLiteral("ver"), version());
|
||||
put(info, QStringLiteral("desc"), description());
|
||||
put(info, QStringLiteral("bdate"), buildDate());
|
||||
put(info, QStringLiteral("bdate"), buildDate());
|
||||
put(info, QStringLiteral("flagdate"), outOfDate());
|
||||
put(info, QStringLiteral("buildAvail"), hasBuildRelatedMetaData());
|
||||
put(info, QStringLiteral("srcAvail"), hasSourceRelatedMetaData());
|
||||
put(info, QStringLiteral("idate"), installDate());
|
||||
put(info, QStringLiteral("isize"), QJsonValue(static_cast<long long int>(installedSize())));
|
||||
put(info, QStringLiteral("url"), upstreamUrl());
|
||||
|
@ -356,7 +345,7 @@ QJsonObject Package::fullInfo(bool includeRepoAndName) const
|
|||
*/
|
||||
void Package::writeToCacheStream(QDataStream &out)
|
||||
{
|
||||
out << static_cast<qint32>(m_origin);
|
||||
out << static_cast<qint32>(m_origin) << m_timeStamp;
|
||||
// general info
|
||||
out << m_hasGeneralInfo << m_name << m_version << m_description << m_upstreamUrl << m_licenses
|
||||
<< m_groups << m_dependencies << m_optionalDependencies << m_conflicts << m_provides
|
||||
|
@ -389,6 +378,7 @@ void Package::restoreFromCacheStream(QDataStream &in)
|
|||
// origin
|
||||
in >> tmp;
|
||||
m_origin = static_cast<PackageOrigin>(tmp); // TODO: validate value
|
||||
in >> m_timeStamp;
|
||||
// general info
|
||||
in >> m_hasGeneralInfo >> m_name >> m_version >> m_description >> m_upstreamUrl >> m_licenses
|
||||
>> m_groups >> m_dependencies >> m_optionalDependencies >> m_conflicts >> m_provides
|
||||
|
@ -420,6 +410,74 @@ void Package::restoreFromCacheStream(QDataStream &in)
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Puts the specified src/pkg info key value pairs; clears current dependencies, provides, ...
|
||||
* \remarks This method should only be called by the associated repository because it must handle a possible name change.
|
||||
*/
|
||||
void Package::putInfo(const QList<QPair<QString, QString> > &baseInfo, const QList<QPair<QString, QString> > &pkgInfo)
|
||||
{
|
||||
// clear current values
|
||||
m_licenses.clear();
|
||||
m_dependencies.clear();
|
||||
m_makeDependencies.clear();
|
||||
m_checkDependencies.clear();
|
||||
m_optionalDependencies.clear();
|
||||
m_conflicts.clear();
|
||||
m_provides.clear();
|
||||
m_replaces.clear();
|
||||
// read specified key value pairs
|
||||
PackageVersion version;
|
||||
QStringList archs;
|
||||
const auto infos = {baseInfo, pkgInfo};
|
||||
for(const auto &info : infos) {
|
||||
for(const auto &pair : info) {
|
||||
const auto &field = pair.first;
|
||||
const auto &value = pair.second;
|
||||
if(field == QLatin1String("pkgbase")) {
|
||||
m_baseName = value;
|
||||
} else if(field == QLatin1String("pkgname")) {
|
||||
m_name = value;
|
||||
} else if(field == QLatin1String("epoch")) {
|
||||
version.epoch = value;
|
||||
} else if(field == QLatin1String("pkgver")) {
|
||||
version.version = value;
|
||||
} else if(field == QLatin1String("pkgrel")) {
|
||||
version.release = value;
|
||||
} else if(field == QLatin1String("pkgdesc")) {
|
||||
m_description = value;
|
||||
} else if(field == QLatin1String("url")) {
|
||||
m_upstreamUrl = value;
|
||||
} else if(field == QLatin1String("arch")) {
|
||||
archs << value;
|
||||
} else if(field == QLatin1String("license")) {
|
||||
m_licenses << value;
|
||||
} else if(field == QLatin1String("depends")) {
|
||||
m_dependencies << Dependency(value);
|
||||
} else if(field == QLatin1String("makedepends")) {
|
||||
m_makeDependencies << Dependency(value);
|
||||
} else if(field == QLatin1String("checkdepends")) {
|
||||
m_checkDependencies << Dependency(value);
|
||||
} else if(field == QLatin1String("optdepends")) {
|
||||
m_optionalDependencies << Dependency(value);
|
||||
} else if(field == QLatin1String("conflicts")) {
|
||||
m_conflicts << Dependency(value);
|
||||
} else if(field == QLatin1String("provides")) {
|
||||
m_provides << Dependency(value);
|
||||
} else if(field == QLatin1String("replaces")) {
|
||||
m_replaces << Dependency(value);
|
||||
} else if(field == QLatin1String("source")) {
|
||||
// currently not used
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!version.version.isEmpty()) {
|
||||
m_version = version.toString();
|
||||
}
|
||||
if(!archs.isEmpty()) {
|
||||
m_architectures.swap(archs);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief The PackageVersion class helps parsing package versions.
|
||||
*/
|
||||
|
@ -472,6 +530,24 @@ PackageVersion::PackageVersion(const QString &versionStr)
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs an empty package version.
|
||||
*/
|
||||
PackageVersion::PackageVersion()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Returns the string representation of the package version: epoch:version-release
|
||||
*/
|
||||
QString RepoIndex::PackageVersion::toString() const
|
||||
{
|
||||
if(epoch.isEmpty()) {
|
||||
return version % QChar('-') % (release.isEmpty() ? QStringLiteral("1") : release);
|
||||
} else {
|
||||
return epoch % QChar(':') % version % QChar('-') % (release.isEmpty() ? QStringLiteral("1") : release);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Compares two version parts.
|
||||
* \returns Returns 1 if part1 is newer then part2, -1 if part2 is newer then part1 and 0 if both parts are equal.
|
||||
|
@ -556,5 +632,45 @@ PackageVersionComparsion PackageVersion::compare(const PackageVersion &other) co
|
|||
return PackageVersionComparsion::Equal;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a dependency from the specified string.
|
||||
* \remarks \a dependency might have version suffix.
|
||||
*/
|
||||
Dependency::Dependency(const QString &dependency)
|
||||
{
|
||||
int suffixBeg;
|
||||
if((suffixBeg = dependency.lastIndexOf(QLatin1String(">="))) > 0) {
|
||||
mode = ALPM_DEP_MOD_GE;
|
||||
} else if((suffixBeg = dependency.lastIndexOf(QLatin1String("<="))) > 0) {
|
||||
mode = ALPM_DEP_MOD_LE;
|
||||
} else if((suffixBeg = dependency.lastIndexOf(QChar('='))) > 0) {
|
||||
mode = ALPM_DEP_MOD_EQ;
|
||||
} else if((suffixBeg = dependency.lastIndexOf(QChar('<'))) > 0) {
|
||||
mode = ALPM_DEP_MOD_LT;
|
||||
} else if((suffixBeg = dependency.lastIndexOf(QChar('>'))) > 0) {
|
||||
mode = ALPM_DEP_MOD_GT;
|
||||
} else {
|
||||
mode = ALPM_DEP_MOD_ANY;
|
||||
}
|
||||
switch(mode) {
|
||||
case ALPM_DEP_MOD_ANY:
|
||||
name = dependency;
|
||||
break;
|
||||
case ALPM_DEP_MOD_GE:
|
||||
case ALPM_DEP_MOD_LE:
|
||||
name = dependency.mid(0, suffixBeg);
|
||||
version = dependency.mid(suffixBeg + 2);
|
||||
break;
|
||||
case ALPM_DEP_MOD_EQ:
|
||||
case ALPM_DEP_MOD_LT:
|
||||
case ALPM_DEP_MOD_GT:
|
||||
name = dependency.mid(0, suffixBeg);
|
||||
version = dependency.mid(suffixBeg + 1);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -64,9 +64,11 @@ class PackageVersion
|
|||
{
|
||||
public:
|
||||
explicit PackageVersion(const QString &versionStr);
|
||||
explicit PackageVersion();
|
||||
|
||||
static PackageVersionPartComparsion compareParts(const QString &part1, const QString &part2);
|
||||
PackageVersionComparsion compare(const PackageVersion &other) const;
|
||||
QString toString() const;
|
||||
|
||||
QString epoch;
|
||||
QString version;
|
||||
|
@ -76,7 +78,8 @@ public:
|
|||
class Dependency
|
||||
{
|
||||
public:
|
||||
explicit Dependency(const QString &name, const QString &version = QString(), _alpm_depmod_t mode = ALPM_DEP_MOD_ANY);
|
||||
explicit Dependency(const QString &name, const QString &version, _alpm_depmod_t mode = ALPM_DEP_MOD_ANY);
|
||||
explicit Dependency(const QString &dependency);
|
||||
QString name;
|
||||
QString version;
|
||||
_alpm_depmod_t mode;
|
||||
|
@ -98,6 +101,7 @@ public:
|
|||
// general package meta data
|
||||
PackageOrigin origin() const;
|
||||
Repository *repository() const;
|
||||
ChronoUtilities::DateTime timeStamp() const;
|
||||
bool hasGeneralInfo() const;
|
||||
const QString &name() const;
|
||||
const QString &version() const;
|
||||
|
@ -127,6 +131,7 @@ public:
|
|||
const QString &buildArchitecture() const;
|
||||
uint32 packageSize() const;
|
||||
const QList<Dependency> &makeDependencies() const;
|
||||
const QList<Dependency> &checkDependencies() const;
|
||||
|
||||
// installation related meta data
|
||||
bool hasInstallRelatedMetaData() const;
|
||||
|
@ -158,12 +163,15 @@ public:
|
|||
|
||||
// JSON serialization
|
||||
QJsonObject basicInfo(bool includeRepoAndName = false) const;
|
||||
QJsonObject fullInfo(bool includeRepoAndName = false) const;
|
||||
QJsonObject detailedInfo() const;
|
||||
|
||||
// caching
|
||||
void writeToCacheStream(QDataStream &out);
|
||||
void restoreFromCacheStream(QDataStream &in);
|
||||
|
||||
// parsing src/pkg info
|
||||
void putInfo(const QList<QPair<QString, QString> > &baseInfo, const QList<QPair<QString, QString> > &pkgInfo);
|
||||
|
||||
protected:
|
||||
explicit Package(const QString &name, Repository *repository);
|
||||
virtual void writeSpecificCacheHeader(QDataStream &out);
|
||||
|
@ -171,6 +179,7 @@ protected:
|
|||
|
||||
PackageOrigin m_origin;
|
||||
Repository *m_repository;
|
||||
ChronoUtilities::DateTime m_timeStamp;
|
||||
|
||||
// general package meta data
|
||||
bool m_hasGeneralInfo;
|
||||
|
@ -201,6 +210,7 @@ protected:
|
|||
QString m_buildArchitecture;
|
||||
uint32 m_packageSize;
|
||||
QList<Dependency> m_makeDependencies;
|
||||
QList<Dependency> m_checkDependencies;
|
||||
|
||||
// installation related meta data
|
||||
bool m_hasInstallRelatedMetaData;
|
||||
|
@ -242,6 +252,14 @@ inline Repository *Package::repository() const
|
|||
return m_repository;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the package's timestamp.
|
||||
*/
|
||||
inline ChronoUtilities::DateTime Package::timeStamp() const
|
||||
{
|
||||
return m_timeStamp;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether general information is available for the package.
|
||||
*/
|
||||
|
@ -446,13 +464,21 @@ inline uint32 Package::packageSize() const
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns make dependencies.
|
||||
* \brief Returns dependencies required to make the package.
|
||||
*/
|
||||
inline const QList<Dependency> &Package::makeDependencies() const
|
||||
{
|
||||
return m_makeDependencies;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns dependencies required to run tests when making the package.
|
||||
*/
|
||||
inline const QList<Dependency> &Package::checkDependencies() const
|
||||
{
|
||||
return m_checkDependencies;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether install-related meta data is available.
|
||||
*
|
||||
|
|
|
@ -73,8 +73,9 @@ SuggestionsReply *Repository::requestSuggestions(const QString &) const
|
|||
/*!
|
||||
* \brief Constructs a new repository (protected since this is a pure virtual class).
|
||||
*/
|
||||
Repository::Repository(const QString &name, QObject *parent) :
|
||||
Repository::Repository(const QString &name, uint32 index, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_index(index),
|
||||
m_name(name),
|
||||
m_usage(static_cast<alpm_db_usage_t>(0)),
|
||||
m_sigLevel(static_cast<alpm_siglevel_t>(ALPM_SIGSTATUS_INVALID))
|
||||
|
@ -251,6 +252,26 @@ QFuture<void> Repository::computeRequiredBy(Manager &manager, bool forceUpdate)
|
|||
return QtConcurrent::map(m_packages, ComputeRequired(manager, forceUpdate));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns suggestions for the specified \a term.
|
||||
*/
|
||||
QJsonObject Repository::suggestions(const QString &term) const
|
||||
{
|
||||
QJsonArray suggestions;
|
||||
size_t remainingSuggestions = 20;
|
||||
for(auto i = packages().lower_bound(term), end = packages().cend(); i != end && remainingSuggestions; ++i, --remainingSuggestions) {
|
||||
if(i->first.startsWith(term, Qt::CaseInsensitive)) {
|
||||
suggestions << i->first;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
QJsonObject res;
|
||||
res.insert(QStringLiteral("repo"), name());
|
||||
res.insert(QStringLiteral("res"), suggestions);
|
||||
return res;
|
||||
}
|
||||
|
||||
QJsonArray Repository::upgradeSourcesJsonArray() const
|
||||
{
|
||||
QJsonArray sources;
|
||||
|
@ -303,6 +324,18 @@ QJsonArray Repository::packageNamesJsonArray() const
|
|||
return names;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns an object with the package names of the repository as keys (and empty objects as value).
|
||||
*/
|
||||
QJsonObject Repository::packagesObjectSkeleton() const
|
||||
{
|
||||
QJsonObject skel;
|
||||
for(const auto &entry : m_packages) {
|
||||
skel.insert(entry.first, QJsonValue(QJsonValue::Object));
|
||||
}
|
||||
return skel;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \cond
|
||||
*/
|
||||
|
@ -328,18 +361,26 @@ inline void put(QJsonObject &obj, const QString &key, const QStringList &values)
|
|||
/*!
|
||||
* \brief Returns basic information about the repository.
|
||||
*/
|
||||
QJsonObject Repository::basicInfo() const
|
||||
QJsonObject Repository::basicInfo(bool includeName) const
|
||||
{
|
||||
QJsonObject info;
|
||||
put(info, QStringLiteral("name"), name());
|
||||
if(includeName) {
|
||||
put(info, QStringLiteral("name"), name());
|
||||
}
|
||||
if(index() != invalidIndex) {
|
||||
info.insert(QStringLiteral("index"), static_cast<int>(index()));
|
||||
}
|
||||
put(info, QStringLiteral("desc"), description());
|
||||
put(info, QStringLiteral("servers"), serverUrls());
|
||||
put(info, QStringLiteral("usage"), Utilities::usageStrings(usage()));
|
||||
put(info, QStringLiteral("sigLevel"), Utilities::sigLevelStrings(sigLevel()));
|
||||
put(info, QStringLiteral("upgradeSources"), upgradeSourcesJsonArray());
|
||||
put(info, QStringLiteral("packages"), packageNamesJsonArray());
|
||||
put(info, QStringLiteral("requestRequired"), requestsRequired(PackageDetail::Basics) != PackageDetailAvailability::Immediately);
|
||||
put(info, QStringLiteral("packages"), packagesObjectSkeleton());
|
||||
if(requestsRequired(PackageDetail::Basics) == PackageDetailAvailability::Immediately) {
|
||||
info.insert(QStringLiteral("packageCount"), static_cast<qint64>(m_packages.size()));
|
||||
}
|
||||
put(info, QStringLiteral("srcOnly"), isSourceOnly());
|
||||
put(info, QStringLiteral("pkgOnly"), isPackageOnly());
|
||||
return info;
|
||||
}
|
||||
|
||||
|
@ -471,4 +512,100 @@ void Repository::restoreSpecificCacheHeader(QDataStream &in)
|
|||
Q_UNUSED(in)
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds a package parsed from the specified \a srcInfo.
|
||||
*/
|
||||
void Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo)
|
||||
{
|
||||
enum {
|
||||
FieldName,
|
||||
EquationSign,
|
||||
Pad,
|
||||
FieldValue
|
||||
} state = FieldName;
|
||||
QString currentFieldName;
|
||||
QString currentFieldValue;
|
||||
QString packageBase;
|
||||
QList<QPair<QString, QString> > baseInfo;
|
||||
QList<QPair<QString, QString> > packageInfo;
|
||||
Package *currentPackage = nullptr;
|
||||
for(char c : srcInfo) {
|
||||
switch(state) {
|
||||
case FieldName:
|
||||
switch(c) {
|
||||
case ' ':
|
||||
if(!currentFieldName.isEmpty()) {
|
||||
state = EquationSign;
|
||||
}
|
||||
break;
|
||||
case '\n': case '\r':
|
||||
if(!currentFieldName.isEmpty()) {
|
||||
// TODO: handle error - field name contains newline character
|
||||
}
|
||||
break;
|
||||
default:
|
||||
currentFieldName.append(c);
|
||||
}
|
||||
break;
|
||||
case EquationSign:
|
||||
switch(c) {
|
||||
case '=':
|
||||
state = Pad;
|
||||
break;
|
||||
default:
|
||||
;// TODO: handle error - no equation sign after pad
|
||||
}
|
||||
break;
|
||||
case Pad:
|
||||
switch(c) {
|
||||
case ' ':
|
||||
state = FieldValue;
|
||||
break;
|
||||
default:
|
||||
;// TODO: handle error - no pad after equation sign
|
||||
}
|
||||
break;
|
||||
case FieldValue:
|
||||
switch(c) {
|
||||
case '\n': case '\r':
|
||||
state = FieldName;
|
||||
if(currentFieldName == QLatin1String("pkgbase")) {
|
||||
// pkgbase
|
||||
packageBase = currentFieldValue;
|
||||
} else if(currentFieldName == QLatin1String("pkgname")) {
|
||||
// next package
|
||||
if(packageBase.isEmpty()) {
|
||||
// TODO: handle error - pkgbase must be present
|
||||
} else {
|
||||
if(currentPackage) {
|
||||
currentPackage->putInfo(baseInfo, packageInfo);
|
||||
}
|
||||
auto &pkg = m_packages[currentFieldValue];
|
||||
if(!pkg) {
|
||||
pkg = emptyPackage();
|
||||
}
|
||||
currentPackage = pkg.get();
|
||||
packageInfo.clear();
|
||||
}
|
||||
}
|
||||
if(currentPackage) {
|
||||
packageInfo << QPair<QString, QString>(currentFieldName, currentFieldValue);
|
||||
} else {
|
||||
baseInfo << QPair<QString, QString>(currentFieldName, currentFieldValue);
|
||||
}
|
||||
currentFieldName.clear();
|
||||
currentFieldValue.clear();
|
||||
break;
|
||||
default:
|
||||
currentFieldValue.append(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(currentPackage) {
|
||||
currentPackage->putInfo(baseInfo, packageInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace PackageManagement
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <QObject>
|
||||
#include <QFuture>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
@ -71,22 +72,20 @@ class SuggestionsReply : public Reply
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SuggestionsReply(QNetworkReply *networkReply);
|
||||
const QJsonArray &suggestions() const;
|
||||
SuggestionsReply(QNetworkReply *networkReply, const QString &term, Repository *repo);
|
||||
QJsonObject suggestions() const;
|
||||
|
||||
protected:
|
||||
QJsonArray m_suggestions;
|
||||
QString m_term;
|
||||
Repository *m_repo;
|
||||
};
|
||||
|
||||
inline SuggestionsReply::SuggestionsReply(QNetworkReply *networkReply) :
|
||||
Reply(networkReply)
|
||||
inline SuggestionsReply::SuggestionsReply(QNetworkReply *networkReply, const QString &term, Repository *repo) :
|
||||
Reply(networkReply),
|
||||
m_term(term),
|
||||
m_repo(repo)
|
||||
{}
|
||||
|
||||
inline const QJsonArray &SuggestionsReply::suggestions() const
|
||||
{
|
||||
return m_suggestions;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief The RepositoryType enum specifies the type of a repository object.
|
||||
*/
|
||||
|
@ -130,6 +129,7 @@ public:
|
|||
virtual RepositoryType type() const = 0;
|
||||
|
||||
// general meta data
|
||||
uint32 index() const;
|
||||
const QString &name() const;
|
||||
const QString &description() const;
|
||||
const std::map<QString, std::unique_ptr<Package> > &packages() const;
|
||||
|
@ -137,6 +137,7 @@ public:
|
|||
const QStringList packageNames() const;
|
||||
alpm_db_usage_t usage() const;
|
||||
bool isSourceOnly() const;
|
||||
bool isPackageOnly() const;
|
||||
std::map<QString, QList<Package *> > &groups();
|
||||
const std::map<QString, QList<Package *> > &groups() const;
|
||||
const QStringList &serverUrls() const;
|
||||
|
@ -156,6 +157,7 @@ public:
|
|||
QList<const Package *> packagesProviding(const Dependency &dependency) const;
|
||||
QList<Package *> packageByFilter(std::function<bool (const Package *)> pred);
|
||||
QFuture<void> computeRequiredBy(Manager &manager, bool forceUpdate = false);
|
||||
QJsonObject suggestions(const QString &term) const;
|
||||
|
||||
// upgrade lookup
|
||||
const QList<const Repository *> &upgradeSources() const;
|
||||
|
@ -172,7 +174,8 @@ public:
|
|||
|
||||
// JSON serialization
|
||||
QJsonArray packageNamesJsonArray() const;
|
||||
QJsonObject basicInfo() const;
|
||||
QJsonObject packagesObjectSkeleton() const;
|
||||
QJsonObject basicInfo(bool includeName = false) const;
|
||||
QJsonObject groupInfo() const;
|
||||
|
||||
// caching
|
||||
|
@ -183,9 +186,16 @@ public:
|
|||
virtual std::unique_ptr<Package> emptyPackage();
|
||||
virtual void restoreSpecificCacheHeader(QDataStream &in);
|
||||
|
||||
protected:
|
||||
explicit Repository(const QString &name, QObject *parent = nullptr);
|
||||
// parsing src/pkg info
|
||||
void addPackagesFromSrcInfo(const QByteArray &srcInfo);
|
||||
|
||||
static const uint32 invalidIndex = static_cast<uint32>(-1);
|
||||
|
||||
protected:
|
||||
explicit Repository(const QString &name, uint32 index = invalidIndex, QObject *parent = nullptr);
|
||||
|
||||
protected:
|
||||
uint32 m_index;
|
||||
QString m_name;
|
||||
QString m_description;
|
||||
std::map<QString, std::unique_ptr<Package> > m_packages;
|
||||
|
@ -198,6 +208,24 @@ protected:
|
|||
QString m_pkgDir;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Returns the suggestions.
|
||||
*/
|
||||
inline QJsonObject SuggestionsReply::suggestions() const
|
||||
{
|
||||
return m_repo->suggestions(m_term);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the index of the repository.
|
||||
*
|
||||
* The index is used to sort the repositories by their occurance the configuration files.
|
||||
*/
|
||||
inline uint32 Repository::index() const
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the name.
|
||||
*/
|
||||
|
@ -222,6 +250,14 @@ inline bool Repository::isSourceOnly() const
|
|||
return requestsRequired(PackageDetail::PackageInfo) == PackageDetailAvailability::Never;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether the repository only has built packages but no sources.
|
||||
*/
|
||||
inline bool Repository::isPackageOnly() const
|
||||
{
|
||||
return requestsRequired(PackageDetail::SourceInfo) == PackageDetailAvailability::Never;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the packages.
|
||||
*/
|
||||
|
|
|
@ -195,7 +195,7 @@ void BuildOrderResolver::printResults(const QStringList &results)
|
|||
|
||||
void BuildOrderResolver::addDeps(QList<TaskInfo *> &tasks, TaskInfo *task) const
|
||||
{
|
||||
if(const auto pkg = m_manager.packageProviding(Dependency(task->name()))) {
|
||||
if(const auto pkg = m_manager.packageProviding(Dependency(task->name(), QString()))) {
|
||||
task->setName(pkg->name()); // update the name to ensure we have the acutal package name and not just a "provides" name
|
||||
addDeps(tasks, task, pkg->dependencies());
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
#include "./suggestionslookup.h"
|
||||
#include "./manager.h"
|
||||
#include "./repository.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace RepoIndex {
|
||||
|
||||
SuggestionsLookup::SuggestionsLookup(Manager &manager, const QJsonObject &request) :
|
||||
m_remainingReplies(0)
|
||||
{
|
||||
m_id = request.value(QStringLiteral("id"));
|
||||
const auto searchTerm = request.value(QStringLiteral("term")).toString();
|
||||
if(searchTerm.isEmpty()) {
|
||||
m_errors << QStringLiteral("No search term specified.");
|
||||
}
|
||||
const auto repos = request.value(QStringLiteral("repos")).toArray();
|
||||
if(repos.isEmpty()) {
|
||||
m_errors << QStringLiteral("No repositories specified.");
|
||||
}
|
||||
if(m_errors.isEmpty()) {
|
||||
for(const auto &repoName : repos) {
|
||||
if(const Repository *repo = manager.repositoryByName(repoName.toString())) {
|
||||
if(const auto *reply = repo->requestSuggestions(searchTerm)) {
|
||||
connect(reply, &SuggestionsReply::resultsAvailable, this, &SuggestionsLookup::addResults);
|
||||
++m_remainingReplies;
|
||||
} else {
|
||||
m_results << repo->suggestions(searchTerm);
|
||||
}
|
||||
|
||||
} else {
|
||||
m_errors << QStringLiteral("The specified repository \"%1\" does not exist.").arg(repoName.toString());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void SuggestionsLookup::addResults()
|
||||
{
|
||||
assert(m_remainingReplies);
|
||||
auto *reply = static_cast<SuggestionsReply *>(sender());
|
||||
m_results << reply->suggestions();
|
||||
reply->deleteLater();
|
||||
if(!--m_remainingReplies) {
|
||||
emit resultsAvailable(QStringLiteral("suggestions"), m_id, m_results);
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace RepoIndex
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#ifndef REPOINDEX_SUGGESTIONSLOOKUP_H
|
||||
#define REPOINDEX_SUGGESTIONSLOOKUP_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonValue>
|
||||
|
||||
namespace RepoIndex {
|
||||
|
||||
class Manager;
|
||||
|
||||
class SuggestionsLookup : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SuggestionsLookup(Manager &manager, const QJsonObject &request);
|
||||
const QJsonArray &errors() const;
|
||||
const QJsonArray &results() const;
|
||||
bool finished() const;
|
||||
|
||||
signals:
|
||||
void resultsAvailable(const QJsonValue &what, const QJsonValue &id, const QJsonValue &value);
|
||||
|
||||
private slots:
|
||||
void addResults();
|
||||
|
||||
private:
|
||||
unsigned int m_remainingReplies;
|
||||
QJsonValue m_id;
|
||||
QJsonArray m_errors;
|
||||
QJsonArray m_results;
|
||||
};
|
||||
|
||||
inline const QJsonArray &SuggestionsLookup::errors() const
|
||||
{
|
||||
return m_errors;
|
||||
}
|
||||
|
||||
inline const QJsonArray &SuggestionsLookup::results() const
|
||||
{
|
||||
return m_results;
|
||||
}
|
||||
|
||||
inline bool SuggestionsLookup::finished() const
|
||||
{
|
||||
return !m_remainingReplies && m_errors.isEmpty();
|
||||
}
|
||||
|
||||
} // namespace RepoIndex
|
||||
|
||||
#endif // REPOINDEX_SUGGESTIONSLOOKUP_H
|
|
@ -26,7 +26,11 @@ using namespace Utilities;
|
|||
QJsonObject UpgradeResult::json() const
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj.insert(QStringLiteral("pkg"), package->basicInfo(true));
|
||||
obj.insert(QStringLiteral("name"), package->name());
|
||||
if(package->repository()) {
|
||||
obj.insert(QStringLiteral("repo"), package->repository()->name());
|
||||
}
|
||||
obj.insert(QStringLiteral("pkg"), package->basicInfo());
|
||||
obj.insert(QStringLiteral("curVer"), currentVersion);
|
||||
return obj;
|
||||
}
|
||||
|
@ -194,10 +198,6 @@ UpgradeLookupJson::UpgradeLookupJson(const Manager &manager, const QJsonObject &
|
|||
} else {
|
||||
m_errorsArray << QStringLiteral("Repository \"%1\" can not be found.").arg(toCheckName);
|
||||
}
|
||||
// there are errors
|
||||
QJsonObject results;
|
||||
results.insert(QStringLiteral("errors"), m_errorsArray);
|
||||
emit resultsAvailable(request.value(QStringLiteral("what")), request.value(QStringLiteral("id")), results);
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
|
@ -231,7 +231,13 @@ void UpgradeLookupJson::processFinished()
|
|||
if(--m_remainingProcesses == 0) {
|
||||
// finally make info for orphanded packages
|
||||
for(const auto *pkg : m_orphanedPackages) {
|
||||
m_orphanedPackagesArray << pkg->basicInfo(true);
|
||||
QJsonObject obj;
|
||||
obj.insert(QStringLiteral("name"), pkg->name());
|
||||
if(pkg->repository()) {
|
||||
obj.insert(QStringLiteral("repo"), pkg->repository()->name());
|
||||
}
|
||||
obj.insert(QStringLiteral("pkg"), pkg->basicInfo());
|
||||
m_orphanedPackagesArray << obj;
|
||||
}
|
||||
// add results to results QJsonObject
|
||||
QJsonObject results;
|
||||
|
@ -367,7 +373,7 @@ void UpgradeLookupCli::printResults()
|
|||
Utilities::printValues(cout, "Orphaned packages", m_orphanedPackagesArray);
|
||||
}
|
||||
}
|
||||
emit finished();
|
||||
QCoreApplication::exit();
|
||||
}
|
||||
|
||||
} // namespace PackageManagement
|
||||
|
|
|
@ -135,6 +135,7 @@ class UpgradeLookupJson : public UpgradeLookup
|
|||
Q_OBJECT
|
||||
public:
|
||||
explicit UpgradeLookupJson(const Manager &manager, const QJsonObject &request, QObject *parent = nullptr);
|
||||
const QJsonArray &errors() const;
|
||||
|
||||
signals:
|
||||
void resultsAvailable(const QJsonValue &what, const QJsonValue &id, const QJsonValue &value);
|
||||
|
@ -152,6 +153,11 @@ private:
|
|||
QJsonArray m_orphanedPackagesArray;
|
||||
};
|
||||
|
||||
inline const QJsonArray &UpgradeLookupJson::errors() const
|
||||
{
|
||||
return m_errorsArray;
|
||||
}
|
||||
|
||||
class UpgradeLookupCli : public UpgradeLookup
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -160,9 +166,6 @@ public:
|
|||
explicit UpgradeLookupCli(const Manager &manager, const std::string &repo, QObject *parent = nullptr);
|
||||
const Repository *toCheck() const;
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
private slots:
|
||||
void processFinished();
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QStringList>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
|
12
general.pri
12
general.pri
|
@ -1,5 +1,3 @@
|
|||
# template
|
||||
TEMPLATE = lib
|
||||
#dirs
|
||||
UI_DIR = ./gui
|
||||
MOC_DIR = ./moc
|
||||
|
@ -75,7 +73,11 @@ guiqtwidgets {
|
|||
DEFINES += GUI_QTWIDGETS
|
||||
DEFINES += MODEL_UNDO_SUPPORT
|
||||
}
|
||||
# configuration for cross compliation with mingw-w64
|
||||
# Windows stuff: configuration for cross compliation with mingw-w64
|
||||
win32 {
|
||||
QMAKE_TARGET_PRODUCT = "$${appname}"
|
||||
QMAKE_TARGET_COPYRIGHT = "by $${appauthor}"
|
||||
}
|
||||
mingw-w64-manualstrip-dll {
|
||||
QMAKE_POST_LINK=$${CROSS_COMPILE}strip --strip-unneeded ./release/$(TARGET); \
|
||||
$${CROSS_COMPILE}strip --strip-unneeded ./release/lib$(TARGET).a
|
||||
|
@ -84,5 +86,7 @@ mingw-w64-manualstrip-exe {
|
|||
QMAKE_POST_LINK=$${CROSS_COMPILE}strip --strip-unneeded ./release/$(TARGET)
|
||||
}
|
||||
mingw-w64-noversion {
|
||||
VERSION = ""
|
||||
TARGET_EXT = ".dll"
|
||||
TARGET_VERSION_EXT = ""
|
||||
CONFIG += skip_target_version_ext
|
||||
}
|
||||
|
|
11
main.cpp
11
main.cpp
|
@ -52,10 +52,11 @@ int main(int argc, char *argv[])
|
|||
QCoreApplication application(argc, argv);
|
||||
// setup manager
|
||||
Manager manager(config);
|
||||
manager.applyPacmanConfig();
|
||||
manager.applyRepoIndexConfig();
|
||||
cerr << shchar << "Loading databases ..." << endl;
|
||||
manager.registerDataBasesFromPacmanConfig();
|
||||
manager.registerDatabasesFromRepoIndexConfig();
|
||||
manager.initAlpmDataBases(configArgs.serverArg.isPresent());
|
||||
cerr << shchar << "Restoring cache ..." << endl;
|
||||
manager.restoreCache();
|
||||
if(configArgs.serverArg.isPresent()) {
|
||||
// setup the server
|
||||
|
@ -67,13 +68,13 @@ int main(int argc, char *argv[])
|
|||
BuildOrderResolver resolver(manager);
|
||||
BuildOrderResolver::printResults(resolver.resolve(configArgs.buildOrderArg.values()));
|
||||
} else if(configArgs.mingwBundleArg.isPresent()) {
|
||||
MingwBundle bundle(manager, configArgs.mingwBundleArg.values(), configArgs.iconThemesArg.values());
|
||||
MingwBundle bundle(manager, configArgs.mingwBundleArg.values(), configArgs.iconThemesArg.values(), configArgs.extraPackagesArg.values());
|
||||
bundle.createBundle(configArgs.targetDirArg.isPresent() ? configArgs.targetDirArg.values().front() : string("."),
|
||||
configArgs.targetNameArg.values().front(),
|
||||
configArgs.targetFormatArg.isPresent() ? configArgs.targetFormatArg.values().front() : string("zip"));
|
||||
configArgs.targetFormatArg.isPresent() ? configArgs.targetFormatArg.values().front() : string("zip"),
|
||||
configArgs.defaultIconThemeArg.isPresent() ? configArgs.defaultIconThemeArg.values().front() : string());
|
||||
} else if(configArgs.upgradeLookupArg.isPresent()) {
|
||||
UpgradeLookupCli upgradeLookup(manager, configArgs.upgradeLookupArg.values().front());
|
||||
QObject::connect(&upgradeLookup, &UpgradeLookupCli::finished, &application, &QCoreApplication::quit);
|
||||
return application.exec();
|
||||
}
|
||||
} else if(!configArgs.helpArg.isPresent()) {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "../alpm/manager.h"
|
||||
#include "../alpm/upgradelookup.h"
|
||||
#include "../alpm/suggestionslookup.h"
|
||||
#include "../alpm/config.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
|
@ -16,7 +17,7 @@ using namespace std;
|
|||
|
||||
namespace RepoIndex {
|
||||
|
||||
Connection::Connection(const Manager &alpmManager, QWebSocket *socket, QObject *parent) :
|
||||
Connection::Connection(Manager &alpmManager, QWebSocket *socket, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_socket(socket),
|
||||
m_manager(alpmManager),
|
||||
|
@ -75,16 +76,37 @@ void Connection::handleQuery(const QJsonObject &obj)
|
|||
const auto id = obj.value(QStringLiteral("id"));
|
||||
if(what == QLatin1String("basicrepoinfo")) {
|
||||
m_repoInfoUpdatesRequested = obj.value(QStringLiteral("updates")).toBool(m_repoInfoUpdatesRequested);
|
||||
sendResults(what, id, m_manager.basicRepoInfo());
|
||||
sendResult(what, id, m_manager.basicRepoInfo());
|
||||
} else if(what == QLatin1String("basicpkginfo")) {
|
||||
sendResults(what, id, m_manager.packageInfo(obj.value("sel").toObject(), false));
|
||||
sendResults(what, id, m_manager.packageInfo(obj.value("sel").toObject(), Manager::Basics));
|
||||
} else if(what == QLatin1String("pkgdetails")) {
|
||||
sendResults(what, id, m_manager.packageInfo(obj.value("sel").toObject(), Manager::Details));
|
||||
} else if(what == QLatin1String("fullpkginfo")) {
|
||||
sendResults(what, id, m_manager.packageInfo(obj.value("sel").toObject(), true));
|
||||
// TODO: figure out why QFlags doesn't work, in the mean time, use static_cast workaround
|
||||
sendResults(what, id, m_manager.packageInfo(obj.value("sel").toObject(), static_cast<Manager::PackageInfoPart>(static_cast<int>(Manager::Basics) | static_cast<int>(Manager::Details))));
|
||||
} else if(what == QLatin1String("groupinfo")) {
|
||||
m_groupInfoUpdatesRequested = obj.value(QStringLiteral("updates")).toBool(m_groupInfoUpdatesRequested);
|
||||
sendResults(what, id, m_manager.groupInfo());
|
||||
} else if(what == QLatin1String("suggestions")) {
|
||||
auto *suggestionsLookup = new SuggestionsLookup(m_manager, obj);
|
||||
if(suggestionsLookup->finished()) {
|
||||
sendResult(what, id, suggestionsLookup->results());
|
||||
} else if(!suggestionsLookup->errors().isEmpty()) {
|
||||
QJsonObject results;
|
||||
results.insert(QStringLiteral("errors"), suggestionsLookup->errors());
|
||||
sendResult(what, id, results);
|
||||
} else {
|
||||
connect(suggestionsLookup, &SuggestionsLookup::resultsAvailable, this, &Connection::sendResult);
|
||||
}
|
||||
} else if(what == QLatin1String("upgradelookup")) {
|
||||
connect(new UpgradeLookupJson(m_manager, obj), &UpgradeLookupJson::resultsAvailable, this, &Connection::sendResult);
|
||||
auto *upgradeLookup = new UpgradeLookupJson(m_manager, obj);
|
||||
if(upgradeLookup->errors().isEmpty()) {
|
||||
connect(upgradeLookup, &UpgradeLookupJson::resultsAvailable, this, &Connection::sendResult);
|
||||
} else {
|
||||
QJsonObject results;
|
||||
results.insert(QStringLiteral("errors"), upgradeLookup->errors());
|
||||
sendResult(what, id, results);
|
||||
}
|
||||
} else if(what == QLatin1String("ping")) {
|
||||
sendResult(what, id, QStringLiteral("pong"));
|
||||
} else {
|
||||
|
@ -103,6 +125,17 @@ void Connection::handleCmd(const QJsonObject &obj)
|
|||
} else {
|
||||
sendError(QStringLiteral("rejected"), id);
|
||||
}
|
||||
} else if(what == QLatin1String("reinitalpm")) {
|
||||
if(m_socket->peerAddress().isLoopback()) {
|
||||
cerr << shchar << "Info: Reinit of ALPM databases triggered via web interface." << endl;
|
||||
m_manager.cleanupAlpm();
|
||||
m_manager.initAlpmHandle();
|
||||
m_manager.registerDataBasesFromPacmanConfig();
|
||||
m_manager.registerDatabasesFromRepoIndexConfig();
|
||||
m_manager.initAlpmDataBases(true);
|
||||
} else {
|
||||
sendError(QStringLiteral("rejected"), id);
|
||||
}
|
||||
} else {
|
||||
sendError(QStringLiteral("unknown command"), id);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ class Connection : public QObject
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Connection(const RepoIndex::Manager &alpmManager, QWebSocket *socket, QObject *parent = nullptr);
|
||||
Connection(RepoIndex::Manager &alpmManager, QWebSocket *socket, QObject *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void processTextMessage(const QString &message);
|
||||
|
@ -33,7 +33,7 @@ private:
|
|||
void handleCmd(const QJsonObject &obj);
|
||||
|
||||
QWebSocket *m_socket;
|
||||
const RepoIndex::Manager &m_manager;
|
||||
RepoIndex::Manager &m_manager;
|
||||
bool m_repoInfoUpdatesRequested;
|
||||
bool m_groupInfoUpdatesRequested;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ using namespace std;
|
|||
|
||||
namespace RepoIndex {
|
||||
|
||||
Server::Server(const RepoIndex::Manager &alpmManager, const RepoIndex::Config &config, QObject *parent) :
|
||||
Server::Server(RepoIndex::Manager &alpmManager, const RepoIndex::Config &config, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_server(new QWebSocketServer(QStringLiteral("Repository index server"),
|
||||
config.serverInsecure() ? QWebSocketServer::NonSecureMode : QWebSocketServer::SecureMode,
|
||||
|
|
|
@ -22,7 +22,7 @@ class Server : public QObject
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Server(const RepoIndex::Manager &alpmManager, const RepoIndex::Config &config, QObject *parent = nullptr);
|
||||
Server(RepoIndex::Manager &alpmManager, const RepoIndex::Config &config, QObject *parent = nullptr);
|
||||
~Server();
|
||||
|
||||
signals:
|
||||
|
@ -34,7 +34,7 @@ private slots:
|
|||
|
||||
private:
|
||||
QWebSocketServer *m_server;
|
||||
const RepoIndex::Manager &m_alpmManager;
|
||||
RepoIndex::Manager &m_alpmManager;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -72,8 +72,8 @@ void AurFullPackageReply::processData()
|
|||
// TODO
|
||||
}
|
||||
|
||||
AurSuggestionsReply::AurSuggestionsReply(QNetworkReply *networkReply) :
|
||||
SuggestionsReply(networkReply)
|
||||
AurSuggestionsReply::AurSuggestionsReply(QNetworkReply *networkReply, const QString &term, UserRepository *repo) :
|
||||
SuggestionsReply(networkReply, term, repo)
|
||||
{}
|
||||
|
||||
void AurSuggestionsReply::processData()
|
||||
|
@ -86,7 +86,16 @@ void AurSuggestionsReply::processData()
|
|||
//const QJsonDocument doc = QJsonDocument::fromJson(data, &error);
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &error);
|
||||
if(error.error == QJsonParseError::NoError) {
|
||||
m_suggestions = doc.array();
|
||||
auto &packages = m_repo->packages();
|
||||
for(const auto &suggestion : doc.array()) {
|
||||
const auto suggestionString = suggestion.toString();
|
||||
if(!suggestionString.isEmpty()) {
|
||||
auto &package = packages[suggestionString];
|
||||
if(!package) {
|
||||
package = make_unique<AurPackage>(suggestionString, static_cast<UserRepository *>(m_repo));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_error = QStringLiteral("Error: Unable to parse JSON received from AUR: ") % error.errorString() % QStringLiteral(" at character ") % QString::number(error.offset);
|
||||
}
|
||||
|
@ -97,7 +106,7 @@ void AurSuggestionsReply::processData()
|
|||
}
|
||||
|
||||
UserRepository::UserRepository(QNetworkAccessManager &networkAccessManager, QObject *parent) :
|
||||
Repository(QStringLiteral("AUR"), parent),
|
||||
Repository(QStringLiteral("AUR"), invalidIndex, parent),
|
||||
m_networkAccessManager(networkAccessManager)
|
||||
{
|
||||
m_description = QStringLiteral("Arch User Repository");
|
||||
|
@ -122,14 +131,20 @@ PackageDetailAvailability UserRepository::requestsRequired(PackageDetail package
|
|||
}
|
||||
}
|
||||
|
||||
AurSuggestionsReply *UserRepository::requestSuggestions(const QString &phrase) const
|
||||
AurSuggestionsReply *UserRepository::requestSuggestions(const QString &term) const
|
||||
{
|
||||
auto url = m_aurRpcUrl;
|
||||
QUrlQuery query;
|
||||
query.addQueryItem(rpcRequestTypeKey, rpcRequestTypeSuggest);
|
||||
query.addQueryItem(rpcArgKey, phrase);
|
||||
url.setQuery(query);
|
||||
return new AurSuggestionsReply(m_networkAccessManager.get(QNetworkRequest(url)));
|
||||
size_t remainingSuggestions = 20;
|
||||
for(auto i = packages().lower_bound(term), end = packages().cend(); i != end && remainingSuggestions && i->first.startsWith(term, Qt::CaseInsensitive); ++i, --remainingSuggestions);
|
||||
if(remainingSuggestions) {
|
||||
auto url = m_aurRpcUrl;
|
||||
QUrlQuery query;
|
||||
query.addQueryItem(rpcRequestTypeKey, rpcRequestTypeSuggest);
|
||||
query.addQueryItem(rpcArgKey, term);
|
||||
url.setQuery(query);
|
||||
return new AurSuggestionsReply(m_networkAccessManager.get(QNetworkRequest(url)), term, const_cast<UserRepository *>(this));
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
AurPackageReply *UserRepository::requestPackageInfo(const QStringList &packageNames, bool forceUpdate) const
|
||||
|
|
|
@ -47,7 +47,7 @@ class AurSuggestionsReply : public SuggestionsReply
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AurSuggestionsReply(QNetworkReply *networkReply);
|
||||
AurSuggestionsReply(QNetworkReply *networkReply, const QString &term, UserRepository *repo);
|
||||
|
||||
private slots:
|
||||
void processData();
|
||||
|
@ -65,7 +65,7 @@ public:
|
|||
static void setAurRpcUrl(const QUrl &aurRpcUrl);
|
||||
|
||||
PackageDetailAvailability requestsRequired(PackageDetail packageDetail) const;
|
||||
AurSuggestionsReply *requestSuggestions(const QString &phrase) const;
|
||||
AurSuggestionsReply *requestSuggestions(const QString &term) const;
|
||||
AurPackageReply *requestPackageInfo(const QStringList &packageNames, bool forceUpdate = false) const;
|
||||
AurFullPackageReply *requestFullPackageInfo(const QStringList &packageNames, bool forceUpdate = false) const;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ projectname = repoindex
|
|||
appname = "Repository Index"
|
||||
appauthor = Martchus
|
||||
appurl = "https://github.com/$${appauthor}/$${projectname}"
|
||||
QMAKE_TARGET_DESCRIPTION = "Provides a web interface to browse Arch Linux package repositories."
|
||||
VERSION = 1.0.0
|
||||
|
||||
# include ../../common.pri when building as part of a subdirs project; otherwise include general.pri
|
||||
|
@ -32,7 +33,8 @@ SOURCES += main.cpp \
|
|||
alpm/aurpackage.cpp \
|
||||
alpm/alpmdatabase.cpp \
|
||||
alpm/repository.cpp \
|
||||
alpm/upgradelookup.cpp
|
||||
alpm/upgradelookup.cpp \
|
||||
alpm/suggestionslookup.cpp
|
||||
|
||||
HEADERS += \
|
||||
alpm/manager.h \
|
||||
|
@ -50,7 +52,8 @@ HEADERS += \
|
|||
alpm/aurpackage.h \
|
||||
alpm/alpmdatabase.h \
|
||||
alpm/repository.h \
|
||||
alpm/upgradelookup.h
|
||||
alpm/upgradelookup.h \
|
||||
alpm/suggestionslookup.h
|
||||
|
||||
DISTFILES += \
|
||||
README.md \
|
||||
|
|
|
@ -69,7 +69,15 @@
|
|||
</div>
|
||||
</form>
|
||||
<form class="navbar-form navbar-right">
|
||||
<button id="nav_stop_server" class="btn btn-danger" onclick="repoindex.client.stopServer();">Stop server</button>
|
||||
<div class="btn-group" id="nav_server">
|
||||
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
Server <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" onclick="repoindex.client.stopServer(); return false;">Stop</a></li>
|
||||
<li><a href="#" onclick="repoindex.client.reinitAlpm(); return false;">Reinit ALPM</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<button id="nav_connect" class="btn btn-danger" onclick="repoindex.client.init();"><span class="glyphicon glyphicon glyphicon-refresh" aria-hidden="true" id="connection_glyphicon"></span> <span id="connection_status">Disconnected</span></button>
|
||||
</form>
|
||||
</div><!-- /.navbar-collapse -->
|
||||
|
@ -96,8 +104,8 @@
|
|||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="repo_buttons_settings_dropdown">
|
||||
<li><input type="checkbox" name="reposButtonsExclusive" id="repos_buttons_exclusive"><label for="repos_buttons_exclusive">Exclusive selection</label></li>
|
||||
<li><a href="#" onclick="repoindex.pageManager.repoManager.buttonContainerExclusiveButton.checked = false; repoindex.pageManager.repoManager.upgradeEnabledAll(true); return false;">Select all</a></li>
|
||||
<li><a href="#" onclick="repoindex.pageManager.repoManager.upgradeEnabledAll(false); return false;">Remove selection</a></li>
|
||||
<li><a href="#" onclick="repoindex.pageManager.repoManager.buttonContainerExclusiveButton.checked = false; repoindex.pageManager.repoManager.updateEnabledAll(true); return false;">Select all</a></li>
|
||||
<li><a href="#" onclick="repoindex.pageManager.repoManager.updateEnabledAll(false); return false;">Remove selection</a></li>
|
||||
</ul>
|
||||
</span>
|
||||
</form>
|
||||
|
|
201
web/js/client.js
201
web/js/client.js
|
@ -13,16 +13,15 @@
|
|||
BasicPackageInfo: "basicpkginfo",
|
||||
FullPackageInfo: "fullpkginfo",
|
||||
GroupInfo: "groupinfo",
|
||||
UpgradeLookup: "upgradelookup"
|
||||
UpgradeLookup: "upgradelookup",
|
||||
Suggestions: "suggestions"
|
||||
};
|
||||
|
||||
repoindex.isLoopback = function(domain) {
|
||||
return domain === "localhost" || domain === "127.0.0.1" || domain === "::1";
|
||||
};
|
||||
|
||||
|
||||
|
||||
// responsible for the connection to the server
|
||||
// responsible for the connection to the server; holds all repo/package information returned by the server
|
||||
var Client = function(url) {
|
||||
// basic initialization
|
||||
this.url = url;
|
||||
|
@ -191,10 +190,10 @@
|
|||
this.useBasicRepoInfo(values);
|
||||
break;
|
||||
case repoindex.RequestType.BasicPackageInfo:
|
||||
// the info is used via the registred callbacks only
|
||||
this.usePackageInfo(values);
|
||||
break;
|
||||
case repoindex.RequestType.FullPackageInfo:
|
||||
// the info is used via the registred callbacks only
|
||||
this.usePackageInfo(values);
|
||||
break;
|
||||
case repoindex.RequestType.GroupInfo:
|
||||
this.useGroupInfo(values);
|
||||
|
@ -202,6 +201,9 @@
|
|||
case repoindex.RequestType.UpgradeLookup:
|
||||
// the info is used via the registred callbacks only
|
||||
break;
|
||||
case repoindex.RequestType.Suggestions:
|
||||
this.useSuggestions(values);
|
||||
break;
|
||||
default:
|
||||
pageManager.addError("Server replied unknown results: " + what);
|
||||
return; // don't invoke callbacks when results are of unknown type
|
||||
|
@ -233,14 +235,37 @@
|
|||
this.scheduleRequest(repoindex.RequestType.GroupInfo, {upgrades: "true"}, callback);
|
||||
};
|
||||
|
||||
this.stopServer = function() {
|
||||
this.requestSuggestions = function(repoNames, searchTerm, callback) {
|
||||
this.scheduleRequest(repoindex.RequestType.Suggestions, {repos: repoNames, term: searchTerm});
|
||||
};
|
||||
|
||||
this.requestAurSuggestions = function(term) {
|
||||
var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if(xmlhttp.readyState === 4 && xmlhttp.status === 200) {
|
||||
repoindex.client.useAurSuggestions(JSON.parse(xmlhttp.responseText));
|
||||
}
|
||||
};
|
||||
xmlhttp.open("GET", "http://aur.archlinux.org/rpc.php?type=suggest&arg=" + encodeURIComponent(term), true);
|
||||
xmlhttp.send();
|
||||
};
|
||||
|
||||
this.sendCmd = function(cmd) {
|
||||
if(this.isOpen()) {
|
||||
this.socket.send(JSON.stringify({class: "cmd", what: "stop"}));
|
||||
this.socket.send(JSON.stringify({class: "cmd", what: cmd}));
|
||||
} else {
|
||||
repoindex.pageManager.addError("Not connected to a server.");
|
||||
}
|
||||
};
|
||||
|
||||
this.stopServer = function() {
|
||||
this.sendCmd("stop");
|
||||
};
|
||||
|
||||
this.reinitAlpm = function() {
|
||||
this.sendCmd("reinitalpm");
|
||||
};
|
||||
|
||||
this.checkForUpgrades = function(dbName, syncdbNames, callback) {
|
||||
var params = {
|
||||
db: dbName
|
||||
|
@ -251,29 +276,102 @@
|
|||
this.scheduleRequest(repoindex.RequestType.UpgradeLookup, params, callback);
|
||||
};
|
||||
|
||||
// define helper functions to access repo/package information
|
||||
this.getPackageInfo = function(repoName, packageName) {
|
||||
var repoInfo = this.repos[repoName];
|
||||
if(!repoInfo) {
|
||||
// the repo doesn't exists; might happen when receiving AUR suggestions directly
|
||||
// -> just create a new, empty repo
|
||||
this.repo[repoName] = (repoInfo = {name: repoName, packages: {}});
|
||||
}
|
||||
var packageInfo = repoInfo.packages[packageName];
|
||||
if(!packageInfo) {
|
||||
repoInfo.packages[packageName] = (packageInfo = {repo: repoName});
|
||||
}
|
||||
return packageInfo;
|
||||
};
|
||||
|
||||
// define functions to use differend kinds of results
|
||||
this.useBasicRepoInfo = function(values) {
|
||||
if(!values) {
|
||||
this.useBasicRepoInfo = function(value) {
|
||||
if(!value) {
|
||||
repoindex.pageManager.addError("Server replied insufficiant basic repo info.");
|
||||
return false;
|
||||
}
|
||||
// upgrade repos and package list
|
||||
this.repos = {};
|
||||
this.repos = value;
|
||||
var repoMgr = repoindex.pageManager.repoManager;
|
||||
var pkgMgr = repoindex.pageManager.packageManager;
|
||||
repoMgr.removeEntries();
|
||||
pkgMgr.removeEntries();
|
||||
for(var i1 = 0; i1 < values.length; ++i1) {
|
||||
this.repos[values[i1].name] = values[i1];
|
||||
var repoEntry = repoMgr.addEntry(values[i1]);
|
||||
var packages = repoEntry.info.packages;
|
||||
for(var i2 = 0; i2 < packages.length; ++i2) {
|
||||
pkgMgr.addEntry(repoEntry, packages[i2]);
|
||||
var reposInOrder = [];
|
||||
for(var repoName in value) {
|
||||
if(value.hasOwnProperty(repoName)) {
|
||||
reposInOrder.push({name: repoName, info: value[repoName]});
|
||||
//var repoInfo = value[repoName];
|
||||
}
|
||||
}
|
||||
reposInOrder.sort(function(lhs, rhs) {
|
||||
if(lhs === rhs) {
|
||||
return 1;
|
||||
} else if(lhs.info.index !== undefined) {
|
||||
if(rhs.info.index !== undefined) {
|
||||
return lhs.info.index > rhs.info.index;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if(rhs.info.index !== undefined) {
|
||||
return 1;
|
||||
} else {
|
||||
return lhs.name > rhs.name;
|
||||
}
|
||||
});
|
||||
for(var i = 0; i < reposInOrder.length; ++i) {
|
||||
var repoName = reposInOrder[i].name;
|
||||
var repoInfo = reposInOrder[i].info;
|
||||
var repoEntry = repoMgr.addEntry(repoName, repoInfo);
|
||||
var packages = repoInfo.packages;
|
||||
for(var packageName in packages) {
|
||||
if(value.hasOwnProperty(repoName)) {
|
||||
var packageInfo = packages[packageName];
|
||||
pkgMgr.addEntry(repoEntry, packageName, packageInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.hasBasicRepoInfo = true;
|
||||
pkgMgr.invalidate();
|
||||
repoMgr.invalidate();
|
||||
repoMgr.applyRepoStatusChange();
|
||||
};
|
||||
|
||||
this.usePackageInfo = function(values) {
|
||||
if(!Array.isArray(values)) {
|
||||
repoindex.pageManager.addError("Server replied insufficiant package info.");
|
||||
return false;
|
||||
}
|
||||
for(var i = 0; i < values.length; ++i) {
|
||||
var value = values[i];
|
||||
var repo = repoindex.client.repos[value.repo];
|
||||
if(repo) {
|
||||
var package = repo.packages[value.name];
|
||||
if(package) {
|
||||
if(value.basics) {
|
||||
package.basics = value.basics;
|
||||
}
|
||||
if(value.details) {
|
||||
package.details = value.details;
|
||||
}
|
||||
} else {
|
||||
repoindex.pageManager.addError("Package info replied by server refers to unknown package.");
|
||||
}
|
||||
} else {
|
||||
repoindex.pageManager.addError("Package info replied by server refers to unknown repository.");
|
||||
}
|
||||
}
|
||||
if(value.error) {
|
||||
repoindex.pageManager.addError("Server replied error in package info: " + value.error);
|
||||
}
|
||||
// updating table rows or any other GUI elements is done via callbacks
|
||||
};
|
||||
|
||||
this.useGroupInfo = function(values) {
|
||||
|
@ -293,13 +391,80 @@
|
|||
groupMgr.useRequestedData();
|
||||
};
|
||||
|
||||
this.useSuggestions = function(values) {
|
||||
if(Array.isArray(values)) {
|
||||
for(var i1 = 0; i1 < values.length; ++i1) {
|
||||
var value = values[i1];
|
||||
var repoName = value.repo;
|
||||
var suggestions = value.res;
|
||||
if(Array.isArray(suggestions)) {
|
||||
if(suggestions.length > 0) {
|
||||
var repoEntry = repoindex.pageManager.repoManager.entryByName(repoName);
|
||||
if(repoEntry) {
|
||||
var pkgMgr = repoindex.pageManager.packageManager;
|
||||
for(var i2 = 0; i2 < suggestions.length; ++i2) {
|
||||
var packageName = suggestions[i2];
|
||||
if(!pkgMgr.entryByName(packageName)) {
|
||||
var packageInfo = this.getPackageInfo(repoName, packageName);
|
||||
pkgMgr.addEntry(repoEntry, packageName, packageInfo);
|
||||
}
|
||||
}
|
||||
pkgMgr.invalidate();
|
||||
} else {
|
||||
repoindex.pageManager.addError("There is no repo entry for the suggestions replied by the server.");
|
||||
}
|
||||
var entries = pkgMgr.entries;
|
||||
entries.sort(function(lhs, rhs) {
|
||||
return lhs.name > rhs.name;
|
||||
});
|
||||
for(var i = 0; i < entries.length; ++i) {
|
||||
entries[i].index = i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO: handle error
|
||||
}
|
||||
}
|
||||
} else if(Array.isArray(values.errors)) {
|
||||
for(var i = 0; i < values.errors.length; ++i) {
|
||||
repoindex.pageManager.addError("Error replied by server in response of suggestion request: " + value.errors[i]);
|
||||
}
|
||||
} else {
|
||||
repoindex.pageManager.addError("Server replied insufficiant suggestion reply.");
|
||||
}
|
||||
};
|
||||
|
||||
this.useAurSuggestions = function(suggestions) {
|
||||
if(Array.isArray(suggestions)) {
|
||||
if(suggestions.length > 0) {
|
||||
var aurEntry = repoindex.pageManager.repoManager.entryByName("AUR");
|
||||
if(aurEntry) {
|
||||
var pkgMgr = repoindex.pageManager.packageManager;
|
||||
for(var i = 0; i < suggestions.length; ++i) {
|
||||
var packageName = suggestions[i];
|
||||
if(!pkgMgr.entryByName(packageName)) {
|
||||
var packageInfo = this.getPackageInfo("AUR", packageName);
|
||||
pkgMgr.addEntry(aurEntry, packageName, packageInfo);
|
||||
}
|
||||
}
|
||||
pkgMgr.invalidate();
|
||||
} else {
|
||||
// there is no AUR entry but we requested AUR suggestions
|
||||
// -> shouldn't happen
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO: handle error
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
// create a global client used within the entire document
|
||||
repoindex.client = new Client((window.location.protocol === "https:" ? "wss://" : "ws://") + document.domain + ":1234");
|
||||
if(!repoindex.isLoopback(document.domain)) {
|
||||
// hide stop button if server is not on loopback interface
|
||||
document.getElementById("nav_stop_server").style.display = "none";
|
||||
document.getElementById("nav_server").style.display = "none";
|
||||
}
|
||||
|
||||
return repoindex;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
this.appendChild(cellElement);
|
||||
};
|
||||
this.initTableRow = function() {};
|
||||
this.upgradeTableRow = function() {
|
||||
this.updateTableRow = function() {
|
||||
this.rowElement.wipeChildren();
|
||||
this.initTableRow();
|
||||
};
|
||||
|
@ -43,7 +43,7 @@
|
|||
this.rowElement.style.display = "table-row";
|
||||
};
|
||||
|
||||
this.upgradeEnabled = function() {};
|
||||
this.updateEnabled = function() {};
|
||||
};
|
||||
|
||||
repoindex.EntryManager = function(EntryType, entryContainer, pagination) {
|
||||
|
@ -52,7 +52,7 @@
|
|||
this.entryContainer = entryContainer;
|
||||
this.entries = [];
|
||||
this.pageName = undefined;
|
||||
this.upgradeRequired = false;
|
||||
this.updateRequired = false;
|
||||
|
||||
// init pagination
|
||||
if((this.pagination = pagination)) {
|
||||
|
@ -79,7 +79,7 @@
|
|||
|
||||
// define default filter predicate
|
||||
this.filterPred = function(entry) {
|
||||
return (!this.filterName || (this.filterNameExact ? entry.info.name === this.filterName : entry.info.name.contains(this.filterName)))
|
||||
return (!this.filterName || (this.filterNameExact ? entry.name === this.filterName : entry.name.contains(this.filterName)))
|
||||
&& (!this.filterRepos || this.filterRepos.contains(entry.info.repo));
|
||||
};
|
||||
|
||||
|
@ -96,7 +96,7 @@
|
|||
//}
|
||||
// upgrade pagination (the pageSelected method defined above will be invoked here automatically)
|
||||
this.pagination.entryCount = this.filteredEntries.length;
|
||||
this.pagination.upgrade();
|
||||
this.pagination.update();
|
||||
};
|
||||
|
||||
this.removeFilter = function() {
|
||||
|
@ -108,15 +108,15 @@
|
|||
this.refreshInfo = function() {};
|
||||
|
||||
this.invalidate = function() {
|
||||
this.upgradeRequired = true;
|
||||
this.upgrade();
|
||||
this.updateRequired = true;
|
||||
this.update();
|
||||
};
|
||||
|
||||
this.upgrade = function() {
|
||||
if(this.upgradeRequired && (!this.pageName || this.pageName === repoindex.pageManager.currentPage)) {
|
||||
this.update = function() {
|
||||
if(this.updateRequired && (!this.pageName || this.pageName === repoindex.pageManager.currentPage)) {
|
||||
this.applyFilter();
|
||||
this.infoBox.innerHTML = this.infoText();
|
||||
this.upgradeRequired = false;
|
||||
this.updateRequired = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -126,9 +126,9 @@
|
|||
this.entryContainer.wipeChildren();
|
||||
};
|
||||
|
||||
this.upgradeEnabledForAll = function(enabled) {
|
||||
this.updateEnabledForAll = function(enabled) {
|
||||
for(var i = 0; i < this.entries.length; ++i) {
|
||||
this.entries[i].upgradeEnabled(enabled);
|
||||
this.entries[i].updateEnabled(enabled);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -185,14 +185,14 @@
|
|||
if(this.customSelection) {
|
||||
for(var i = 0; i < this.customSelection.length; ++i) {
|
||||
var entry = this.customSelection[i];
|
||||
if(entry.info && entry.info.name === entryName) {
|
||||
if(entry.name === entryName) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(var i = 0; i < this.entries.length; ++i) {
|
||||
var entry = this.entries[i];
|
||||
if(entry.info && entry.info.name === entryName) {
|
||||
if(entry.name === entryName) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
var GroupEntry = {};
|
||||
GroupEntry.prototype = new repoindex.Entry();
|
||||
GroupEntry.prototype.constructor = GroupEntry;
|
||||
GroupEntry = function(groupInfo) {
|
||||
repoindex.Entry.prototype.constructor.call(this, groupInfo);
|
||||
GroupEntry = function(groupName, groupInfo) {
|
||||
repoindex.Entry.prototype.constructor.call(this, groupName, groupInfo);
|
||||
|
||||
this.initTableRow = function() {
|
||||
this.rowElement.addCell(this.info.name);
|
||||
this.rowElement.addCell(this.name);
|
||||
this.rowElement.addCell(this.info.repo);
|
||||
var packagesCellElement = document.createElement("td");
|
||||
repoindex.setPackageNames(packagesCellElement, this.info.packages);
|
||||
|
@ -30,13 +30,13 @@
|
|||
this.getContainerQuantity = repoindex.entryManagerGetRepoQuantity;
|
||||
|
||||
this.addEntry = function(repoName, groupName, packages) {
|
||||
var groupInfo = {
|
||||
index: this.entries.length,
|
||||
var entry = new GroupEntry(groupName, {
|
||||
repo: repoName,
|
||||
name: groupName,
|
||||
packages: packages
|
||||
};
|
||||
this.entries.push(new GroupEntry(groupInfo));
|
||||
});
|
||||
entry.index = this.entries.length;
|
||||
this.entries.push(entry);
|
||||
};
|
||||
|
||||
// handle a page selection
|
||||
|
|
|
@ -8,67 +8,30 @@
|
|||
var PackageEntry = {};
|
||||
PackageEntry.prototype = new repoindex.Entry();
|
||||
PackageEntry.prototype.constructor = PackageEntry;
|
||||
PackageEntry = function(repoEntry, packageInfo, color) {
|
||||
PackageEntry = function(repoEntry, packageName, packageInfo, color) {
|
||||
this.repoEntry = repoEntry; // might be undefined
|
||||
repoindex.Entry.prototype.constructor.call(this, packageInfo);
|
||||
repoindex.Entry.prototype.constructor.call(this, packageName, packageInfo);
|
||||
|
||||
// init row element
|
||||
if(color) {
|
||||
this.rowElement.style.backgroundColor = color;
|
||||
}
|
||||
this.rowElement.onclick = function() {
|
||||
repoindex.pageManager.packageManager.showPackageInfoForIndex(this.entry.info.index);
|
||||
repoindex.pageManager.packageManager.showPackageInfoForIndex(this.entry.index);
|
||||
};
|
||||
|
||||
this.initTableRow = function() {
|
||||
var basics = this.info.basics ? this.info.basics : {};
|
||||
var srcOnly = this.repoEntry && this.repoEntry.info.srcOnly;
|
||||
var values = [srcOnly ? "n/a" : this.info.arch, this.info.repo, this.info.name, this.info.ver, this.info.desc, srcOnly ? "n/a" : this.info.bdate, this.info.flagdate];
|
||||
var pkgOnly = this.repoEntry && this.repoEntry.info.pkgOnly;
|
||||
var version = this.curVer ? (this.curVer + " → " + (basics.ver ? basics.ver : "?")) : basics.ver;
|
||||
var values = [srcOnly ? "n/a" : basics.arch, this.info.repo, this.name, version, basics.desc, srcOnly ? "n/a" : basics.bdate, pkgOnly ? "n/a" : basics.flagdate];
|
||||
for(var i = 0; i < 7; ++i) {
|
||||
this.rowElement.addCell(repoindex.makeStr(values[i]));
|
||||
}
|
||||
};
|
||||
|
||||
this.initTableRow();
|
||||
|
||||
this.applyBasicInfo = function(info, noUpgrade) {
|
||||
if(info.repo) this.info.repo = info.repo;
|
||||
if(info.name) this.info.name = info.name;
|
||||
if(info.arch) this.info.arch = info.arch;
|
||||
if(info.ver) this.info.ver = info.ver;
|
||||
if(info.desc) this.info.desc = info.desc;
|
||||
if(info.bdate) this.info.bdate = info.bdate;
|
||||
if(info.flagdate) this.info.flagdate = info.flagdate;
|
||||
this.info.basic = true;
|
||||
if(!noUpgrade) {
|
||||
this.upgradeTableRow();
|
||||
}
|
||||
};
|
||||
|
||||
this.applyFullInfo = function(info, noUpgrade) {
|
||||
this.applyBasicInfo(info);
|
||||
if(info.idate) this.info.idate = info.idate;
|
||||
if(info.isize) this.info.isize = info.isize;
|
||||
if(info.url) this.info.url = info.url;
|
||||
if(info.isize) this.info.isize = info.isize;
|
||||
if(info.lic) this.info.lic = info.lic;
|
||||
if(info.grp) this.info.grp = info.grp;
|
||||
if(info.prov) this.info.prov = info.prov;
|
||||
if(info.optd) this.info.optd = info.optd;
|
||||
if(info.deps) this.info.deps = info.deps;
|
||||
if(info.requ) this.info.requ = info.requ;
|
||||
if(info.conf) this.info.conf = info.conf;
|
||||
if(info.repl) this.info.repl = info.repl;
|
||||
if(info.pack) this.info.pack = info.pack;
|
||||
if(info.expl) this.info.expl = info.expl;
|
||||
if(info.scri) this.info.scri = info.scri;
|
||||
if(info.sig) this.info.sig = info.sig;
|
||||
if(info.file) this.info.file = info.file;
|
||||
if(info.files) this.info.files = info.files;
|
||||
this.info.full = true;
|
||||
if(!noUpgrade) {
|
||||
this.upgradeTableRow();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
repoindex.PackageEntryManager = {};
|
||||
|
@ -82,18 +45,16 @@
|
|||
this.containerNamePlural = "repositories";
|
||||
this.getContainerQuantity = repoindex.entryManagerGetRepoQuantity;
|
||||
|
||||
this.createCustomEntry = function(color) {
|
||||
return new PackageEntry(undefined, {}, color);
|
||||
this.createCustomEntry = function(repoEntry, packageName, packageInfo, color) {
|
||||
return new PackageEntry(repoEntry, packageName, packageInfo, color);
|
||||
};
|
||||
|
||||
this.addEntry = function(repoEntry, packageName) {
|
||||
var packageInfo = {
|
||||
index: this.entries.length,
|
||||
repo: repoEntry.info.name,
|
||||
name: packageName,
|
||||
received: false
|
||||
};
|
||||
var entry = new PackageEntry(repoEntry, packageInfo);
|
||||
this.addEntry = function(repoEntry, packageName, packageInfo) {
|
||||
packageInfo.repo = repoEntry.name;
|
||||
packageInfo.name = packageName;
|
||||
packageInfo.received = false;
|
||||
var entry = new PackageEntry(repoEntry, packageName, packageInfo);
|
||||
entry.index = this.entries.length;
|
||||
this.entries.push(entry);
|
||||
return entry;
|
||||
};
|
||||
|
@ -121,24 +82,13 @@
|
|||
entriesRequired = true;
|
||||
}
|
||||
}, mgr.filteredEntries.length);
|
||||
var updateTableRows = function() {
|
||||
pageElement.forRange(function(i) {
|
||||
mgr.filteredEntries[i].updateTableRow();
|
||||
}, mgr.filteredEntries.length);
|
||||
};
|
||||
if(entriesRequired) {
|
||||
var pkgEntries = repoindex.pageManager.packageManager.relevantEntries();
|
||||
var useBasicPackageInfo = function(values) {
|
||||
if(Array.isArray(values)) {
|
||||
for(var i = 0; i < values.length; ++i) {
|
||||
var info = values[i];
|
||||
if(!info.error) {
|
||||
if(info.index >= 0 && info.index < pkgEntries.length) {
|
||||
var entry = pkgEntries[info.index];
|
||||
entry.applyBasicInfo(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
repoindex.pageManager.addError("Basic package info returned by the server is invalid.");
|
||||
}
|
||||
};
|
||||
repoindex.client.requestBasicPackagesInfo(packageSelection, useBasicPackageInfo);
|
||||
repoindex.client.requestBasicPackagesInfo(packageSelection, updateTableRows);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -170,80 +120,56 @@
|
|||
// check whether specified entry index is valid
|
||||
var entry = this.entryByIndex(entryIndex);
|
||||
if(entry) {
|
||||
var i = entry.info;
|
||||
// show properties in "Package info" box
|
||||
var setProperties = function() {
|
||||
// -> basic package info
|
||||
repoindex.setPackageNames("pkg_name", [i.name]);
|
||||
repoindex.setText("pkg_repo", repoindex.makeStr(i.repo));
|
||||
repoindex.setText("pkg_ver", repoindex.makeStr(i.ver));
|
||||
repoindex.setText("pkg_desc", repoindex.makeStr(i.desc));
|
||||
repoindex.setText("pkg_arch", repoindex.makeStr(i.arch));
|
||||
repoindex.setText("pkg_bdate", repoindex.makeStr(i.bdate));
|
||||
var basics = entry.info.basics ? entry.info.basics : {};
|
||||
repoindex.setPackageNames("pkg_name", [entry.name]);
|
||||
repoindex.setText("pkg_repo", repoindex.makeStr(entry.info.repo));
|
||||
repoindex.setText("pkg_ver", repoindex.makeStr(basics.ver));
|
||||
repoindex.setText("pkg_desc", repoindex.makeStr(basics.desc));
|
||||
repoindex.setText("pkg_arch", repoindex.makeStr(basics.arch));
|
||||
repoindex.setText("pkg_bdate", repoindex.makeStr(basics.bdate));
|
||||
// -> full package info
|
||||
if(i.url) {
|
||||
repoindex.setLink("pkg_url", i.url, i.url, window.open);
|
||||
var details = entry.info.details ? entry.info.details : {};
|
||||
if(details.url) {
|
||||
repoindex.setLink("pkg_url", details.url, details.url, window.open);
|
||||
} else {
|
||||
repoindex.setText("pkg_url", "unknown");
|
||||
}
|
||||
repoindex.setText("pkg_lic", repoindex.makeArray(i.lic));
|
||||
repoindex.setPackageNames("pkg_grp", repoindex.pack(i.grp), repoindex.Pages.Groups);
|
||||
repoindex.setPackageNames("pkg_prov", repoindex.pkgNamesFromDeps(i.prov));
|
||||
repoindex.setPackageNames("pkg_deps", repoindex.pkgNamesFromDeps(i.deps));
|
||||
repoindex.setPackageNames("pkg_optd", repoindex.pkgNamesFromDeps(i.optd));
|
||||
repoindex.setPackageNames("pkg_requ", repoindex.pack(i.requ));
|
||||
repoindex.setPackageNames("pkg_conf", repoindex.pkgNamesFromDeps(i.conf));
|
||||
repoindex.setPackageNames("pkg_repl", repoindex.pkgNamesFromDeps(i.repl));
|
||||
repoindex.setText("pkg_isize", repoindex.makeDataSize(i.isize));
|
||||
repoindex.setText("pkg_pack", repoindex.makeStr(i.pack));
|
||||
repoindex.setText("pkg_idate", repoindex.makeStr(i.idate));
|
||||
repoindex.setText("pkg_expl", i.repo === "local" ? (i.expl ? "explicitly installed" : "installed as dependency") : "-");
|
||||
repoindex.setText("pkg_scri", repoindex.makeBool(i.scri));
|
||||
repoindex.setText("pkg_sig", repoindex.makeArray(i.sig));
|
||||
repoindex.setTree("pkg_files", repoindex.makeTree(i.files));
|
||||
repoindex.setText("pkg_lic", repoindex.makeArray(details.lic));
|
||||
repoindex.setPackageNames("pkg_grp", repoindex.pack(details.grp), repoindex.Pages.Groups);
|
||||
repoindex.setPackageNames("pkg_prov", repoindex.pkgNamesFromDeps(details.prov));
|
||||
repoindex.setPackageNames("pkg_deps", repoindex.pkgNamesFromDeps(details.deps));
|
||||
repoindex.setPackageNames("pkg_optd", repoindex.pkgNamesFromDeps(details.optd));
|
||||
repoindex.setPackageNames("pkg_requ", repoindex.pack(details.requ));
|
||||
repoindex.setPackageNames("pkg_conf", repoindex.pkgNamesFromDeps(details.conf));
|
||||
repoindex.setPackageNames("pkg_repl", repoindex.pkgNamesFromDeps(details.repl));
|
||||
repoindex.setText("pkg_isize", repoindex.makeDataSize(details.isize));
|
||||
repoindex.setText("pkg_pack", repoindex.makeStr(details.pack));
|
||||
repoindex.setText("pkg_idate", repoindex.makeStr(details.idate));
|
||||
repoindex.setText("pkg_expl", entry.info.repo === "local" ? (details.expl ? "explicitly installed" : "installed as dependency") : "n/a");
|
||||
repoindex.setText("pkg_scri", repoindex.makeBool(details.scri));
|
||||
repoindex.setText("pkg_sig", repoindex.makeArray(details.sig));
|
||||
repoindex.setTree("pkg_files", repoindex.makeTree(details.files));
|
||||
// -> upgrade download buttons
|
||||
var downloadPkgParams = {repo: i.repo, pkg: i.name, down: "pkg"};
|
||||
var downloadPkgParams = {repo: entry.info.repo, pkg: entry.name, down: "pkg"};
|
||||
repoindex.setDownloadButton("pkg_down", "package", repoindex.makeHash(repoindex.Pages.Packages, downloadPkgParams, true), function() {
|
||||
repoindex.pageManager.denoteHash(repoindex.Pages.Packages, downloadPkgParams);
|
||||
repoindex.pageManager.packageManager.showMirrorsForIndex(entryIndex);
|
||||
});
|
||||
var downloadSrcParams = {repo: i.repo, pkg: i.name, down: "src"};
|
||||
var downloadSrcParams = {repo: entry.info.repo, pkg: entry.name, down: "src"};
|
||||
repoindex.setDownloadButton("src_down", "source", repoindex.makeHash(repoindex.Pages.Packages, downloadSrcParams, true));
|
||||
};
|
||||
setProperties();
|
||||
// use full package info (callback)
|
||||
var pkgEntries = this.relevantEntries();
|
||||
var useFullPackageInfo = function(values) {
|
||||
// apply full info for all entries
|
||||
for(var i = 0; i < values.length; ++i) {
|
||||
var info = values[i];
|
||||
if(!info.error) {
|
||||
if(info.index >= 0 && info.index < pkgEntries.length) {
|
||||
pkgEntries[info.index].applyFullInfo(info);
|
||||
}
|
||||
// set properties (again) to actually show applied info
|
||||
setProperties();
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
if(!i.full) {
|
||||
if(!entry.info.basics || !entry.info.details) {
|
||||
// don't have the full package info yet -> request full package info
|
||||
var packageSelection = {};
|
||||
packageSelection[i.repo] = [{index: entryIndex, name: i.name}];
|
||||
repoindex.client.requestFullPackagesInfo(packageSelection, useFullPackageInfo);
|
||||
packageSelection[entry.info.repo] = [{index: entryIndex, name: entry.name}];
|
||||
repoindex.client.requestFullPackagesInfo(packageSelection, setProperties);
|
||||
}
|
||||
// set currentInfo (the pageManager needs this value to upgrade the hash)
|
||||
this.currentInfo = i;
|
||||
this.currentInfo = entry.info;
|
||||
// ensures, that the "Package Info" box (with the properties just set) is shown
|
||||
repoindex.pageManager.showPackageInfo(true);
|
||||
}
|
||||
|
@ -252,23 +178,22 @@
|
|||
this.showMirrors = function(repo, name) {
|
||||
var determineEntry = function() {
|
||||
var res = repoindex.pageManager.packageManager.entries.filter(function(entry) {
|
||||
return entry.info.repo === repo && entry.info.name === name;
|
||||
return entry.info.repo === repo && entry.name === name;
|
||||
});
|
||||
// entry exists?
|
||||
if(res.length > 0) {
|
||||
// yes -> full package info available?
|
||||
var i = res[0].info;
|
||||
var entry = res[0];
|
||||
var showEntry = function() {
|
||||
repoindex.pageManager.packageManager.showMirrorsForIndex(i.index);
|
||||
repoindex.pageManager.packageManager.showMirrorsForIndex(entry.index);
|
||||
};
|
||||
if(i.full) {
|
||||
if(entry.info.details) {
|
||||
// yes -> show entry instantly
|
||||
showEntry();
|
||||
} else {
|
||||
// no -> request full info, use callback to show entry when info becomes available
|
||||
//repoindex.client.requestFullPackagesInfo([{index: i.index, repo: i.repo, name: i.name}], showEntry());
|
||||
var packageSelection = {};
|
||||
packageSelection[i.repo] = [{index: entryIndex, name: i.name}];
|
||||
packageSelection[entry.info.repo] = [{index: entry.index, name: entry.name}];
|
||||
repoindex.client.requestFullPackagesInfo(packageSelection, showEntry);
|
||||
}
|
||||
} else {
|
||||
|
@ -290,11 +215,11 @@
|
|||
var entry = this.entryByIndex(entryIndex);
|
||||
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(entry.name) + "</i>", true);
|
||||
var listMirrorSelection = document.getElementById("list_mirror_selection");
|
||||
listMirrorSelection.wipeChildren();
|
||||
var repoEntries = repoindex.pageManager.repoManager.entries.filter(function(entry) {
|
||||
return entry.info.name === info.repo;
|
||||
return entry.name === info.repo;
|
||||
});
|
||||
var mirrorsAvailable = 0;
|
||||
if(repoEntries.length > 0) {
|
||||
|
@ -303,7 +228,7 @@
|
|||
for(var i = 0; i < mirrors.length; ++i) {
|
||||
var liElement = document.createElement("li");
|
||||
var aElement = document.createElement("a");
|
||||
var url = mirrors[i] + "/" + info.file;
|
||||
var url = mirrors[i] + "/" + info.details.file;
|
||||
aElement.appendChild(document.createTextNode(url));
|
||||
aElement.href = url;
|
||||
aElement.onclick = function() {
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
switch(pageName) {
|
||||
case repoindex.Pages.Packages:
|
||||
this.repoManager.buttonRow.style.display = "block";
|
||||
this.packageManager.upgrade();
|
||||
this.packageManager.update();
|
||||
if(params && params.repo && params.pkg) {
|
||||
if(params.down) {
|
||||
switch(params.down) {
|
||||
|
@ -149,7 +149,7 @@
|
|||
if(!repoindex.client.hasGroupInfo) {
|
||||
repoindex.client.requestGroupInfo();
|
||||
}
|
||||
this.groupManager.upgrade();
|
||||
this.groupManager.update();
|
||||
break;
|
||||
case repoindex.Pages.Repositories:
|
||||
this.repoManager.buttonRow.style.display = "none";
|
||||
|
@ -243,6 +243,9 @@
|
|||
this.currentManager.filterNameExact = exact;
|
||||
this.currentManager.filterDescr = searchTerm ? (exact ? "with the name" : "for the search term") : undefined;
|
||||
this.currentManager.invalidate(true);
|
||||
if(searchTerm && !this.currentManager.customSelection && this.repoManager.entryByName("AUR").enabled) {
|
||||
repoindex.client.requestSuggestions(["AUR"], searchTerm);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -93,9 +93,9 @@
|
|||
// provide a select function for the page element (will be called when the page element
|
||||
// is clicked)
|
||||
pageElement.select = function() {
|
||||
// upgrade active/inactive status and visibility of all page elements
|
||||
// update active/inactive status and visibility of all page elements
|
||||
var pagination = this.pagination;
|
||||
var upgradeVisibility = function(index, visible) {
|
||||
var updateVisibility = function(index, visible) {
|
||||
var lowest = 0;
|
||||
var highest = pagination.elements.length - 1;
|
||||
var low = index - pagination.visibleElementsBeforeAfter;
|
||||
|
@ -112,13 +112,13 @@
|
|||
}
|
||||
}
|
||||
if(pagination.currentElement) {
|
||||
upgradeVisibility(pagination.currentElement.pageIndex, false);
|
||||
updateVisibility(pagination.currentElement.pageIndex, false);
|
||||
pagination.currentElement.setActive(false);
|
||||
}
|
||||
upgradeVisibility(this.pageIndex, true);
|
||||
updateVisibility(this.pageIndex, true);
|
||||
this.setActive(true);
|
||||
|
||||
// upgrade status of the containing pagination object
|
||||
// update status of the containing pagination object
|
||||
pagination.currentElement = this;
|
||||
pagination.previousElement.setEnabled(this !== pagination.elements.first());
|
||||
pagination.nextElement.setEnabled(this !== pagination.elements.last());
|
||||
|
@ -186,8 +186,8 @@
|
|||
this.currentElement = undefined;
|
||||
};
|
||||
|
||||
// provide a function to upgrade the pagination (after properties such as the entryCount have been changed)
|
||||
this.upgrade = function() {
|
||||
// provide a function to update the pagination (after properties such as the entryCount have been changed)
|
||||
this.update = function() {
|
||||
var requiredPages = Math.ceil(this.entryCount / this.entriesPerPage);
|
||||
var currentPages = this.elements.length;
|
||||
if(requiredPages < currentPages) {
|
||||
|
|
|
@ -5,20 +5,20 @@
|
|||
RepoEntry.prototype.constructor = RepoEntry;
|
||||
RepoEntry = function(repoName, repoInfo, enabled) {
|
||||
if(enabled === undefined) {
|
||||
enabled = !repoInfo.requestRequired;
|
||||
// per default enable all repos with a fix number of packages
|
||||
enabled = repoInfo.packageCount;
|
||||
}
|
||||
repoindex.Entry.prototype.constructor.call(this, repoName, repoInfo, enabled);
|
||||
|
||||
this.info.currentServer = 0;
|
||||
|
||||
this.rowElement.onclick = function() {
|
||||
repoindex.pageManager.repoManager.showRepoInfoForIndex(this.entry.info.index);
|
||||
repoindex.pageManager.repoManager.showRepoInfoForIndex(this.entry.index);
|
||||
};
|
||||
|
||||
this.initTableRow = function() {
|
||||
this.rowElement.addCell(this.info.name);
|
||||
this.rowElement.addCell(this.name);
|
||||
this.rowElement.addCell(this.info.desc);
|
||||
//this.rowElement.addCell(this.info.servers && this.info.currentServer < this.info.servers.length ? this.info.servers[this.info.currentServer] : "none");
|
||||
};
|
||||
this.initTableRow();
|
||||
|
||||
|
@ -31,23 +31,23 @@
|
|||
this.link.repo = this;
|
||||
this.link.onclick = function() {
|
||||
if(repoindex.pageManager.repoManager.buttonContainerExclusiveButton.checked) {
|
||||
repoindex.pageManager.repoManager.upgradeEnabledAll(false);
|
||||
repoindex.pageManager.repoManager.updateEnabledAll(false);
|
||||
}
|
||||
this.repo.toggleEnabled();
|
||||
return false;
|
||||
};
|
||||
this.link.appendChild(document.createTextNode(repoInfo.name));
|
||||
this.link.appendChild(document.createTextNode(repoName));
|
||||
this.link.title = repoInfo.desc;
|
||||
|
||||
// use Bootstrap tooltip
|
||||
this.link.setAttribute("data-placement", "bottom");
|
||||
$(this.link).tooltip();
|
||||
|
||||
if(!repoInfo.requestRequired) {
|
||||
if(repoInfo.packageCount) {
|
||||
// create badge with package count
|
||||
var span = document.createElement("span");
|
||||
span.className = "badge";
|
||||
span.appendChild(document.createTextNode(repoInfo.packages.length));
|
||||
span.appendChild(document.createTextNode(repoInfo.packageCount));
|
||||
this.link.appendChild(document.createTextNode(" "));
|
||||
this.link.appendChild(span);
|
||||
}
|
||||
|
@ -65,15 +65,17 @@
|
|||
|
||||
|
||||
// provide a function to toggle enabled/disabled
|
||||
this.upgradeEnabled = function(enabled) {
|
||||
this.updateEnabled = function(enabled, noNotify) {
|
||||
if(this.enabled !== enabled) {
|
||||
this.link.className = (this.enabled = enabled) ? "btn btn-primary" : "btn btn-default";
|
||||
this.statusChanged(this);
|
||||
if(!noNotify) {
|
||||
this.statusChanged(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.toggleEnabled = function() {
|
||||
this.upgradeEnabled(!this.enabled);
|
||||
this.updateEnabled(!this.enabled);
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -98,7 +100,7 @@
|
|||
var repoFilter = [];
|
||||
for(var i = 0, end = repoEntries.length; i < end; ++i) {
|
||||
if(repoEntries[i].enabled) {
|
||||
repoFilter.push(repoEntries[i].info.name);
|
||||
repoFilter.push(repoEntries[i].name);
|
||||
}
|
||||
}
|
||||
pageMgr.packageManager.filterRepos = pageMgr.groupManager.filterRepos = repoFilter;
|
||||
|
@ -107,12 +109,12 @@
|
|||
};
|
||||
|
||||
// provide a function to add repo entries
|
||||
this.addEntry = function(repoInfo) {
|
||||
var entry = new RepoEntry(repoInfo);
|
||||
this.addEntry = function(repoName, repoInfo) {
|
||||
var entry = new RepoEntry(repoName, repoInfo);
|
||||
entry.statusChanged = this.applyRepoStatusChange;
|
||||
entry.pageManager = this;
|
||||
entry.repoEntryManager = this;
|
||||
entry.info.index = this.entries.length;
|
||||
entry.index = this.entries.length;
|
||||
this.entries.push(entry);
|
||||
return entry;
|
||||
};
|
||||
|
@ -125,9 +127,12 @@
|
|||
this.baseRemoveEntries();
|
||||
};
|
||||
|
||||
this.upgradeEnabledAll = function(enabled) {
|
||||
this.updateEnabledAll = function(enabled, noNotify) {
|
||||
for(var i = 0; i < this.entries.length; ++i) {
|
||||
this.entries[i].upgradeEnabled(enabled);
|
||||
this.entries[i].updateEnabled(enabled, true);
|
||||
}
|
||||
if(!noNotify) {
|
||||
this.applyRepoStatusChange();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -151,12 +156,12 @@
|
|||
this.showRepoInfo = function(repo) {
|
||||
var determineEntry = function() {
|
||||
var res = repoindex.pageManager.repoManager.entries.filter(function(entry) {
|
||||
return entry.info.name === repo;
|
||||
return entry.name === repo;
|
||||
});
|
||||
// entry exists?
|
||||
if(res.length > 0) {
|
||||
// yes -> full package info available?
|
||||
repoindex.pageManager.repoManager.showRepoInfoForIndex(res[0].info.index);
|
||||
repoindex.pageManager.repoManager.showRepoInfoForIndex(res[0].index);
|
||||
} else {
|
||||
// no -> show error
|
||||
repoindex.pageManager.repoManager.showRepoNotFound(repo);
|
||||
|
@ -175,21 +180,21 @@
|
|||
this.showRepoInfoForIndex = function(entryIndex) {
|
||||
var entry = this.entryByIndex(entryIndex);
|
||||
if(entry) {
|
||||
var i = entry.info;
|
||||
repoindex.setText("repo_name", i.name);
|
||||
repoindex.setText("repo_desc", i.desc);
|
||||
repoindex.setText("repo_pkgcount", i.requestRequired ? "unknown" : i.packages.length);
|
||||
repoindex.setText("repo_usage", repoindex.makeArray(i.usage, ", "));
|
||||
repoindex.setText("repo_siglevel", repoindex.makeArray(i.sigLevel, ", "));
|
||||
repoindex.setText("repo_source_only", repoindex.makeBool(i.srcOnly));
|
||||
repoindex.setText("repo_upgrade_sources", repoindex.makeArray(i.upgradeSources, ", "));
|
||||
var invokeUpgradeLookupParams = {repo: i.name, invoke: "upgradelookup"};
|
||||
var info = entry.info;
|
||||
repoindex.setText("repo_name", entry.name);
|
||||
repoindex.setText("repo_desc", info.desc);
|
||||
repoindex.setText("repo_pkgcount", repoindex.makeStr(info.packageCount));
|
||||
repoindex.setText("repo_usage", repoindex.makeArray(info.usage, ", "));
|
||||
repoindex.setText("repo_siglevel", repoindex.makeArray(info.sigLevel, ", "));
|
||||
repoindex.setText("repo_source_only", repoindex.makeBool(info.srcOnly));
|
||||
repoindex.setText("repo_upgrade_sources", repoindex.makeArray(info.upgradeSources, ", "));
|
||||
var invokeUpgradeLookupParams = {repo: entry.name, invoke: "upgradelookup"};
|
||||
repoindex.setDownloadButton("repo_checkforupgrades", "check for upgrades", repoindex.makeHash(repoindex.Pages.Repositories, invokeUpgradeLookupParams, true), function() {
|
||||
repoindex.pageManager.repoManager.showAvailableUpgrades(i.name);
|
||||
repoindex.pageManager.repoManager.showAvailableUpgrades(entry.name);
|
||||
repoindex.pageManager.denoteHash(repoindex.Pages.Repositories, invokeUpgradeLookupParams);
|
||||
}, "refresh");
|
||||
// set currentInfo (the pageManager needs this value to upgrade the hash)
|
||||
this.currentInfo = i;
|
||||
this.currentInfo = info;
|
||||
// ensures, that the "Package Info" box (with the properties just set) is shown
|
||||
repoindex.pageManager.showRepoInfo();
|
||||
}
|
||||
|
@ -250,21 +255,21 @@
|
|||
// iterate through all kinds of "upgrades" declared above
|
||||
for(var i2 = 0; i2 < upgrades[i1].entries.length; ++i2) {
|
||||
// iterate through all entries which have been assigned to the current upgrade type
|
||||
var newEntry = pkgMgr.createCustomEntry(upgrades[i1].color);
|
||||
newEntry.info.index = upgradeEntries.length;
|
||||
if(upgrades[i1].entries[i2].pkg) {
|
||||
newEntry.applyBasicInfo(upgrades[i1].entries[i2].pkg, true);
|
||||
if(upgrades[i1].entries[i2].curVer) {
|
||||
// add current version to upgrade version
|
||||
newEntry.info.ver = upgrades[i1].entries[i2].curVer + " → " + (newEntry.info.ver ? newEntry.info.ver : "?");
|
||||
}
|
||||
var upgradeEntry = upgrades[i1].entries[i2];
|
||||
if(upgradeEntry.pkg) {
|
||||
var packageInfo = repoindex.client.getPackageInfo(upgradeEntry.repo, upgradeEntry.name);
|
||||
packageInfo.basics = upgradeEntry.pkg;
|
||||
// find associated repo entry
|
||||
if((newEntry.repoEntry = repoMgr.entryByName(newEntry.info.repo))) {
|
||||
newEntry.repoEntry.upgradeEnabled(true); // ensure repo is enabled
|
||||
var repoEntry;
|
||||
if((repoEntry = repoMgr.entryByName(packageInfo.repo))) {
|
||||
repoEntry.updateEnabled(true); // ensure repo is enabled
|
||||
}
|
||||
newEntry.upgradeTableRow();
|
||||
var newEntry = pkgMgr.createCustomEntry(repoEntry, upgradeEntry.name, packageInfo, upgrades[i1].color);
|
||||
newEntry.curVer = upgradeEntry.curVer;
|
||||
newEntry.index = upgradeEntries.length;
|
||||
newEntry.updateTableRow();
|
||||
} else {
|
||||
newEntry.applyBasicInfo(upgrades[i1].entries[i2]);
|
||||
repoindex.pageManager.addError("Upgrade entry replied by server does not include package info.");
|
||||
}
|
||||
upgradeEntries.push(newEntry);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue