This commit is contained in:
Martchus 2015-09-27 19:29:45 +02:00
parent 715633c96e
commit a48a6fd656
20 changed files with 405 additions and 167 deletions

View File

@ -16,25 +16,11 @@ namespace RepoIndex {
/*!
* \brief Creates a new instance from the specified "AurJson value".
*/
AurPackage::AurPackage(const QJsonValue &aurJsonValue, UserRepository *repository) :
AurPackage::AurPackage(const QJsonObject &aurJsonObject, UserRepository *repository) :
Package(QString(), repository)
{
m_origin = PackageOrigin::Aur;
QJsonObject obj = aurJsonValue.toObject();
m_name = obj.value(QStringLiteral("Name")).toString();
m_hasGeneralInfo = true;
m_id = obj.value(QStringLiteral("ID")).toInt(-1);
m_categoryId = obj.value(QStringLiteral("CategoryID")).toInt(-1);
m_version = obj.value(QStringLiteral("Version")).toString();
m_description = obj.value(QStringLiteral("Description")).toString();
m_upstreamUrl = obj.value(QStringLiteral("URL")).toString();
m_votes = obj.value(QStringLiteral("NumVotes")).toInt(0);
m_outOfDate = DateTime::fromTimeStamp(obj.value(QStringLiteral("OutOfDate")).toInt());
m_maintainer = obj.value(QStringLiteral("Maintainer")).toString();
m_firstSubmitted = DateTime::fromTimeStamp(obj.value(QStringLiteral("FirstSubmitted")).toInt());
m_lastModified = DateTime::fromTimeStamp(obj.value(QStringLiteral("LastModified")).toInt());
m_licenses << obj.value(QStringLiteral("License")).toString();
m_tarUrl = obj.value(QStringLiteral("URLPath")).toString();
putJson(aurJsonObject);
}
/*!
@ -52,5 +38,24 @@ AurPackage::AurPackage(UserRepository *repository) :
Package(QString(), repository)
{}
void AurPackage::putJson(const QJsonObject &aurJsonObject)
{
m_name = aurJsonObject.value(QStringLiteral("Name")).toString();
m_hasGeneralInfo = true;
m_id = aurJsonObject.value(QStringLiteral("ID")).toInt(-1);
m_categoryId = aurJsonObject.value(QStringLiteral("CategoryID")).toInt(-1);
m_version = aurJsonObject.value(QStringLiteral("Version")).toString();
m_description = aurJsonObject.value(QStringLiteral("Description")).toString();
m_upstreamUrl = aurJsonObject.value(QStringLiteral("URL")).toString();
m_votes = aurJsonObject.value(QStringLiteral("NumVotes")).toInt(0);
m_outOfDate = DateTime::fromTimeStamp(aurJsonObject.value(QStringLiteral("OutOfDate")).toInt());
m_maintainer = aurJsonObject.value(QStringLiteral("Maintainer")).toString();
m_firstSubmitted = DateTime::fromTimeStamp(aurJsonObject.value(QStringLiteral("FirstSubmitted")).toInt());
m_lastModified = DateTime::fromTimeStamp(aurJsonObject.value(QStringLiteral("LastModified")).toInt());
m_licenses.clear();
m_licenses << aurJsonObject.value(QStringLiteral("License")).toString();
m_tarUrl = aurJsonObject.value(QStringLiteral("URLPath")).toString();
}
} // namespace PackageManagement

View File

@ -10,9 +10,11 @@ class UserRepository;
class AurPackage : public Package
{
public:
explicit AurPackage(const QJsonValue &aurJsonValue, UserRepository *repository);
explicit AurPackage(const QJsonObject &aurJsonObject, UserRepository *repository);
explicit AurPackage(const QString &name, UserRepository *repository);
explicit AurPackage(UserRepository *repository);
void putJson(const QJsonObject &aurJsonObject);
};
} // namespace PackageManagement

View File

@ -594,6 +594,8 @@ const QJsonObject &Manager::basicRepoInfo() const
/*!
* \brief Returns package information for the specified selection of packages.
* \remarks Does not request any information and hence will only return information
* which does not need to be requested or has been requested yet.
*/
const QJsonArray Manager::packageInfo(const QJsonObject &pkgSelection, PackageInfoPart part) const
{

View File

@ -140,13 +140,15 @@ struct RelevantFile
data(file->data()),
fileType(type),
arch(arch),
subDir(subDir)
subDir(subDir),
symlinkTarget(file->symLinkTarget())
{}
QString name;
QByteArray data;
RelevantFileType fileType;
RelevantFileArch arch;
QString subDir;
QString symlinkTarget;
};
struct PkgFileInfo
@ -341,30 +343,43 @@ void makeArchive(const list<PkgFileInfo> &pkgFiles, const QByteArray &pkgList, c
for(const auto &pkgFile : pkgFiles) {
for(const RelevantFile &relevantFile : pkgFile.relevantFiles) {
if(relevantFile.arch == RelevantFileArch::Any || relevantFile.arch == arch) {
QString path;
mode_t mode;
switch(relevantFile.fileType) {
case RelevantFileType::Binary:
targetArchive->writeFile(root % QStringLiteral("/bin/") % relevantFile.name, relevantFile.data, 0100755);
path = root % QStringLiteral("/bin/") % relevantFile.name;
mode = 0100755;
break;
case RelevantFileType::Translation:
targetArchive->writeFile(root % QStringLiteral("/share/") % pkgFile.name % QStringLiteral("/translations/") % relevantFile.name, relevantFile.data, 0100644);
path = root % QStringLiteral("/share/") % pkgFile.name % QStringLiteral("/translations/") % relevantFile.name;
mode = 0100644;
break;
case RelevantFileType::QtTranslation:
targetArchive->writeFile(root % QStringLiteral("/share/qt/translations/") % relevantFile.name, relevantFile.data, 0100644);
path = root % QStringLiteral("/share/qt/translations/") % relevantFile.name;
mode = 0100644;
break;
case RelevantFileType::QtPlugin:
targetArchive->writeFile(root % QStringLiteral("/bin/") % relevantFile.subDir % QChar('/') % relevantFile.name, relevantFile.data, 0100755);
path = root % QStringLiteral("/bin/") % relevantFile.subDir % QChar('/') % relevantFile.name;
mode = 0100755;
break;
case RelevantFileType::IconTheme:
targetArchive->writeFile(root % QStringLiteral("/share/icons/") % relevantFile.subDir % QChar('/') % relevantFile.name, relevantFile.data, 0100644);
path = root % QStringLiteral("/share/icons/") % relevantFile.subDir % QChar('/') % relevantFile.name;
mode = 0100644;
break;
case RelevantFileType::ConfigFile:
if(relevantFile.subDir.isEmpty()) {
targetArchive->writeFile(root % QStringLiteral("/share/") % pkgFile.name % QChar('/') % relevantFile.name, relevantFile.data, 0100644);
path = root % QStringLiteral("/share/") % pkgFile.name % QChar('/') % relevantFile.name;
} else {
targetArchive->writeFile(root % QStringLiteral("/share/") % pkgFile.name % QChar('/') % relevantFile.subDir % QChar('/') % relevantFile.name, relevantFile.data, 0100644);
path = root % QStringLiteral("/share/") % pkgFile.name % QChar('/') % relevantFile.subDir % QChar('/') % relevantFile.name;
}
mode = 0100644;
break;
}
if(relevantFile.symlinkTarget.isEmpty()) {
targetArchive->writeFile(path, relevantFile.data, mode);
} else {
targetArchive->writeSymLink(path, relevantFile.symlinkTarget, QString(), QString(), mode);
}
}
}
}

View File

@ -175,31 +175,8 @@ inline void put(QJsonObject &obj, const QString &key, const QStringList &values)
void put(QJsonObject &obj, const QString &key, const QList<Dependency> &dependencies)
{
QJsonArray jsonArray;
for(const auto &dep : dependencies) {
QJsonObject depObj;
depObj.insert(QStringLiteral("name"), dep.name);
depObj.insert(QStringLiteral("ver"), dep.version);
switch(dep.mode) {
case ALPM_DEP_MOD_ANY:
depObj.insert(QStringLiteral("mod"), QStringLiteral("any"));
break;
case ALPM_DEP_MOD_EQ:
depObj.insert(QStringLiteral("mod"), QStringLiteral("eq"));
break;
case ALPM_DEP_MOD_GE:
depObj.insert(QStringLiteral("mod"), QStringLiteral("ge"));
break;
case ALPM_DEP_MOD_LE:
depObj.insert(QStringLiteral("mod"), QStringLiteral("le"));
break;
case ALPM_DEP_MOD_GT:
depObj.insert(QStringLiteral("mod"), QStringLiteral("gt"));
break;
case ALPM_DEP_MOD_LT:
depObj.insert(QStringLiteral("mod"), QStringLiteral("lt"));
break;
}
jsonArray << depObj;
for(const auto &dependency : dependencies) {
jsonArray << dependency.toJson();
}
put(obj, key, jsonArray);
}
@ -560,8 +537,8 @@ PackageVersionPartComparsion PackageVersion::compareParts(const QString &part1,
// determine current segments
part1End = part1.indexOf(nonAlphanumericPattern, part1Pos);
part2End = part2.indexOf(nonAlphanumericPattern, part2Pos);
auto segment1 = part1.midRef(part1Pos, part1End);
auto segment2 = part2.midRef(part2Pos, part2End);
auto segment1 = part1.midRef(part1Pos, part1End >= 0 ? part1End - part1Pos : -1);
auto segment2 = part2.midRef(part2Pos, part2End >= 0 ? part2End - part2Pos : -1);
// compare current segments
int digit1 = segment1.size();
int digit2 = segment2.size();
@ -638,39 +615,81 @@ PackageVersionComparsion PackageVersion::compare(const PackageVersion &other) co
*/
Dependency::Dependency(const QString &dependency)
{
int descrBeg = dependency.lastIndexOf(QChar(':'));
QStringRef actualDependency;
if(descrBeg > 0) {
description = dependency.midRef(descrBeg + 1).trimmed().toString();
actualDependency = dependency.midRef(0, descrBeg);
} else {
actualDependency = QStringRef(&dependency);
}
int suffixBeg;
if((suffixBeg = dependency.lastIndexOf(QLatin1String(">="))) > 0) {
if((suffixBeg = actualDependency.lastIndexOf(QLatin1String(">="))) > 0) {
mode = ALPM_DEP_MOD_GE;
} else if((suffixBeg = dependency.lastIndexOf(QLatin1String("<="))) > 0) {
} else if((suffixBeg = actualDependency.lastIndexOf(QLatin1String("<="))) > 0) {
mode = ALPM_DEP_MOD_LE;
} else if((suffixBeg = dependency.lastIndexOf(QChar('='))) > 0) {
} else if((suffixBeg = actualDependency.lastIndexOf(QChar('='))) > 0) {
mode = ALPM_DEP_MOD_EQ;
} else if((suffixBeg = dependency.lastIndexOf(QChar('<'))) > 0) {
} else if((suffixBeg = actualDependency.lastIndexOf(QChar('<'))) > 0) {
mode = ALPM_DEP_MOD_LT;
} else if((suffixBeg = dependency.lastIndexOf(QChar('>'))) > 0) {
} else if((suffixBeg = actualDependency.lastIndexOf(QChar('>'))) > 0) {
mode = ALPM_DEP_MOD_GT;
} else {
mode = ALPM_DEP_MOD_ANY;
}
switch(mode) {
case ALPM_DEP_MOD_ANY:
name = dependency;
name = actualDependency.toString();
break;
case ALPM_DEP_MOD_GE:
case ALPM_DEP_MOD_LE:
name = dependency.mid(0, suffixBeg);
version = dependency.mid(suffixBeg + 2);
name = actualDependency.mid(0, suffixBeg).toString();
version = actualDependency.mid(suffixBeg + 2).toString();
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);
name = actualDependency.mid(0, suffixBeg).toString();
version = actualDependency.mid(suffixBeg + 1).toString();
break;
default:
;
}
}
/*!
* \brief Returns a JSON object for the current instance.
*/
QJsonObject Dependency::toJson() const
{
QJsonObject obj;
obj.insert(QStringLiteral("name"), name);
obj.insert(QStringLiteral("ver"), version);
switch(mode) {
case ALPM_DEP_MOD_ANY:
obj.insert(QStringLiteral("mod"), QStringLiteral("any"));
break;
case ALPM_DEP_MOD_EQ:
obj.insert(QStringLiteral("mod"), QStringLiteral("eq"));
break;
case ALPM_DEP_MOD_GE:
obj.insert(QStringLiteral("mod"), QStringLiteral("ge"));
break;
case ALPM_DEP_MOD_LE:
obj.insert(QStringLiteral("mod"), QStringLiteral("le"));
break;
case ALPM_DEP_MOD_GT:
obj.insert(QStringLiteral("mod"), QStringLiteral("gt"));
break;
case ALPM_DEP_MOD_LT:
obj.insert(QStringLiteral("mod"), QStringLiteral("lt"));
break;
}
if(!description.isEmpty()) {
obj.insert(QStringLiteral("desc"), description);
}
return obj;
}
}

View File

@ -78,17 +78,22 @@ public:
class Dependency
{
public:
explicit Dependency(const QString &name, const QString &version, _alpm_depmod_t mode = ALPM_DEP_MOD_ANY);
explicit Dependency(const QString &name, const QString &version, _alpm_depmod_t mode = ALPM_DEP_MOD_ANY, const QString &description = QString());
explicit Dependency(const QString &dependency);
QJsonObject toJson() const;
QString name;
QString version;
_alpm_depmod_t mode;
QString description;
};
inline Dependency::Dependency(const QString &name, const QString &version, _alpm_depmod_t mode) :
inline Dependency::Dependency(const QString &name, const QString &version, _alpm_depmod_t mode, const QString &description) :
name(name),
version(version),
mode(mode)
mode(mode),
description(description)
{}
class Manager;

View File

@ -0,0 +1,52 @@
#include "./packageinfolookup.h"
#include "./repository.h"
namespace RepoIndex {
PackageInfoLookup::PackageInfoLookup(Manager &manager, const QJsonObject &packageSelection, Manager::PackageInfoPart part, QObject *parent) :
PackageLookup(parent)
{
if(part != Manager::None) {
for(auto i = packageSelection.constBegin(), end = packageSelection.constEnd(); i != end; ++i) {
if(auto *repo = manager.repositoryByName(i.key())) {
QStringList packagesToBeRequested;
for(const auto &entry : i.value().toArray()) {
const auto entryObj = entry.toObject();
const auto pkgName = entryObj.value(QStringLiteral("name")).toString();
if(!pkgName.isEmpty()) {
packagesToBeRequested << pkgName;
}
}
if(!packagesToBeRequested.isEmpty()) {
if(const auto *reply = (part & Manager::Details ? repo->requestFullPackageInfo(packagesToBeRequested) : repo->requestPackageInfo(packagesToBeRequested))) {
connect(reply, &PackageReply::resultsAvailable, this, &PackageInfoLookup::addResults);
++m_remainingReplies;
} else {
// no need to request any of the packages
}
}
} else {
// specified repository can not be found
QJsonObject errorObj;
errorObj.insert(QStringLiteral("repo"), i.key());
errorObj.insert(QStringLiteral("error"), QStringLiteral("na"));
m_results << errorObj;
}
}
}
}
void PackageInfoLookup::addResults()
{
assert(m_remainingReplies);
auto *reply = static_cast<PackageReply *>(sender());
m_results << reply->;
reply->deleteLater();
if(!--m_remainingReplies) {
emit resultsAvailable(QStringLiteral("pkginfo"), m_id, m_results);
deleteLater();
}
}
} // namespace RepoIndex

24
alpm/packageinfolookup.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef REPOINDEX_PACKAGEINFOLOOKUP_H
#define REPOINDEX_PACKAGEINFOLOOKUP_H
#include "./packagelookup.h"
#include "./manager.h"
namespace RepoIndex {
class PackageInfoLookup : public PackageLookup
{
Q_OBJECT
public:
explicit PackageInfoLookup(Manager &manager, const QJsonObject &packageSelection, Manager::PackageInfoPart part, QObject *parent = nullptr);
private:
void addResults();
QList<Package *> m_packages;
};
} // namespace RepoIndex
#endif // REPOINDEX_PACKAGEINFOLOOKUP_H

4
alpm/packagelookup.cpp Normal file
View File

@ -0,0 +1,4 @@
#include "./packagelookup.h"

48
alpm/packagelookup.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef PACKAGELOOKUP_H
#define PACKAGELOOKUP_H
#include <QObject>
#include <QJsonArray>
#include <QJsonValue>
class PackageLookup : public QObject
{
Q_OBJECT
public:
explicit PackageLookup(QObject *parent = nullptr);
const QJsonArray &errors() const;
const QJsonArray &results() const;
bool finished() const;
signals:
void resultsAvailable(const QJsonValue &what, const QJsonValue &id, const QJsonValue &value);
protected:
unsigned int m_remainingReplies;
QJsonValue m_id;
QJsonArray m_errors;
QJsonArray m_results;
};
inline PackageLookup::PackageLookup(QObject *parent) :
QObject(parent),
m_remainingReplies(0)
{}
inline const QJsonArray &PackageLookup::errors() const
{
return m_errors;
}
inline const QJsonArray &PackageLookup::results() const
{
return m_results;
}
inline bool PackageLookup::finished() const
{
return !m_remainingReplies && m_errors.isEmpty();
}
#endif // PACKAGELOOKUP_H

View File

@ -60,7 +60,7 @@ const QStringList RepoIndex::Repository::packageNames() const
* \returns Returns a reply object used for the request. The reply must be destroyed by the caller
* using destroyLater() after resultsAvailable() has been emitted.
*/
SuggestionsReply *Repository::requestSuggestions(const QString &) const
SuggestionsReply *Repository::requestSuggestions(const QString &)
{
return nullptr;
}
@ -114,7 +114,7 @@ PackageDetailAvailability Repository::requestsRequired(PackageDetail ) const
* requested again. If it turns out, that all packages are already cached, nullptr
* is returned in this case.
*/
PackageReply *Repository::requestPackageInfo(const QStringList &, bool ) const
PackageReply *Repository::requestPackageInfo(const QStringList &, bool )
{
return nullptr;
}
@ -129,7 +129,7 @@ PackageReply *Repository::requestPackageInfo(const QStringList &, bool ) const
* requested again. If it turns out, that all packages are already cached, nullptr
* is returned in this case.
*/
PackageReply *Repository::requestFullPackageInfo(const QStringList &, bool ) const
PackageReply *Repository::requestFullPackageInfo(const QStringList &, bool )
{
return nullptr;
}
@ -258,12 +258,17 @@ QFuture<void> Repository::computeRequiredBy(Manager &manager, bool forceUpdate)
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;
// 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;
// }
// }
for(const auto &pkgEntry : packages()) {
if(pkgEntry.first.compare(term, Qt::CaseInsensitive) == 0) {
suggestions << pkgEntry.first;
}
}
QJsonObject res;
@ -281,7 +286,7 @@ QJsonArray Repository::upgradeSourcesJsonArray() const
return sources;
}
void Repository::checkForUpgrades(UpgradeLookupResults &results, const QList<const Repository *> &upgradeSources) const
void Repository::checkForUpgrades(UpgradeLookupResults &results, const QList<Repository *> &upgradeSources) const
{
if(upgradeSources.isEmpty()) {
results.noSources = true;
@ -450,7 +455,7 @@ void Repository::restoreFromCacheStream(QDataStream &in)
in >> packageCount;
bool good = true;
for(quint32 i = 0; i < packageCount && good && in.status() == QDataStream::Ok; ++i) {
if(unique_ptr<Package> package = emptyPackage()) {
if(auto package = emptyPackage()) {
package->restoreFromCacheStream(in);
if(!package->name().isEmpty()) {
m_packages[package->name()] = move(package);
@ -514,8 +519,9 @@ void Repository::restoreSpecificCacheHeader(QDataStream &in)
/*!
* \brief Adds a package parsed from the specified \a srcInfo.
* \returns Returns the packages.
*/
void Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo)
QList<Package *> Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo)
{
enum {
FieldName,
@ -528,6 +534,7 @@ void Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo)
QString packageBase;
QList<QPair<QString, QString> > baseInfo;
QList<QPair<QString, QString> > packageInfo;
QList<Package *> packages;
Package *currentPackage = nullptr;
for(char c : srcInfo) {
switch(state) {
@ -538,9 +545,9 @@ void Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo)
state = EquationSign;
}
break;
case '\n': case '\r':
case '\n': case '\r': case '\t':
if(!currentFieldName.isEmpty()) {
// TODO: handle error - field name contains newline character
// TODO: handle error - field name contains invalid char character
}
break;
default:
@ -579,6 +586,7 @@ void Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo)
} else {
if(currentPackage) {
currentPackage->putInfo(baseInfo, packageInfo);
packages << currentPackage;
}
auto &pkg = m_packages[currentFieldValue];
if(!pkg) {
@ -604,7 +612,9 @@ void Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo)
}
if(currentPackage) {
currentPackage->putInfo(baseInfo, packageInfo);
packages << currentPackage;
}
return packages;
}

View File

@ -145,9 +145,9 @@ public:
// gathering data
virtual PackageDetailAvailability requestsRequired(PackageDetail packageDetail = PackageDetail::Basics) const;
virtual SuggestionsReply *requestSuggestions(const QString &phrase) const;
virtual PackageReply *requestPackageInfo(const QStringList &packageNames, bool forceUpdate = false) const;
virtual PackageReply *requestFullPackageInfo(const QStringList &package, bool forceUpdate = false) const;
virtual SuggestionsReply *requestSuggestions(const QString &phrase);
virtual PackageReply *requestPackageInfo(const QStringList &packageNames, bool forceUpdate = false);
virtual PackageReply *requestFullPackageInfo(const QStringList &packageNames, bool forceUpdate = false);
// package search
const Package *packageByName(const QString &name) const;
@ -160,11 +160,11 @@ public:
QJsonObject suggestions(const QString &term) const;
// upgrade lookup
const QList<const Repository *> &upgradeSources() const;
QList<const Repository *> &upgradeSources();
const QList<Repository *> &upgradeSources() const;
QList<Repository *> &upgradeSources();
QJsonArray upgradeSourcesJsonArray() const;
void checkForUpgrades(UpgradeLookupResults &results) const;
void checkForUpgrades(UpgradeLookupResults &results, const QList<const Repository *> &upgradeSources) const;
void checkForUpgrades(UpgradeLookupResults &results, const QList<Repository *> &upgradeSources) const;
// build system
const QString &sourcesDirectory() const;
@ -187,7 +187,7 @@ public:
virtual void restoreSpecificCacheHeader(QDataStream &in);
// parsing src/pkg info
void addPackagesFromSrcInfo(const QByteArray &srcInfo);
QList<Package *> addPackagesFromSrcInfo(const QByteArray &srcInfo);
static const uint32 invalidIndex = static_cast<uint32>(-1);
@ -203,7 +203,7 @@ protected:
std::map<QString, QList<Package *> > m_groups;
QStringList m_serverUrls;
alpm_siglevel_t m_sigLevel;
QList<const Repository *> m_upgradeSources;
QList<Repository *> m_upgradeSources;
QString m_srcDir;
QString m_pkgDir;
};
@ -331,12 +331,12 @@ inline alpm_siglevel_t Repository::sigLevel() const
return m_sigLevel;
}
inline const QList<const Repository *> &Repository::upgradeSources() const
inline const QList<Repository *> &Repository::upgradeSources() const
{
return m_upgradeSources;
}
inline QList<const Repository *> &Repository::upgradeSources()
inline QList<Repository *> &Repository::upgradeSources()
{
return m_upgradeSources;
}

View File

@ -9,8 +9,8 @@
namespace RepoIndex {
SuggestionsLookup::SuggestionsLookup(Manager &manager, const QJsonObject &request) :
m_remainingReplies(0)
SuggestionsLookup::SuggestionsLookup(Manager &manager, const QJsonObject &request, QObject *parent) :
PackageLookup(parent)
{
m_id = request.value(QStringLiteral("id"));
const auto searchTerm = request.value(QStringLiteral("term")).toString();
@ -23,7 +23,7 @@ SuggestionsLookup::SuggestionsLookup(Manager &manager, const QJsonObject &reques
}
if(m_errors.isEmpty()) {
for(const auto &repoName : repos) {
if(const Repository *repo = manager.repositoryByName(repoName.toString())) {
if(auto *repo = manager.repositoryByName(repoName.toString())) {
if(const auto *reply = repo->requestSuggestions(searchTerm)) {
connect(reply, &SuggestionsReply::resultsAvailable, this, &SuggestionsLookup::addResults);
++m_remainingReplies;

View File

@ -1,51 +1,22 @@
#ifndef REPOINDEX_SUGGESTIONSLOOKUP_H
#define REPOINDEX_SUGGESTIONSLOOKUP_H
#include <QObject>
#include <QJsonArray>
#include <QJsonValue>
#include "./packagelookup.h"
namespace RepoIndex {
class Manager;
class SuggestionsLookup : public QObject
class SuggestionsLookup : public PackageLookup
{
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);
SuggestionsLookup(Manager &manager, const QJsonObject &request, QObject *parent = nullptr);
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

View File

@ -23,7 +23,7 @@ using namespace Utilities;
/*!
* \brief Returns a JSON object for the current instance.
*/
QJsonObject UpgradeResult::json() const
QJsonObject UpgradeResult::toJson() const
{
QJsonObject obj;
obj.insert(QStringLiteral("name"), package->name());
@ -43,7 +43,7 @@ QJsonObject UpgradeResult::json() const
/*!
* \brief Constructs a new upgrade lookup process. The upgrade lookup process is started immediately.
*/
UpgradeLookupProcess::UpgradeLookupProcess(UpgradeLookup *upgradeLookup, const Repository *upgradeSource) :
UpgradeLookupProcess::UpgradeLookupProcess(UpgradeLookup *upgradeLookup, Repository *upgradeSource) :
QObject(upgradeLookup),
m_toCheck(upgradeLookup->toCheck()),
m_upgradeSource(upgradeSource),
@ -101,7 +101,7 @@ void UpgradeLookupProcess::sourceReady()
*/
void UpgradeLookupProcess::checkUpgrades()
{
m_toCheck->checkForUpgrades(m_results, QList<const Repository *>() << m_upgradeSource);
m_toCheck->checkForUpgrades(m_results, QList<Repository *>() << m_upgradeSource);
}
/*!
@ -165,7 +165,7 @@ UpgradeLookup::UpgradeLookup(QObject *parent) :
/*!
* \brief Constructs a new upgrade lookup for the specified \a request using the specified \a manager.
*/
UpgradeLookupJson::UpgradeLookupJson(const Manager &manager, const QJsonObject &request, QObject *parent) :
UpgradeLookupJson::UpgradeLookupJson(Manager &manager, const QJsonObject &request, QObject *parent) :
UpgradeLookup(parent),
m_request(request)
{
@ -174,14 +174,14 @@ UpgradeLookupJson::UpgradeLookupJson(const Manager &manager, const QJsonObject &
// construct upgrade lookup processes
const auto syncDbsArray = request.value(QStringLiteral("syncdbs")).toArray();
if(syncDbsArray.isEmpty()) {
for(const auto *src : m_toCheck->upgradeSources()) {
for(auto *src : m_toCheck->upgradeSources()) {
new UpgradeLookupProcess(this, src);
++m_remainingProcesses;
}
} else {
for(const auto &syncDbValue : syncDbsArray) {
const auto syncDbName = syncDbValue.toString();
if(const auto *src = manager.repositoryByName(syncDbName)) {
if(auto *src = manager.repositoryByName(syncDbName)) {
new UpgradeLookupProcess(this, src);
++m_remainingProcesses;
} else {
@ -207,13 +207,13 @@ void UpgradeLookupJson::processFinished()
// add results
const auto &results = static_cast<UpgradeLookupProcess *>(sender())->results();
for(const auto &res : results.newVersions) {
m_softwareUpgradesArray << res.json();
m_softwareUpgradesArray << res.toJson();
}
for(const auto &res : results.newReleases) {
m_packageOnlyUpgradesArray << res.json();
m_packageOnlyUpgradesArray << res.toJson();
}
for(const auto &res : results.downgrades) {
m_downgradesArray << res.json();
m_downgradesArray << res.toJson();
}
for(const auto &warning : results.warnings) {
m_warningsArray << warning;
@ -267,14 +267,14 @@ void UpgradeLookupJson::processFinished()
/*!
* \brief Constructs a new upgrade lookup for the specified \a db using the specified \a manager.
*/
UpgradeLookupCli::UpgradeLookupCli(const Manager &manager, const string &repo, QObject *parent) :
UpgradeLookupCli::UpgradeLookupCli(Manager &manager, const string &repo, QObject *parent) :
UpgradeLookup(parent)
{
cerr << shchar << "Checking upgrades for \"" << repo << "\" ..." << endl;
const auto toCheckName = qstr(repo);
if((m_toCheck = manager.repositoryByName(toCheckName))) {
// construct upgrade lookup processes
for(const auto *src : m_toCheck->upgradeSources()) {
for(auto *src : m_toCheck->upgradeSources()) {
new UpgradeLookupProcess(this, src);
++m_remainingProcesses;
}

View File

@ -21,7 +21,7 @@ public:
UpgradeResult(const Package *package, const QString &currentVersion);
const Package *package;
QString currentVersion;
QJsonObject json() const;
QJsonObject toJson() const;
};
/*!
@ -84,7 +84,7 @@ class UpgradeLookupProcess : public QObject
{
Q_OBJECT
public:
explicit UpgradeLookupProcess(UpgradeLookup *upgradeLookup, const Repository *upgradeSource);
explicit UpgradeLookupProcess(UpgradeLookup *upgradeLookup, Repository *upgradeSource);
const UpgradeLookupResults &results() const;
signals:
@ -96,7 +96,7 @@ private slots:
private:
const Repository *m_toCheck;
const Repository *m_upgradeSource;
Repository *m_upgradeSource;
PackageReply *m_reply;
QFutureWatcher<void> *m_watcher;
UpgradeLookupResults m_results;
@ -116,7 +116,7 @@ private slots:
protected:
explicit UpgradeLookup(QObject *parent = nullptr);
const Repository *m_toCheck;
Repository *m_toCheck;
unsigned int m_remainingProcesses;
bool m_firstFinished;
QSet<const Package *> m_orphanedPackages;
@ -134,7 +134,7 @@ class UpgradeLookupJson : public UpgradeLookup
{
Q_OBJECT
public:
explicit UpgradeLookupJson(const Manager &manager, const QJsonObject &request, QObject *parent = nullptr);
explicit UpgradeLookupJson(Manager &manager, const QJsonObject &request, QObject *parent = nullptr);
const QJsonArray &errors() const;
signals:
@ -163,7 +163,7 @@ class UpgradeLookupCli : public UpgradeLookup
Q_OBJECT
friend class UpgradeLookupProcess;
public:
explicit UpgradeLookupCli(const Manager &manager, const std::string &repo, QObject *parent = nullptr);
explicit UpgradeLookupCli(Manager &manager, const std::string &repo, QObject *parent = nullptr);
const Repository *toCheck() const;
private slots:

View File

@ -15,6 +15,11 @@
#include <iostream>
#include <algorithm>
// testing
#include "./alpm/aurpackage.h"
#include "./network/userrepository.h"
#include <QFile>
using namespace std;
using namespace ApplicationUtilities;
using namespace RepoIndex;
@ -58,6 +63,13 @@ int main(int argc, char *argv[])
manager.initAlpmDataBases(configArgs.serverArg.isPresent());
cerr << shchar << "Restoring cache ..." << endl;
manager.restoreCache();
//QFile file(QStringLiteral("/run/media/devel/dist/arch/dolphin-emu-git/.SRCINFO"));
//file.open(QFile::ReadOnly);
//manager.userRepository()->addPackagesFromSrcInfo(file.readAll());
//PackageVersion version(manager.databaseByName("ownstuff")->packageByName(QStringLiteral("ffmpeg-libfdk_aac"))->version());
//auto res = version.compare(PackageVersion(QStringLiteral("1:2.8-1")));
if(configArgs.serverArg.isPresent()) {
// setup the server
Server server(manager, manager.config());

View File

@ -5,6 +5,7 @@
#include <c++utilities/misc/memory.h>
#include <KTar>
#include <KArchiveFile>
#include <QStringBuilder>
#include <QUrlQuery>
@ -21,6 +22,7 @@ namespace RepoIndex {
const char *requestTypeProp = "type";
const QString rpcRequestTypeKey(QStringLiteral("type"));
const QString rpcRequestTypeSearch(QStringLiteral("search"));
const QString rpcRequestTypeSuggest(QStringLiteral("suggest"));
const QString rpcRequestTypeMultiInfo(QStringLiteral("multiinfo"));
const QString rpcArgKey(QStringLiteral("arg"));
@ -47,16 +49,22 @@ void AurPackageReply::processData()
const QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &error);
if(error.error == QJsonParseError::NoError) {
for(const auto &result : doc.object().value(QStringLiteral("results")).toArray()) {
auto package = make_unique<AurPackage>(result, m_userRepo);
if(!package->name().isEmpty()) {
m_packages[package->name()] = move(package);
QJsonObject obj = result.toObject();
QString packageName = obj.value(QStringLiteral("Name")).toString();
if(!packageName.isEmpty()) {
auto &package = m_packages[packageName];
if(package) {
static_cast<AurPackage *>(package.get())->putJson(obj);
} else {
package = make_unique<AurPackage>(obj, static_cast<UserRepository *>(m_userRepo));
}
}
}
} else {
m_error = QStringLiteral("Error: Unable to parse JSON received from AUR: ") % error.errorString() % QStringLiteral(" at character ") % QString::number(error.offset);
}
} else {
m_error = QStringLiteral("Error: Unable to request data from AUR: ") + reply->errorString();
m_error = QStringLiteral("Error: Unable to request data from AUR via AurJson: ") + reply->errorString();
}
emit resultsAvailable();
}
@ -68,8 +76,38 @@ AurFullPackageReply::AurFullPackageReply(const QList<QNetworkReply *> &networkRe
void AurFullPackageReply::processData()
{
//auto *reply = static_cast<QNetworkReply *>(sender());
// TODO
auto *reply = static_cast<QNetworkReply *>(sender());
if(reply->error() == QNetworkReply::NoError) {
KTar tar(reply);
if(tar.open(QIODevice::ReadOnly)) {
const auto *baseDir = tar.directory();
//const auto packageBase = baseDir->name();
const auto *srcInfoEntry = baseDir->entry(QStringLiteral(".SRCINFO"));
if(srcInfoEntry && srcInfoEntry->isFile()) {
const QByteArray srcInfo = static_cast<const KArchiveFile *>(srcInfoEntry)->data();
const auto packages = m_userRepo->addPackagesFromSrcInfo(srcInfo);
// TODO: error handling
for(const auto &entryName : baseDir->entries()) {
if(entryName != QLatin1String(".SRCINFO")) {
const auto *entry = baseDir->entry(entryName);
if(entry->isFile()) {
for(const auto *package : packages) {
// TODO: add source files
}
} else {
// don't think it is required to read sub directories recursively
}
}
}
} else {
m_error = QStringLiteral("Error: Aur tarball does not contain \".SRCINFO\".");
}
} else {
m_error = QStringLiteral("Error: Unable to open tarball reply.");
}
} else {
m_error = QStringLiteral("Error: Unable to request tarball from AUR: ") + reply->errorString();
}
}
AurSuggestionsReply::AurSuggestionsReply(QNetworkReply *networkReply, const QString &term, UserRepository *repo) :
@ -87,12 +125,27 @@ void AurSuggestionsReply::processData()
const QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &error);
if(error.error == QJsonParseError::NoError) {
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));
if(doc.isObject()) {
for(const auto &result : doc.object().value(QStringLiteral("results")).toArray()) {
QJsonObject obj = result.toObject();
QString packageName = obj.value(QStringLiteral("Name")).toString();
if(!packageName.isEmpty()) {
auto &package = packages[packageName];
if(package) {
static_cast<AurPackage *>(package.get())->putJson(obj);
} else {
package = make_unique<AurPackage>(obj, static_cast<UserRepository *>(m_repo));
}
}
}
} else if(doc.isArray()) {
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));
}
}
}
}
@ -131,27 +184,39 @@ PackageDetailAvailability UserRepository::requestsRequired(PackageDetail package
}
}
AurSuggestionsReply *UserRepository::requestSuggestions(const QString &term) const
AurSuggestionsReply *UserRepository::requestSuggestions(const QString &term)
{
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);
//for(auto i = packages().lower_bound(term), end = packages().cend(); i != end && remainingSuggestions && i->first.startsWith(term, Qt::CaseInsensitive); ++i, --remainingSuggestions);
for(const auto &pkgEntry : packages()) {
if(pkgEntry.first.compare(term, Qt::CaseInsensitive) == 0) {
if(!(--remainingSuggestions)) {
break;
}
}
}
if(remainingSuggestions) {
auto url = m_aurRpcUrl;
QUrlQuery query;
query.addQueryItem(rpcRequestTypeKey, rpcRequestTypeSuggest);
query.addQueryItem(rpcRequestTypeKey, term.size() < 3 ? rpcRequestTypeSuggest : rpcRequestTypeSearch);
query.addQueryItem(rpcArgKey, term);
url.setQuery(query);
return new AurSuggestionsReply(m_networkAccessManager.get(QNetworkRequest(url)), term, const_cast<UserRepository *>(this));
return new AurSuggestionsReply(m_networkAccessManager.get(QNetworkRequest(url)), term, this);
} else {
return nullptr;
}
}
AurPackageReply *UserRepository::requestPackageInfo(const QStringList &packageNames, bool forceUpdate) const
AurPackageReply *UserRepository::requestPackageInfo(const QStringList &packageNames, bool forceUpdate)
{
QUrlQuery query;
for(const auto &packageName : packageNames) {
if(forceUpdate || !m_packages.count(packageName)) {
try {
const auto &pkg = m_packages.at(packageName);
if(!pkg->hasGeneralInfo() || forceUpdate) {
query.addQueryItem(rpcArgArray, packageName);
}
} catch(const out_of_range &) {
query.addQueryItem(rpcArgArray, packageName);
}
}
@ -161,11 +226,11 @@ AurPackageReply *UserRepository::requestPackageInfo(const QStringList &packageNa
auto url = m_aurRpcUrl;
query.addQueryItem(rpcRequestTypeKey, rpcRequestTypeMultiInfo);
url.setQuery(query);
return new AurPackageReply(m_networkAccessManager.get(QNetworkRequest(url)), const_cast<UserRepository *>(this));
return new AurPackageReply(m_networkAccessManager.get(QNetworkRequest(url)), this);
}
}
AurFullPackageReply *UserRepository::requestFullPackageInfo(const QStringList &packageNames, bool forceUpdate) const
AurFullPackageReply *UserRepository::requestFullPackageInfo(const QStringList &packageNames, bool forceUpdate)
{
QList<QNetworkReply *> replies;
for(const auto &packageName : packageNames) {
@ -187,7 +252,7 @@ AurFullPackageReply *UserRepository::requestFullPackageInfo(const QStringList &p
if(replies.isEmpty()) {
return nullptr;
} else {
return new AurFullPackageReply(replies, const_cast<UserRepository *>(this));
return new AurFullPackageReply(replies, this);
}
}

View File

@ -65,9 +65,9 @@ public:
static void setAurRpcUrl(const QUrl &aurRpcUrl);
PackageDetailAvailability requestsRequired(PackageDetail packageDetail) 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;
AurSuggestionsReply *requestSuggestions(const QString &term);
AurPackageReply *requestPackageInfo(const QStringList &packageNames, bool forceUpdate = false);
AurFullPackageReply *requestFullPackageInfo(const QStringList &packageNames, bool forceUpdate = false);
protected:
std::unique_ptr<Package> emptyPackage();

View File

@ -34,7 +34,9 @@ SOURCES += main.cpp \
alpm/alpmdatabase.cpp \
alpm/repository.cpp \
alpm/upgradelookup.cpp \
alpm/suggestionslookup.cpp
alpm/suggestionslookup.cpp \
alpm/packageinfolookup.cpp \
alpm/packagelookup.cpp
HEADERS += \
alpm/manager.h \
@ -53,7 +55,9 @@ HEADERS += \
alpm/alpmdatabase.h \
alpm/repository.h \
alpm/upgradelookup.h \
alpm/suggestionslookup.h
alpm/suggestionslookup.h \
alpm/packageinfolookup.h \
alpm/packagelookup.h
DISTFILES += \
README.md \