From 69b0d7e2587424e7cde6d9a1727c3ec8690c935e Mon Sep 17 00:00:00 2001 From: Martchus Date: Fri, 12 Feb 2016 01:05:08 +0100 Subject: [PATCH] added desc parser, minor adjustments --- alpm/alpmdatabase.cpp | 5 + alpm/alpmdatabase.h | 3 + alpm/alpmpackage.cpp | 10 +- alpm/alpmpackage.h | 1 + alpm/config.cpp | 6 + alpm/config.h | 2 + alpm/package.cpp | 274 +++++++++++++++++++++++++-- alpm/package.h | 19 +- alpm/repository.cpp | 148 +++++++++++++-- alpm/repository.h | 1 + network/userrepository.cpp | 8 +- resources/settings/repoindex.conf.js | 3 +- web/css/core.css | 1 + 13 files changed, 434 insertions(+), 47 deletions(-) diff --git a/alpm/alpmdatabase.cpp b/alpm/alpmdatabase.cpp index e1b3952..d5da152 100644 --- a/alpm/alpmdatabase.cpp +++ b/alpm/alpmdatabase.cpp @@ -125,5 +125,10 @@ bool AlpmDatabase::addServerUrls(const QStringList &urls) return res; } +std::unique_ptr AlpmDatabase::emptyPackage() +{ + return make_unique(this); +} + } // namespace Alpm diff --git a/alpm/alpmdatabase.h b/alpm/alpmdatabase.h index 4917c72..d63a60f 100644 --- a/alpm/alpmdatabase.h +++ b/alpm/alpmdatabase.h @@ -49,6 +49,9 @@ public: signals: void initiated(); +protected: + std::unique_ptr emptyPackage(); + private: alpm_db_t *m_ptr; QString m_dbFile; diff --git a/alpm/alpmpackage.cpp b/alpm/alpmpackage.cpp index 7a13272..49754c7 100644 --- a/alpm/alpmpackage.cpp +++ b/alpm/alpmpackage.cpp @@ -37,6 +37,14 @@ using namespace Utilities; * \brief The AlpmPackage class wraps an ALPM package struct and holds additional meta information. */ +/*! + * \brief Constructs an empty ALPM package. + */ +AlpmPackage::AlpmPackage(AlpmDatabase *repository) : + Package(QString(), repository), + m_ptr(nullptr) +{} + /*! * \brief Constructs a new instance for the specified ALPM \a package. */ @@ -64,7 +72,7 @@ AlpmPackage::AlpmPackage(alpm_pkg_t *package, AlpmDatabase *alpmDatabase) : m_hasInstallScript = alpm_pkg_has_scriptlet(package); m_fileName = qstr(alpm_pkg_get_filename(package)); m_buildDate = DateTime::fromTimeStamp(alpm_pkg_get_builddate(package)); - m_packer = qstr(alpm_pkg_get_packager(package)); + m_packager = qstr(alpm_pkg_get_packager(package)); m_md5 = qstr(alpm_pkg_get_md5sum(package)); m_sha256 = qstr(alpm_pkg_get_sha256sum(package)); m_buildArchitecture = qstr(alpm_pkg_get_arch(package)); diff --git a/alpm/alpmpackage.h b/alpm/alpmpackage.h index 069576a..19b002e 100644 --- a/alpm/alpmpackage.h +++ b/alpm/alpmpackage.h @@ -10,6 +10,7 @@ class AlpmDatabase; class AlpmPackage : public Package { public: + AlpmPackage(AlpmDatabase *repository); AlpmPackage(alpm_pkg_t *package, AlpmDatabase *alpmDatabase); AlpmPackage(alpm_pkg_t *package); diff --git a/alpm/config.cpp b/alpm/config.cpp index 2c8a635..d309b53 100644 --- a/alpm/config.cpp +++ b/alpm/config.cpp @@ -53,6 +53,7 @@ ConfigArgs::ConfigArgs(ArgumentParser &parser) : 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"), cacheDirArg("cache-dir", string(), "specifies the cache directory (default is /var/cache/repoindex)"), + storageDirArg("storage-dir", string(), "specifies the storage directory (default is /var/lib/repoindex)"), 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") { @@ -130,6 +131,9 @@ ConfigArgs::ConfigArgs(ArgumentParser &parser) : cacheDirArg.setCombinable(true); cacheDirArg.setRequiredValueCount(1); cacheDirArg.setValueNames(pathValueName); + storageDirArg.setCombinable(true); + storageDirArg.setRequiredValueCount(1); + storageDirArg.setValueNames(pathValueName); parser.setMainArguments({&buildOrderArg, &upgradeLookupArg, &serverArg, &mingwBundleArg, &repoindexConfArg, &repoindexConfArg, &cacheDirArg, &helpArg}); } @@ -146,6 +150,7 @@ Config::Config() : m_alpmDbPath(QStringLiteral("/var/lib/pacman")), m_pacmanConfFile(QStringLiteral("/etc/pacman.conf")), m_cacheDir(QStringLiteral("/var/cache/repoindex")), + m_storageDir(QStringLiteral("/var/lib/repoindex")), m_websocketServerListeningAddr(QHostAddress::LocalHost), m_websocketServerListeningPort(1234), m_serverInsecure(false), @@ -234,6 +239,7 @@ void Config::loadFromConfigFile(const QString &configFilePath) m_alpmDbPath = alpmObj.value(QStringLiteral("dbPath")).toString(m_alpmDbPath); m_pacmanConfFile = alpmObj.value(QStringLiteral("pacmanConfigFile")).toString(m_pacmanConfFile); m_cacheDir = mainObj.value(QStringLiteral("cacheDir")).toString(m_cacheDir); + m_storageDir = mainObj.value(QStringLiteral("storageDir")).toString(m_storageDir); auto aurObj = mainObj.value(QStringLiteral("aur")).toObject(); m_aurEnabled = aurObj.value(QStringLiteral("enabled")).toBool(m_aurEnabled); auto serverObj = mainObj.value(QStringLiteral("server")).toObject(); diff --git a/alpm/config.h b/alpm/config.h index 123b2d5..9873baa 100644 --- a/alpm/config.h +++ b/alpm/config.h @@ -44,6 +44,7 @@ public: ApplicationUtilities::Argument defaultIconThemeArg; ApplicationUtilities::Argument extraPackagesArg; ApplicationUtilities::Argument cacheDirArg; + ApplicationUtilities::Argument storageDirArg; ApplicationUtilities::Argument shSyntaxArg; ApplicationUtilities::Argument repoArg; }; @@ -143,6 +144,7 @@ private: QString m_alpmDbPath; QString m_pacmanConfFile; QString m_cacheDir; + QString m_storageDir; QHostAddress m_websocketServerListeningAddr; quint16 m_websocketServerListeningPort; diff --git a/alpm/package.cpp b/alpm/package.cpp index 28aab0b..5ce97ed 100644 --- a/alpm/package.cpp +++ b/alpm/package.cpp @@ -328,7 +328,7 @@ QJsonObject Package::detailedInfo() const put(info, QStringLiteral("optf"), optionalFor()); put(info, QStringLiteral("conf"), conflicts()); put(info, QStringLiteral("repl"), replaces()); - put(info, QStringLiteral("pack"), packer()); + put(info, QStringLiteral("pack"), packager()); put(info, QStringLiteral("expl"), QJsonValue(installReason() == ALPM_PKG_REASON_EXPLICIT)); put(info, QStringLiteral("scri"), QJsonValue(hasInstallScript())); put(info, QStringLiteral("sig"), Utilities::validationMethodsStrings(validationMethods())); @@ -348,7 +348,7 @@ QJsonObject Package::simpleInfo() const put(info, QStringLiteral("bdate"), buildDate()); put(info, QStringLiteral("url"), upstreamUrl()); put(info, QStringLiteral("lic"), licenses()); - put(info, QStringLiteral("packer"), packer()); + put(info, QStringLiteral("packer"), packager()); return info; } @@ -363,7 +363,7 @@ void Package::writeToCacheStream(QDataStream &out) << m_groups << m_dependencies << m_optionalDependencies << m_conflicts << m_provides << m_replaces << m_requiredByComputed << m_requiredBy << m_optionalFor << m_hasInstallScript; // build related meta data - out << m_hasBuildRelatedMetaData << m_fileName << m_files << m_buildDate << m_packer + out << m_hasBuildRelatedMetaData << m_fileName << m_files << m_buildDate << m_packager << m_md5 << m_sha256 << m_buildArchitecture << m_packageSize << m_makeDependencies; // installation related meta data out << m_hasInstallRelatedMetaData << m_installDate << m_installedSize << m_backupFiles @@ -396,7 +396,7 @@ void Package::restoreFromCacheStream(QDataStream &in) >> m_groups >> m_dependencies >> m_optionalDependencies >> m_conflicts >> m_provides >> m_replaces >> m_requiredByComputed >> m_requiredBy >> m_optionalFor >> m_hasInstallScript; // build related meta data - in >> m_hasBuildRelatedMetaData >> m_fileName >> m_files >> m_buildDate >> m_packer + in >> m_hasBuildRelatedMetaData >> m_fileName >> m_files >> m_buildDate >> m_packager >> m_md5 >> m_sha256 >> m_buildArchitecture >> m_packageSize >> m_makeDependencies; // installation related meta data in >> m_hasInstallRelatedMetaData >> m_installDate >> m_installedSize >> m_backupFiles; @@ -423,32 +423,101 @@ void Package::restoreFromCacheStream(QDataStream &in) } /*! - * \brief Puts the specified src/pkg info key value pairs; clears current dependencies, provides, ... before inserting new values. - * \remarks This method should only be called by the associated repository because it must handle a possible name change. + * \brief Puts the specified .SRCINFO/.PKGINFO key value pairs; clears current values before inserting new values. + * \remarks + * - This method should only be called by the associated repository because the associated repository might + * has to handle a possible name change. + * - Actual parsing of .SRCINFO/.PKGINFO is done in Repository::addPackagesFromSrcInfo() because one info file + * applies to multiple packages in case of split packages. */ -void Package::putInfo(const QList > &baseInfo, const QList > &pkgInfo, bool includesSourceRelatedMetaData) +void Package::putInfo(const QList > &baseInfo, const QList > &pkgInfo, bool includesSourceRelatedMetaData, bool includesBuildRelatedMetaData) { // clear current values + m_baseName.clear(); + m_description.clear(); + m_upstreamUrl.clear(); + m_packager.clear(); 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 + if(includesBuildRelatedMetaData) { + m_buildArchitecture.clear(); + } + if(includesSourceRelatedMetaData) { + m_architectures.clear(); + m_makeDependencies.clear(); + m_checkDependencies.clear(); + m_installedSize = 0; + m_buildDate = DateTime(); + m_packager.clear(); + } + + // prevent overwriting these crucial fields with empty values + QString name; PackageVersion version; - QStringList archs; + + // read specified key value pairs const auto infos = {baseInfo, pkgInfo}; for(const auto &info : infos) { + for(const auto &pair : info) { + const auto &field = pair.first; + if(field == QLatin1String("pkgbase")) { + m_baseName.clear(); + } else if(field == QLatin1String("pkgname")) { + name.clear(); + } else if(field == QLatin1String("epoch")) { + version.epoch.clear(); + } else if(field == QLatin1String("pkgver")) { + version.version.clear(); + } else if(field == QLatin1String("pkgrel")) { + version.release.clear(); + } else if(field == QLatin1String("pkgdesc")) { + m_description.clear(); + } else if(field == QLatin1String("url")) { + m_upstreamUrl.clear(); + } else if(field == QLatin1String("arch")) { + if(includesSourceRelatedMetaData) { + m_architectures.clear(); + } + if(includesBuildRelatedMetaData) { + m_buildArchitecture.clear(); + } + } else if(field == QLatin1String("license")) { + m_licenses.clear(); + } else if(field == QLatin1String("depends")) { + m_dependencies.clear(); + } else if(field == QLatin1String("makedepends")) { + m_makeDependencies.clear(); + } else if(field == QLatin1String("checkdepends")) { + m_checkDependencies.clear(); + } else if(field == QLatin1String("optdepends")) { + m_optionalDependencies.clear(); + } else if(field == QLatin1String("conflicts")) { + m_conflicts.clear(); + } else if(field == QLatin1String("provides")) { + m_provides.clear(); + } else if(field == QLatin1String("replaces")) { + m_replaces.clear(); + } else if(field == QLatin1String("source")) { + // currently not used + } else if(field == QLatin1String("size")) { + m_installedSize = 0; + } else if(field == QLatin1String("builddate")) { + m_buildDate = DateTime(); + } else if(field == QLatin1String("packager")) { + m_packager.clear(); + } + } 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; + name = value; } else if(field == QLatin1String("epoch")) { version.epoch = value; } else if(field == QLatin1String("pkgver")) { @@ -460,7 +529,12 @@ void Package::putInfo(const QList > &baseInfo, const QLi } else if(field == QLatin1String("url")) { m_upstreamUrl = value; } else if(field == QLatin1String("arch")) { - archs << value; + if(includesSourceRelatedMetaData) { + m_architectures << value; + } + if(includesBuildRelatedMetaData) { + m_buildArchitecture = value; + } } else if(field == QLatin1String("license")) { m_licenses << value; } else if(field == QLatin1String("depends")) { @@ -479,26 +553,196 @@ void Package::putInfo(const QList > &baseInfo, const QLi m_replaces << Dependency(value); } else if(field == QLatin1String("source")) { // currently not used + } else if(field == QLatin1String("size")) { + m_installedSize = value.toUInt(); + } else if(field == QLatin1String("builddate")) { + m_buildDate = DateTime::fromTimeStampGmt(value.toUInt()); + } else if(field == QLatin1String("packager")) { + m_packager = value; } } } + + // ensure crucial information is still present (use old values rather than no values) + if(!name.isEmpty()) { + m_name = name; + } if(!version.version.isEmpty()) { m_version = version.toString(); } - if(!archs.isEmpty()) { - m_architectures.swap(archs); + // use the name as base name if the base name hasn't been specified explicitely + if(includesSourceRelatedMetaData && m_baseName.isEmpty()) { + m_baseName = m_name; } + // consider general information as complete m_hasGeneralInfo = m_hasAllGeneralInfo = true; m_hasSourceRelatedMetaData = includesSourceRelatedMetaData; + m_hasBuildRelatedMetaData = includesBuildRelatedMetaData; } +inline void put(QString &lhs, const QStringList &rhs) +{ + if(!rhs.isEmpty()) { + lhs = rhs.back(); + } +} + +inline void put(QList &lhs, const QStringList &rhs) +{ + lhs.reserve(rhs.size()); + for(const QString &dep : rhs) { + lhs << Dependency(dep); + } +} + +inline void put(QJsonArray &lhs, const QStringList &rhs) +{ + for(const QString &value : rhs) { + lhs << value; + } +} + +/*! + * \brief Puts the specified desc/depends/files key value(s) pairs; clears current values before inserting new values. + * \remarks + * - This method should only be called by the associated repository because the associated repository might + * has to handle a possible name change. + * - Actual parsing of desc/depends/files is done in Repository::addPackagesFromSrcInfo() because one info file + * applies to multiple packages in case of split packages. + */ +void Package::putDescription(QString name, const QList > &description) +{ + // clear current meta data + m_hasInstallRelatedMetaData = false; + m_fileName.clear(); + m_description.clear(); + m_upstreamUrl.clear(); + m_buildArchitecture.clear(); + m_licenses.clear(); + m_dependencies.clear(); + m_makeDependencies.clear(); + m_checkDependencies.clear(); + m_optionalDependencies.clear(); + m_conflicts.clear(); + m_provides.clear(); + m_replaces.clear(); + m_buildDate = m_installDate = DateTime(); + m_packageSize = m_installedSize = 0; + m_files = QJsonArray(); + m_md5.clear(); + m_sha256.clear(); + m_installReason = ALPM_PKG_REASON_EXPLICIT; + m_validationMethods = ALPM_PKG_VALIDATION_UNKNOWN; + + // prevent overwriting these crucial fields with empty values + PackageVersion version; + + for(const auto &pair : description) { + const auto &field = pair.first; + const auto &values = pair.second; + if(field == QLatin1String("FILENAME")) { + put(m_fileName, values); + } else if(field == QLatin1String("NAME")) { + put(name, values); + } else if(field == QLatin1String("VERSION")) { + if(!values.isEmpty()) { + version = PackageVersion(values.back()); + } + } else if(field == QLatin1String("DESC")) { + put(m_description, values); + } else if(field == QLatin1String("URL")) { + put(m_upstreamUrl, values); + } else if(field == QLatin1String("ARCH")) { + put(m_buildArchitecture, values); + } else if(field == QLatin1String("LICENSE")) { + m_licenses = values; + } else if(field == QLatin1String("DEPENDS")) { + put(m_dependencies, values); + } else if(field == QLatin1String("MAKEDEPENDS")) { + put(m_makeDependencies, values); + } else if(field == QLatin1String("CHECKDEPENDS")) { + put(m_checkDependencies, values); + } else if(field == QLatin1String("OPTDEPENDS")) { + put(m_optionalDependencies, values); + } else if(field == QLatin1String("CONFLICTS")) { + put(m_conflicts, values); + } else if(field == QLatin1String("PROVIDES")) { + put(m_provides, values); + } else if(field == QLatin1String("REPLACES")) { + put(m_replaces, values); + } else if(field == QLatin1String("BUILDDATE")) { + if(!values.isEmpty()) { + m_buildDate = DateTime::fromTimeStampGmt(values.back().toUInt()); + } + } else if(field == QLatin1String("INSTALLDATE")) { + if(!values.isEmpty()) { + m_installDate = DateTime::fromTimeStampGmt(values.back().toUInt()); + m_hasInstallRelatedMetaData = true; + } + } else if(field == QLatin1String("ISIZE") || field == QLatin1String("SIZE")) { + if(!values.empty()) { + m_installedSize = values.back().toUInt(); + m_hasInstallRelatedMetaData = true; + } + } else if(field == QLatin1String("CSIZE")) { + if(!values.empty()) { + m_packageSize = values.back().toUInt(); + } + } else if(field == QLatin1String("PACKAGER")) { + put(m_packager, values); + } else if(field == QLatin1String("MD5SUM")) { + put(m_md5, values); + } else if(field == QLatin1String("SHA256SUM")) { + put(m_sha256, values); + } else if(field == QLatin1String("FILES")) { + put(m_files, values); + } else if(field == QLatin1String("REASON")) { + if(!values.isEmpty()) { + m_installReason = values.back().toUInt() == 1 ? ALPM_PKG_REASON_DEPEND : ALPM_PKG_REASON_EXPLICIT; + } + } else if(field == QLatin1String("VALIDATION")) { + if(values.isEmpty()) { + m_validationMethods = ALPM_PKG_VALIDATION_NONE; + } else { + for(const QString &value : values) { + if(value == QLatin1String("md5")) { + m_validationMethods = static_cast(m_validationMethods | ALPM_PKG_VALIDATION_MD5SUM); + } else if(value == QLatin1String("sha256")) { + m_validationMethods = static_cast(m_validationMethods | ALPM_PKG_VALIDATION_SHA256SUM); + } else if(value == QLatin1String("pgp")) { + m_validationMethods = static_cast(m_validationMethods | ALPM_PKG_VALIDATION_SIGNATURE); + } else { + // TODO: error handling (imporant?) + } + } + } + m_hasInstallRelatedMetaData = true; + } + } + + // ensure crucial information is still present (use old values rather than no values) + if(!name.isEmpty()) { + m_name = name; + } + if(!version.version.isEmpty()) { + m_version = version.toString(); + } + + // description provides source related meta data, too (except pkgbase, TODO: special flag required?) + m_hasBuildRelatedMetaData = m_hasSourceRelatedMetaData = true; +} + +/*! + * \brief Adds a source file with the specified \a path and \a data. + */ void Package::putSourceFile(const QString &path, const QByteArray &data) { m_sourceFiles.insert(make_pair(path, data)); } /*! + * \class PackageVersion * \brief The PackageVersion class helps parsing package versions. */ diff --git a/alpm/package.h b/alpm/package.h index aa7dba2..e9e6ca3 100644 --- a/alpm/package.h +++ b/alpm/package.h @@ -144,7 +144,7 @@ public: const QString &fileName() const; const QJsonArray &files() const; ChronoUtilities::DateTime buildDate() const; - const QString &packer() const; + const QString &packager() const; const QString &md5() const; const QString &sha256() const; const QString &buildArchitecture() const; @@ -191,8 +191,9 @@ public: void restoreFromCacheStream(QDataStream &in); void reinitEntries(); - // parsing src/pkg info - void putInfo(const QList > &baseInfo, const QList > &pkgInfo, bool includesSourceRelatedMetaData = false); + // parsing .SRCINFO/.PKGINFO/desc/depends/files info + void putInfo(const QList > &baseInfo, const QList > &pkgInfo, bool includesSourceRelatedMetaData = false, bool includesBuildRelatedMetaData = false); + void putDescription(QString name, const QList > &description); void putSourceFile(const QString &path, const QByteArray &data); protected: @@ -228,7 +229,7 @@ protected: QString m_fileName; QJsonArray m_files; ChronoUtilities::DateTime m_buildDate; - QString m_packer; + QString m_packager; QString m_md5; QString m_sha256; QString m_buildArchitecture; @@ -457,11 +458,11 @@ inline ChronoUtilities::DateTime Package::buildDate() const } /*! - * \brief Returns the packer of the package file. + * \brief Returns the packager of the package file. */ -inline const QString &Package::packer() const +inline const QString &Package::packager() const { - return m_packer; + return m_packager; } /*! @@ -660,7 +661,9 @@ inline const QString &Package::tarUrl() const } /*! - * \brief Returns the source files of the package. + * \brief Returns the available source files. + * + * Contains usually the PKGBUILD/.SRCINFO file and patches. */ inline const std::map &Package::sourceFiles() const { diff --git a/alpm/repository.cpp b/alpm/repository.cpp index d16a508..8faf34e 100644 --- a/alpm/repository.cpp +++ b/alpm/repository.cpp @@ -551,25 +551,37 @@ void Repository::cleanOutdatedPackages() } /*! - * \brief Adds packages parsed from the specified \a srcInfo. - * \returns Returns the added packages. + * \brief Adds packages parsed from the specified .SRCINFO/.PKGINFO file. + * \remarks Updates existing packages. + * \returns Returns the added/updated packages. In the case of a split package more then + * one package is returned. */ QList Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo) { + // define states enum { - FieldName, - EquationSign, - Pad, - FieldValue, - Comment + FieldName, // reading field name (initial state) + EquationSign, // expecting equation sign + Pad, // expecting padding + FieldValue, // reading field value + Comment // reading comment } state = FieldName; + + // define variables to store parsing results QString currentFieldName; + currentFieldName.reserve(16); QString currentFieldValue; + currentFieldValue.reserve(32); QString packageBase; + packageBase.reserve(32); QList > baseInfo; + baseInfo.reserve(16); QList > packageInfo; + packageInfo.reserve(16); QList packages; Package *currentPackage = nullptr; + + // state machine: consumes each char of .SRCINFO for(const char c : srcInfo) { switch(state) { case FieldName: @@ -628,23 +640,28 @@ QList Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo) } else if(currentFieldName == QLatin1String("pkgname")) { // next package if(packageBase.isEmpty()) { - // TODO: handle error - pkgbase must be present - } else { - if(currentPackage) { - currentPackage->putInfo(baseInfo, packageInfo, true); - packages << currentPackage; - } - auto &pkg = m_packages[currentFieldValue]; - if(!pkg) { - pkg = emptyPackage(); - } - currentPackage = pkg.get(); - packageInfo.clear(); + // no pkgbase specified -> use the first pkgname as pkgbase + packageBase = currentFieldName; } + // put current info to current package + if(currentPackage) { + currentPackage->putInfo(baseInfo, packageInfo, true); + packages << currentPackage; + } + // find next package + auto &pkg = m_packages[currentFieldValue]; + if(!pkg) { + pkg = emptyPackage(); + } + currentPackage = pkg.get(); + packageInfo.clear(); } + // add field to ... if(currentPackage) { + // ... concrete package info if there's already a concrete package packageInfo << QPair(currentFieldName, currentFieldValue); } else { + // ... base info if still parsing general info baseInfo << QPair(currentFieldName, currentFieldValue); } currentFieldName.clear(); @@ -672,4 +689,97 @@ QList Repository::addPackagesFromSrcInfo(const QByteArray &srcInfo) return packages; } +/*! + * \brief Adds packages parsed from the specified desc/depends/files file. + * \remarks Updates the package if it already exists. + * \returns Returns the added/updated package. + */ +Package *Repository::addPackageFromDescription(QString name, const QList &descriptions) +{ + // define variables to store parsing results + QString currentFieldName; + currentFieldName.reserve(16); + QStringList currentFieldValues; + QList > fields; + + for(const QByteArray &description : descriptions) { + // define states + enum { + FieldName, // reading field name + NewLine, // expecting new line (after field name) + Next, // start reading next field value / next field name (initial state) + FieldValue, // reading field value + } state = Next; + + // state machine: consumes each char of desc + for(const char c : description) { + switch(state) { + case FieldName: + switch(c) { + case '%': + state = NewLine; + break; + default: + currentFieldName.append(c); + } + break; + case NewLine: + switch(c) { + case '\n': case '\r': + state = Next; + break; + default: + ; // ignore unexpected characters + } + break; + case Next: + switch(c) { + case '\n': case '\r': case '\t': case ' ': + break; + case '%': + state = FieldName; + // next field -> put current field + if(!currentFieldName.isEmpty()) { + if(!currentFieldValues.isEmpty() && currentFieldName == QLatin1String("NAME")) { + name = currentFieldValues.back(); + } + fields << QPair(currentFieldName, currentFieldValues); + currentFieldName.clear(); + currentFieldValues.clear(); + } + break; + default: + state = FieldValue; + currentFieldValues << QString(QChar(c)); + } + break; + case FieldValue: + switch(c) { + case '\n': case '\r': + state = Next; + break; + default: + currentFieldValues.back().append(c); + } + } + } + + // put last field + if(!currentFieldName.isEmpty()) { + if(!currentFieldValues.isEmpty() && currentFieldName == QLatin1String("NAME")) { + name = currentFieldValues.back(); + } + fields << QPair(currentFieldName, currentFieldValues); + } + } + + // find/create package for description + auto &pkg = m_packages[name]; + if(!pkg) { + pkg = emptyPackage(); + } + pkg->putDescription(name, fields); + return pkg.get(); +} + } // namespace PackageManagement diff --git a/alpm/repository.h b/alpm/repository.h index b421410..399a6d0 100644 --- a/alpm/repository.h +++ b/alpm/repository.h @@ -242,6 +242,7 @@ public: // parsing src/pkg info QList addPackagesFromSrcInfo(const QByteArray &srcInfo); + Package *addPackageFromDescription(QString name, const QList &descriptions); // thread synchronization QReadWriteLock *lock() const; diff --git a/network/userrepository.cpp b/network/userrepository.cpp index b54bfc4..2eca8eb 100644 --- a/network/userrepository.cpp +++ b/network/userrepository.cpp @@ -1,6 +1,7 @@ #include "userrepository.h" #include "../alpm/aurpackage.h" +#include "../alpm/config.h" #include @@ -20,6 +21,8 @@ #include #include +#include + using namespace std; using namespace ChronoUtilities; @@ -118,10 +121,9 @@ void AurFullPackageReply::processData(QNetworkReply *reply) const auto data = static_cast(entry)->data(); for(Package *package : packages) { package->putSourceFile(entry->name(), data); - // TODO: add source files } } else { - // don't think it is required to read sub directories recursively + // don't think it is required to read sub directories recursively (TODO?) } } } @@ -135,7 +137,7 @@ void AurFullPackageReply::processData(QNetworkReply *reply) m_error = QStringLiteral("Unable to request tarball from AUR: ") + reply->errorString(); } if(!m_error.isEmpty()) { - qDebug() << m_error; + cerr << shchar << m_error.toLocal8Bit().data(); } } diff --git a/resources/settings/repoindex.conf.js b/resources/settings/repoindex.conf.js index 9970c34..d9dc3bb 100644 --- a/resources/settings/repoindex.conf.js +++ b/resources/settings/repoindex.conf.js @@ -9,7 +9,8 @@ "enabled": true }, - "cacheDir": "/var/cache/repoindex" + "cacheDir": "/var/cache/repoindex", + "storageDir": "/var/lib/repoindex", "server": { "websocketListeningAddr": "any-IPv4", diff --git a/web/css/core.css b/web/css/core.css index 0e72b4d..c169624 100644 --- a/web/css/core.css +++ b/web/css/core.css @@ -54,6 +54,7 @@ span.glyphicon { border: none!important; font-size: 90%; padding: 5px; + vertical-align: top!important; } /*