From a48a6fd656aff42f47f4f0d7293c4db5c003a762 Mon Sep 17 00:00:00 2001 From: Martchus Date: Sun, 27 Sep 2015 19:29:45 +0200 Subject: [PATCH] update --- alpm/aurpackage.cpp | 37 +++++++------ alpm/aurpackage.h | 4 +- alpm/manager.cpp | 2 + alpm/mingwbundle.cpp | 31 ++++++++--- alpm/package.cpp | 93 +++++++++++++++++++------------- alpm/package.h | 11 ++-- alpm/packageinfolookup.cpp | 52 ++++++++++++++++++ alpm/packageinfolookup.h | 24 +++++++++ alpm/packagelookup.cpp | 4 ++ alpm/packagelookup.h | 48 +++++++++++++++++ alpm/repository.cpp | 38 ++++++++----- alpm/repository.h | 20 +++---- alpm/suggestionslookup.cpp | 6 +-- alpm/suggestionslookup.h | 35 ++---------- alpm/upgradelookup.cpp | 22 ++++---- alpm/upgradelookup.h | 12 ++--- main.cpp | 12 +++++ network/userrepository.cpp | 107 +++++++++++++++++++++++++++++-------- network/userrepository.h | 6 +-- repoindex.pro | 8 ++- 20 files changed, 405 insertions(+), 167 deletions(-) create mode 100644 alpm/packageinfolookup.cpp create mode 100644 alpm/packageinfolookup.h create mode 100644 alpm/packagelookup.cpp create mode 100644 alpm/packagelookup.h diff --git a/alpm/aurpackage.cpp b/alpm/aurpackage.cpp index 33ac23e..ed89138 100644 --- a/alpm/aurpackage.cpp +++ b/alpm/aurpackage.cpp @@ -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 diff --git a/alpm/aurpackage.h b/alpm/aurpackage.h index 20d56dd..2b694eb 100644 --- a/alpm/aurpackage.h +++ b/alpm/aurpackage.h @@ -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 diff --git a/alpm/manager.cpp b/alpm/manager.cpp index ce8c656..88e99a6 100644 --- a/alpm/manager.cpp +++ b/alpm/manager.cpp @@ -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 { diff --git a/alpm/mingwbundle.cpp b/alpm/mingwbundle.cpp index c5fef9d..25a4208 100644 --- a/alpm/mingwbundle.cpp +++ b/alpm/mingwbundle.cpp @@ -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 &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); + } } } } diff --git a/alpm/package.cpp b/alpm/package.cpp index 5db17eb..5ceacaf 100644 --- a/alpm/package.cpp +++ b/alpm/package.cpp @@ -175,31 +175,8 @@ inline void put(QJsonObject &obj, const QString &key, const QStringList &values) void put(QJsonObject &obj, const QString &key, const QList &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; +} + } diff --git a/alpm/package.h b/alpm/package.h index 6550bc5..a060835 100644 --- a/alpm/package.h +++ b/alpm/package.h @@ -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; diff --git a/alpm/packageinfolookup.cpp b/alpm/packageinfolookup.cpp new file mode 100644 index 0000000..854ded2 --- /dev/null +++ b/alpm/packageinfolookup.cpp @@ -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(sender()); + m_results << reply->; + reply->deleteLater(); + if(!--m_remainingReplies) { + emit resultsAvailable(QStringLiteral("pkginfo"), m_id, m_results); + deleteLater(); + } +} + +} // namespace RepoIndex + diff --git a/alpm/packageinfolookup.h b/alpm/packageinfolookup.h new file mode 100644 index 0000000..cdacd93 --- /dev/null +++ b/alpm/packageinfolookup.h @@ -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 m_packages; + +}; + +} // namespace RepoIndex + +#endif // REPOINDEX_PACKAGEINFOLOOKUP_H diff --git a/alpm/packagelookup.cpp b/alpm/packagelookup.cpp new file mode 100644 index 0000000..c7b4094 --- /dev/null +++ b/alpm/packagelookup.cpp @@ -0,0 +1,4 @@ +#include "./packagelookup.h" + + + diff --git a/alpm/packagelookup.h b/alpm/packagelookup.h new file mode 100644 index 0000000..448d83d --- /dev/null +++ b/alpm/packagelookup.h @@ -0,0 +1,48 @@ +#ifndef PACKAGELOOKUP_H +#define PACKAGELOOKUP_H + +#include +#include +#include + +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 diff --git a/alpm/repository.cpp b/alpm/repository.cpp index ab2df41..c98ee61 100644 --- a/alpm/repository.cpp +++ b/alpm/repository.cpp @@ -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 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 &upgradeSources) const +void Repository::checkForUpgrades(UpgradeLookupResults &results, const QList &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 = 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 Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo) { enum { FieldName, @@ -528,6 +534,7 @@ void Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo) QString packageBase; QList > baseInfo; QList > packageInfo; + QList 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; } diff --git a/alpm/repository.h b/alpm/repository.h index cd66bbf..2c4234e 100644 --- a/alpm/repository.h +++ b/alpm/repository.h @@ -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 &upgradeSources() const; - QList &upgradeSources(); + const QList &upgradeSources() const; + QList &upgradeSources(); QJsonArray upgradeSourcesJsonArray() const; void checkForUpgrades(UpgradeLookupResults &results) const; - void checkForUpgrades(UpgradeLookupResults &results, const QList &upgradeSources) const; + void checkForUpgrades(UpgradeLookupResults &results, const QList &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 addPackagesFromSrcInfo(const QByteArray &srcInfo); static const uint32 invalidIndex = static_cast(-1); @@ -203,7 +203,7 @@ protected: std::map > m_groups; QStringList m_serverUrls; alpm_siglevel_t m_sigLevel; - QList m_upgradeSources; + QList 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 &Repository::upgradeSources() const +inline const QList &Repository::upgradeSources() const { return m_upgradeSources; } -inline QList &Repository::upgradeSources() +inline QList &Repository::upgradeSources() { return m_upgradeSources; } diff --git a/alpm/suggestionslookup.cpp b/alpm/suggestionslookup.cpp index 90123a1..6a9b57d 100644 --- a/alpm/suggestionslookup.cpp +++ b/alpm/suggestionslookup.cpp @@ -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; diff --git a/alpm/suggestionslookup.h b/alpm/suggestionslookup.h index 203cc89..a0b829d 100644 --- a/alpm/suggestionslookup.h +++ b/alpm/suggestionslookup.h @@ -1,51 +1,22 @@ #ifndef REPOINDEX_SUGGESTIONSLOOKUP_H #define REPOINDEX_SUGGESTIONSLOOKUP_H -#include -#include -#include +#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 diff --git a/alpm/upgradelookup.cpp b/alpm/upgradelookup.cpp index a0266f8..9727d30 100644 --- a/alpm/upgradelookup.cpp +++ b/alpm/upgradelookup.cpp @@ -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() << m_upgradeSource); + m_toCheck->checkForUpgrades(m_results, QList() << 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(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; } diff --git a/alpm/upgradelookup.h b/alpm/upgradelookup.h index 55390b3..2617ad1 100644 --- a/alpm/upgradelookup.h +++ b/alpm/upgradelookup.h @@ -21,7 +21,7 @@ public: UpgradeResult(const Package *package, const QString ¤tVersion); 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 *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 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: diff --git a/main.cpp b/main.cpp index 78a8fa5..7914ce3 100644 --- a/main.cpp +++ b/main.cpp @@ -15,6 +15,11 @@ #include #include +// testing +#include "./alpm/aurpackage.h" +#include "./network/userrepository.h" +#include + 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()); diff --git a/network/userrepository.cpp b/network/userrepository.cpp index 340c8e1..a918605 100644 --- a/network/userrepository.cpp +++ b/network/userrepository.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -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(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(package.get())->putJson(obj); + } else { + package = make_unique(obj, static_cast(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 &networkRe void AurFullPackageReply::processData() { - //auto *reply = static_cast(sender()); - // TODO + auto *reply = static_cast(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(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(suggestionString, static_cast(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(package.get())->putJson(obj); + } else { + package = make_unique(obj, static_cast(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(suggestionString, static_cast(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(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(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 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(this)); + return new AurFullPackageReply(replies, this); } } diff --git a/network/userrepository.h b/network/userrepository.h index 7fea8d0..19a8794 100644 --- a/network/userrepository.h +++ b/network/userrepository.h @@ -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 emptyPackage(); diff --git a/repoindex.pro b/repoindex.pro index 4c34eb9..ceb0d7c 100644 --- a/repoindex.pro +++ b/repoindex.pro @@ -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 \