2021-01-25 00:24:31 +01:00
|
|
|
#include "./database.h"
|
|
|
|
#include "./config.h"
|
2021-12-05 23:40:51 +01:00
|
|
|
#include "./storageprivate.h"
|
2021-01-25 00:24:31 +01:00
|
|
|
|
|
|
|
#include "reflection/database.h"
|
|
|
|
|
|
|
|
#include <c++utilities/conversion/stringbuilder.h>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace CppUtilities;
|
|
|
|
|
|
|
|
namespace LibPkg {
|
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
struct AffectedPackages {
|
|
|
|
std::unordered_set<StorageID> newPackages;
|
|
|
|
std::unordered_set<StorageID> removedPackages;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct AffectedPackagesWithDependencyDetail : public AffectedPackages {
|
|
|
|
std::string version;
|
|
|
|
DependencyMode mode = DependencyMode::Any;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PackageUpdaterPrivate {
|
|
|
|
using AffectedDeps = std::unordered_multimap<std::string, AffectedPackagesWithDependencyDetail>;
|
|
|
|
using AffectedLibs = std::unordered_map<std::string, AffectedPackages>;
|
|
|
|
|
|
|
|
explicit PackageUpdaterPrivate(DatabaseStorage &storage);
|
|
|
|
void update(const PackageCache::StoreResult &res, const std::shared_ptr<Package> &package);
|
|
|
|
void update(const StorageID packageID, bool removed, const std::shared_ptr<Package> &package);
|
|
|
|
void submit(const std::string &dependencyName, AffectedDeps::mapped_type &affected, DependencyStorage::RWTransaction &txn);
|
|
|
|
void submit(const std::string &libraryName, AffectedLibs::mapped_type &affected, LibraryDependencyStorage::RWTransaction &txn);
|
|
|
|
|
|
|
|
PackageStorage::RWTransaction packagesTxn;
|
|
|
|
AffectedDeps affectedProvidedDeps;
|
|
|
|
AffectedDeps affectedRequiredDeps;
|
|
|
|
AffectedLibs affectedProvidedLibs;
|
|
|
|
AffectedLibs affectedRequiredLibs;
|
|
|
|
|
|
|
|
private:
|
|
|
|
static AffectedDeps::iterator findDependency(const Dependency &dependency, AffectedDeps &affected);
|
|
|
|
static void addDependency(StorageID packageID, const Dependency &dependency, bool removed, AffectedDeps &affected);
|
|
|
|
static void addLibrary(StorageID packageID, const std::string &libraryName, bool removed, AffectedLibs &affected);
|
|
|
|
};
|
|
|
|
|
|
|
|
Database::Database(const std::string &name, const std::string &path)
|
|
|
|
: name(name)
|
|
|
|
, path(path)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Database::Database(std::string &&name, std::string &&path)
|
|
|
|
: name(std::move(name))
|
|
|
|
, path(std::move(path))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Database::Database(Database &&other)
|
|
|
|
: name(std::move(other.name))
|
|
|
|
, path(std::move(other.path))
|
|
|
|
, filesPath(std::move(other.filesPath))
|
|
|
|
, mirrors(std::move(other.mirrors))
|
|
|
|
, usage(other.usage)
|
|
|
|
, signatureLevel(other.signatureLevel)
|
|
|
|
, arch(std::move(other.arch))
|
|
|
|
, dependencies(std::move(other.dependencies))
|
|
|
|
, localPkgDir(std::move(other.localPkgDir))
|
|
|
|
, localDbDir(std::move(other.localDbDir))
|
|
|
|
, lastUpdate(other.lastUpdate)
|
|
|
|
, syncFromMirror(other.syncFromMirror)
|
|
|
|
, toBeDiscarded(other.toBeDiscarded)
|
|
|
|
, m_storage(std::move(other.m_storage))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Database::~Database()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Database::initStorage(StorageDistribution &storage)
|
|
|
|
{
|
|
|
|
m_storage = storage.forDatabase(name % '@' + arch);
|
|
|
|
}
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
void LibPkg::Database::deducePathsFromLocalDirs()
|
|
|
|
{
|
|
|
|
if (localDbDir.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (path.empty()) {
|
|
|
|
path = localDbDir % '/' % name + ".db";
|
|
|
|
}
|
|
|
|
if (filesPath.empty()) {
|
|
|
|
filesPath = localDbDir % '/' % name + ".files";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Database::resetConfiguration()
|
|
|
|
{
|
|
|
|
path.clear();
|
|
|
|
filesPath.clear();
|
|
|
|
mirrors.clear();
|
|
|
|
usage = DatabaseUsage::None;
|
|
|
|
signatureLevel = SignatureLevel::Default;
|
|
|
|
arch = "x86_64";
|
|
|
|
dependencies.clear();
|
|
|
|
localPkgDir.clear();
|
|
|
|
localDbDir.clear();
|
|
|
|
syncFromMirror = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Database::clearPackages()
|
|
|
|
{
|
|
|
|
lastUpdate = CppUtilities::DateTime::gmtNow();
|
2021-12-05 23:40:51 +01:00
|
|
|
if (m_storage) {
|
|
|
|
m_storage->packageCache.clear(*m_storage);
|
|
|
|
}
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::shared_ptr<Package>> Database::findPackages(const std::function<bool(const Database &, const Package &)> &pred)
|
|
|
|
{
|
2021-12-05 23:40:51 +01:00
|
|
|
// TODO: use cache here
|
|
|
|
// TODO: avoid std::move()
|
|
|
|
auto pkgs = std::vector<std::shared_ptr<Package>>();
|
|
|
|
auto txn = m_storage->packages.getROTransaction();
|
|
|
|
for (auto i = txn.begin(); i != txn.end(); ++i) {
|
|
|
|
if (pred(*this, *i)) {
|
|
|
|
pkgs.emplace_back(std::make_shared<Package>(std::move(*i)));
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return pkgs;
|
|
|
|
}
|
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
static void removeDependency(DependencyStorage::RWTransaction &txn, StorageID packageID, const std::string &dependencyName)
|
|
|
|
{
|
|
|
|
for (auto [i, end] = txn.equal_range<0>(dependencyName); i != end; ++i) {
|
|
|
|
auto &dependency = i.value();
|
|
|
|
dependency.relevantPackages.erase(packageID);
|
|
|
|
if (dependency.relevantPackages.empty()) {
|
|
|
|
i.del();
|
|
|
|
} else {
|
|
|
|
txn.put(dependency, i.getID());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void removeLibDependency(LibraryDependencyStorage::RWTransaction &txn, StorageID packageID, const std::string &dependencyName)
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
2021-12-05 23:40:51 +01:00
|
|
|
for (auto [i, end] = txn.equal_range<0>(dependencyName); i != end; ++i) {
|
|
|
|
auto &dependency = i.value();
|
|
|
|
dependency.relevantPackages.erase(packageID);
|
|
|
|
if (dependency.relevantPackages.empty()) {
|
|
|
|
i.del();
|
|
|
|
} else {
|
|
|
|
txn.put(dependency, i.getID());
|
|
|
|
}
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Database::removePackageDependencies(StorageID packageID, const std::shared_ptr<Package> &package)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
auto txn = m_storage->providedDeps.getRWTransaction();
|
|
|
|
removeDependency(txn, packageID, package->name);
|
|
|
|
for (const auto &dep : package->provides) {
|
|
|
|
removeDependency(txn, packageID, dep.name);
|
|
|
|
}
|
|
|
|
txn.commit();
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
{
|
|
|
|
auto txn = m_storage->requiredDeps.getRWTransaction();
|
|
|
|
for (const auto &dep : package->dependencies) {
|
|
|
|
removeDependency(txn, packageID, dep.name);
|
|
|
|
}
|
|
|
|
for (const auto &dep : package->optionalDependencies) {
|
|
|
|
removeDependency(txn, packageID, dep.name);
|
|
|
|
}
|
|
|
|
txn.commit();
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
{
|
|
|
|
auto txn = m_storage->providedLibs.getRWTransaction();
|
|
|
|
for (const auto &lib : package->libprovides) {
|
|
|
|
removeLibDependency(txn, packageID, lib);
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
txn.commit();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto txn = m_storage->requiredLibs.getRWTransaction();
|
|
|
|
for (const auto &lib : package->libdepends) {
|
|
|
|
removeLibDependency(txn, packageID, lib);
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
txn.commit();
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void addDependency(DependencyStorage::RWTransaction &txn, StorageID packageID, const std::string &dependencyName,
|
|
|
|
const std::string &dependencyVersion, DependencyMode dependencyMode = DependencyMode::Any)
|
|
|
|
{
|
|
|
|
for (auto [i, end] = txn.equal_range<0>(dependencyName); i != end; ++i) {
|
|
|
|
auto &existingDependency = i.value();
|
|
|
|
if (static_cast<const Dependency &>(existingDependency).version != dependencyVersion) {
|
2021-01-25 00:24:31 +01:00
|
|
|
continue;
|
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
const auto [i2, newID] = existingDependency.relevantPackages.emplace(packageID);
|
|
|
|
if (newID) {
|
|
|
|
txn.put(existingDependency, i.getID());
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
return;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
auto newDependency = DatabaseDependency(dependencyName, dependencyVersion, dependencyMode);
|
|
|
|
newDependency.relevantPackages.emplace(packageID);
|
|
|
|
txn.put(newDependency);
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
static void addLibDependency(LibraryDependencyStorage::RWTransaction &txn, StorageID packageID, const std::string &dependencyName)
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
2021-12-05 23:40:51 +01:00
|
|
|
for (auto [i, end] = txn.equal_range<0>(dependencyName); i != end; ++i) {
|
|
|
|
auto &existingDependency = i.value();
|
|
|
|
const auto [i2, newID] = existingDependency.relevantPackages.emplace(packageID);
|
|
|
|
if (newID) {
|
|
|
|
txn.put(existingDependency, i.getID());
|
|
|
|
}
|
|
|
|
return;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
auto newDependency = DatabaseLibraryDependency(dependencyName);
|
|
|
|
newDependency.relevantPackages.emplace(packageID);
|
|
|
|
txn.put(newDependency);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Database::addPackageDependencies(StorageID packageID, const std::shared_ptr<Package> &package)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
auto txn = m_storage->providedDeps.getRWTransaction();
|
|
|
|
addDependency(txn, packageID, package->name, package->version);
|
|
|
|
for (const auto &dep : package->provides) {
|
|
|
|
addDependency(txn, packageID, dep.name, dep.version, dep.mode);
|
|
|
|
}
|
|
|
|
txn.commit();
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
{
|
|
|
|
auto txn = m_storage->requiredDeps.getRWTransaction();
|
|
|
|
for (const auto &dep : package->dependencies) {
|
|
|
|
addDependency(txn, packageID, dep.name, dep.version, dep.mode);
|
|
|
|
}
|
|
|
|
for (const auto &dep : package->optionalDependencies) {
|
|
|
|
addDependency(txn, packageID, dep.name, dep.version, dep.mode);
|
|
|
|
}
|
|
|
|
txn.commit();
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
{
|
|
|
|
auto txn = m_storage->providedLibs.getRWTransaction();
|
|
|
|
for (const auto &lib : package->libprovides) {
|
|
|
|
addLibDependency(txn, packageID, lib);
|
|
|
|
}
|
|
|
|
txn.commit();
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
{
|
|
|
|
auto txn = m_storage->requiredLibs.getRWTransaction();
|
|
|
|
for (const auto &lib : package->libdepends) {
|
|
|
|
addLibDependency(txn, packageID, lib);
|
|
|
|
}
|
|
|
|
txn.commit();
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
void Database::allPackages(const PackageVisitor &visitor)
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
2021-12-05 23:40:51 +01:00
|
|
|
// TODO: use cache here
|
|
|
|
//auto &cachedPackages = m_storage->packageCache;
|
|
|
|
auto txn = m_storage->packages.getROTransaction();
|
|
|
|
for (auto i = txn.begin(); i != txn.end(); ++i) {
|
|
|
|
if (visitor(i.getID(), std::move(i.value()))) {
|
|
|
|
return;
|
|
|
|
}
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
std::size_t Database::packageCount() const
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
2021-12-05 23:40:51 +01:00
|
|
|
return m_storage->packages.getROTransaction().size();
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
void Database::providingPackages(const Dependency &dependency, bool reverse, const PackageVisitor &visitor)
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
2021-12-05 23:40:51 +01:00
|
|
|
// TODO: use cache here
|
|
|
|
auto package = Package();
|
|
|
|
auto providesTxn = (reverse ? m_storage->requiredDeps : m_storage->providedDeps).getROTransaction();
|
|
|
|
auto packagesTxn = m_storage->packages.getROTransaction();
|
|
|
|
for (auto [i, end] = providesTxn.equal_range<0>(dependency.name); i != end; ++i) {
|
|
|
|
const Dependency &providedDependency = i.value();
|
|
|
|
if (!Dependency::matches(dependency.mode, dependency.version, providedDependency.version)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (const auto packageID : i->relevantPackages) {
|
|
|
|
if (packagesTxn.get(packageID, package) && visitor(packageID, std::move(package))) {
|
|
|
|
return;
|
|
|
|
}
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
}
|
2021-01-25 00:24:31 +01:00
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
void Database::providingPackages(const std::string &libraryName, bool reverse, const PackageVisitor &visitor)
|
|
|
|
{
|
|
|
|
// TODO: use cache here
|
|
|
|
auto package = Package();
|
|
|
|
auto providesTxn = (reverse ? m_storage->requiredLibs : m_storage->providedLibs).getROTransaction();
|
|
|
|
auto packagesTxn = m_storage->packages.getROTransaction();
|
|
|
|
for (auto [i, end] = providesTxn.equal_range<0>(libraryName); i != end; ++i) {
|
|
|
|
for (const auto packageID : i->relevantPackages) {
|
|
|
|
if (packagesTxn.get(packageID, package) && visitor(packageID, std::move(package))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
bool Database::provides(const Dependency &dependency, bool reverse) const
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
2021-12-05 23:40:51 +01:00
|
|
|
auto providesTxn = (reverse ? m_storage->requiredDeps : m_storage->providedDeps).getROTransaction();
|
|
|
|
for (auto [i, end] = providesTxn.equal_range<0>(dependency.name); i != end; ++i) {
|
|
|
|
const Dependency &providedDependency = i.value();
|
|
|
|
if (Dependency::matches(dependency.mode, dependency.version, providedDependency.version)) {
|
|
|
|
return true;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Database::provides(const std::string &libraryName, bool reverse) const
|
|
|
|
{
|
|
|
|
auto providesTxn = (reverse ? m_storage->requiredLibs : m_storage->providedLibs).getROTransaction();
|
|
|
|
return providesTxn.find<0>(libraryName) != providesTxn.end();
|
|
|
|
}
|
2021-01-25 00:24:31 +01:00
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
std::shared_ptr<Package> Database::findPackage(StorageID packageID)
|
|
|
|
{
|
|
|
|
// TODO: use cache here
|
|
|
|
auto package = std::make_shared<Package>();
|
|
|
|
auto txn = m_storage->packages.getROTransaction();
|
|
|
|
return txn.get(packageID, *package) ? package : std::shared_ptr<Package>();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<Package> Database::findPackage(const std::string &packageName)
|
|
|
|
{
|
|
|
|
return m_storage->packageCache.retrieve(*m_storage, packageName).pkg;
|
|
|
|
}
|
|
|
|
|
|
|
|
PackageSpec Database::findPackageWithID(const std::string &packageName)
|
|
|
|
{
|
|
|
|
return m_storage->packageCache.retrieve(*m_storage, packageName);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Database::removePackage(const std::string &packageName)
|
|
|
|
{
|
|
|
|
const auto [packageID, package] = m_storage->packageCache.retrieve(*m_storage, packageName);
|
|
|
|
if (package) {
|
|
|
|
removePackageDependencies(packageID, package);
|
|
|
|
m_storage->packageCache.invalidate(*m_storage, packageName);
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
StorageID Database::updatePackage(const std::shared_ptr<Package> &package)
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
2021-12-05 23:40:51 +01:00
|
|
|
const auto res = m_storage->packageCache.store(*m_storage, package, false);
|
|
|
|
if (!res.updated) {
|
|
|
|
return res.id;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
if (res.oldPackage) {
|
|
|
|
removePackageDependencies(res.id, res.oldPackage);
|
|
|
|
}
|
|
|
|
addPackageDependencies(res.id, package);
|
|
|
|
return res.id;
|
|
|
|
}
|
|
|
|
|
|
|
|
StorageID Database::forceUpdatePackage(const std::shared_ptr<Package> &package)
|
|
|
|
{
|
|
|
|
const auto res = m_storage->packageCache.store(*m_storage, package, true);
|
|
|
|
if (res.oldPackage) {
|
|
|
|
removePackageDependencies(res.id, res.oldPackage);
|
|
|
|
}
|
|
|
|
addPackageDependencies(res.id, package);
|
|
|
|
return res.id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Database::replacePackages(const std::vector<std::shared_ptr<Package>> &newPackages, DateTime lastModified)
|
|
|
|
{
|
2021-01-25 00:24:31 +01:00
|
|
|
clearPackages();
|
2021-12-05 23:40:51 +01:00
|
|
|
auto updater = PackageUpdater(*this);
|
|
|
|
for (const auto &package : newPackages) {
|
|
|
|
updater.update(package);
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
updater.commit();
|
2021-01-25 00:24:31 +01:00
|
|
|
lastUpdate = lastModified;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2021-02-08 23:19:52 +01:00
|
|
|
* \brief Determines which packages are unresolvable assuming new packages are added to the database and certain provides are removed.
|
2021-01-25 00:24:31 +01:00
|
|
|
* \param config The configuration supposed to contain database dependencies.
|
2021-02-08 23:19:52 +01:00
|
|
|
* \param newPackages Packages which are assumed to be added to the database.
|
|
|
|
* \param removedProvides Provides which are assumed to be removed from the database.
|
|
|
|
* \param depsToIgnore Specifies dependencies to be ignored if missing (version constraints not supported).
|
|
|
|
* \param libsToIgnore Specifies libraries to be ignored if missing.
|
|
|
|
* \remarks "Resolvable" means here (so far) just that all dependencies are present. It does not mean a package is "installable" because
|
|
|
|
* conflicts between dependencies might still prevent that.
|
2021-01-25 00:24:31 +01:00
|
|
|
*/
|
2021-12-05 23:40:51 +01:00
|
|
|
std::unordered_map<PackageSpec, UnresolvedDependencies> Database::detectUnresolvedPackages(Config &config,
|
2021-02-08 23:19:52 +01:00
|
|
|
const std::vector<std::shared_ptr<Package>> &newPackages, const DependencySet &removedProvides,
|
|
|
|
const std::unordered_set<std::string_view> &depsToIgnore, const std::unordered_set<std::string_view> &libsToIgnore)
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
2021-12-05 23:40:51 +01:00
|
|
|
auto unresolvedPackages = std::unordered_map<PackageSpec, UnresolvedDependencies>();
|
2021-01-25 00:24:31 +01:00
|
|
|
|
|
|
|
// determine new provides
|
2021-12-05 23:40:51 +01:00
|
|
|
auto newProvides = DependencySet();
|
|
|
|
auto newLibProvides = std::set<std::string>();
|
2021-01-25 00:24:31 +01:00
|
|
|
for (const auto &newPackage : newPackages) {
|
|
|
|
newProvides.add(Dependency(newPackage->name, newPackage->version), newPackage);
|
|
|
|
for (const auto &newProvide : newPackage->provides) {
|
|
|
|
newProvides.add(newProvide, newPackage);
|
|
|
|
}
|
|
|
|
for (const auto &newLibProvide : newPackage->libprovides) {
|
|
|
|
newLibProvides.emplace(newLibProvide);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-08 23:52:01 +01:00
|
|
|
// determine dependencies and "protected" database
|
|
|
|
auto deps = std::vector<Database *>();
|
2021-02-09 11:59:23 +01:00
|
|
|
const auto depOrder = config.computeDatabaseDependencyOrder(*this, false);
|
2021-02-08 23:52:01 +01:00
|
|
|
if (auto *const dbs = std::get_if<std::vector<Database *>>(&depOrder)) {
|
|
|
|
deps = std::move(*dbs);
|
|
|
|
}
|
|
|
|
if (auto *const protectedDb = config.findDatabase(name + "-protected", arch)) {
|
|
|
|
deps.emplace_back(protectedDb);
|
|
|
|
}
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
// check whether all required dependencies are still provided
|
2021-12-05 23:40:51 +01:00
|
|
|
for (auto txn = m_storage->requiredDeps.getROTransaction(); const auto &requiredDep : txn) {
|
2021-02-08 23:19:52 +01:00
|
|
|
// skip dependencies to ignore
|
2021-12-05 23:40:51 +01:00
|
|
|
if (depsToIgnore.find(requiredDep.name) != depsToIgnore.end()) {
|
2021-02-08 23:19:52 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
// skip if new packages provide dependency
|
2021-12-05 23:40:51 +01:00
|
|
|
if (newProvides.provides(requiredDep)) {
|
2021-01-25 00:24:31 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// skip if db provides dependency
|
2021-12-05 23:40:51 +01:00
|
|
|
if (!removedProvides.provides(requiredDep) && provides(requiredDep)) {
|
2021-01-25 00:24:31 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-02-08 23:52:01 +01:00
|
|
|
// skip if dependency is provided by a database this database depends on or the protected version of this db
|
2021-01-25 00:24:31 +01:00
|
|
|
auto providedByAnotherDb = false;
|
2021-02-08 23:52:01 +01:00
|
|
|
for (const auto *db : deps) {
|
2021-12-05 23:40:51 +01:00
|
|
|
if ((providedByAnotherDb = db->provides(requiredDep))) {
|
2021-01-25 00:24:31 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (providedByAnotherDb) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add packages to list of unresolved packages
|
2021-12-05 23:40:51 +01:00
|
|
|
for (const auto &affectedPackageID : requiredDep.relevantPackages) {
|
|
|
|
const auto affectedPackage = findPackage(affectedPackageID);
|
|
|
|
unresolvedPackages[PackageSpec(affectedPackageID, affectedPackage)].deps.emplace_back(requiredDep);
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check whether all required libraries are still provided
|
2021-12-05 23:40:51 +01:00
|
|
|
for (auto txn = m_storage->requiredLibs.getROTransaction(); const auto &requiredLib : txn) {
|
2021-01-25 00:24:31 +01:00
|
|
|
|
2021-02-08 23:19:52 +01:00
|
|
|
// skip libs to ignore
|
2021-12-05 23:40:51 +01:00
|
|
|
if (libsToIgnore.find(requiredLib.name) != libsToIgnore.end()) {
|
2021-02-08 23:19:52 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
// skip if new packages provide dependency
|
2021-12-05 23:40:51 +01:00
|
|
|
if (newLibProvides.find(requiredLib.name) != newLibProvides.end()) {
|
2021-01-25 00:24:31 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// skip if db provides dependency
|
2021-12-05 23:40:51 +01:00
|
|
|
if (provides(requiredLib.name)) {
|
2021-01-25 00:24:31 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-02-08 23:52:01 +01:00
|
|
|
// skip if dependency is provided by a database this database depends on or the protected version of this db
|
2021-01-25 00:24:31 +01:00
|
|
|
auto providedByAnotherDb = false;
|
2021-02-08 23:52:01 +01:00
|
|
|
for (const auto *db : deps) {
|
2021-12-05 23:40:51 +01:00
|
|
|
if ((providedByAnotherDb = db->provides(requiredLib.name))) {
|
2021-01-25 00:24:31 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (providedByAnotherDb) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add packages to list of unresolved packages
|
2021-12-05 23:40:51 +01:00
|
|
|
for (const auto &affectedPackageID : requiredLib.relevantPackages) {
|
|
|
|
const auto affectedPackage = findPackage(affectedPackageID);
|
|
|
|
unresolvedPackages[PackageSpec(affectedPackageID, affectedPackage)].libs.emplace_back(requiredLib.name);
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return unresolvedPackages;
|
|
|
|
}
|
|
|
|
|
2021-01-31 19:56:40 +01:00
|
|
|
LibPkg::PackageUpdates LibPkg::Database::checkForUpdates(const std::vector<LibPkg::Database *> &updateSources, UpdateCheckOptions options)
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
2021-12-05 23:40:51 +01:00
|
|
|
auto results = PackageUpdates();
|
|
|
|
allPackages([&](StorageID myPackageID, Package &&package) {
|
|
|
|
auto myPackage = std::make_shared<Package>(std::move(package));
|
2021-01-31 19:56:40 +01:00
|
|
|
auto regularName = std::string();
|
|
|
|
if (options & UpdateCheckOptions::ConsiderRegularPackage) {
|
|
|
|
const auto decomposedName = myPackage->decomposeName();
|
|
|
|
if ((!decomposedName.targetPrefix.empty() || !decomposedName.vcsSuffix.empty()) && !decomposedName.isVcsPackage()) {
|
|
|
|
regularName = decomposedName.actualName;
|
|
|
|
}
|
|
|
|
}
|
2021-01-25 00:24:31 +01:00
|
|
|
auto foundPackage = false;
|
2021-01-31 19:56:40 +01:00
|
|
|
for (auto *const updateSource : updateSources) {
|
2021-12-05 23:40:51 +01:00
|
|
|
const auto [updatePackageID, updatePackage] = updateSource->findPackageWithID(myPackage->name);
|
|
|
|
if (!updatePackage) {
|
2021-01-25 00:24:31 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
foundPackage = true;
|
|
|
|
const auto versionDiff = myPackage->compareVersion(*updatePackage);
|
|
|
|
std::vector<PackageUpdate> *list = nullptr;
|
|
|
|
switch (versionDiff) {
|
|
|
|
case PackageVersionComparison::SoftwareUpgrade:
|
|
|
|
list = &results.versionUpdates;
|
|
|
|
break;
|
|
|
|
case PackageVersionComparison::PackageUpgradeOnly:
|
|
|
|
list = &results.packageUpdates;
|
|
|
|
break;
|
|
|
|
case PackageVersionComparison::NewerThanSyncVersion:
|
|
|
|
list = &results.downgrades;
|
|
|
|
break;
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
if (list) {
|
2021-12-05 23:40:51 +01:00
|
|
|
list->emplace_back(
|
|
|
|
PackageSearchResult(*this, myPackage, myPackageID), PackageSearchResult(*updateSource, updatePackage, updatePackageID));
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!foundPackage) {
|
2021-12-05 23:40:51 +01:00
|
|
|
results.orphans.emplace_back(PackageSearchResult(*this, myPackage, myPackageID));
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-01-31 19:56:40 +01:00
|
|
|
if (regularName.empty()) {
|
2021-12-05 23:40:51 +01:00
|
|
|
return false;
|
2021-01-31 19:56:40 +01:00
|
|
|
}
|
|
|
|
for (auto *const updateSource : updateSources) {
|
2021-12-05 23:40:51 +01:00
|
|
|
const auto [updatePackageID, updatePackage] = updateSource->findPackageWithID(regularName);
|
|
|
|
if (!updatePackage) {
|
2021-01-31 19:56:40 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const auto versionDiff = myPackage->compareVersion(*updatePackage);
|
|
|
|
std::vector<PackageUpdate> *list = nullptr;
|
|
|
|
switch (versionDiff) {
|
|
|
|
case PackageVersionComparison::SoftwareUpgrade:
|
|
|
|
list = &results.versionUpdates;
|
|
|
|
break;
|
|
|
|
case PackageVersionComparison::PackageUpgradeOnly:
|
|
|
|
list = &results.packageUpdates;
|
|
|
|
break;
|
|
|
|
case PackageVersionComparison::NewerThanSyncVersion:
|
|
|
|
list = &results.downgrades;
|
|
|
|
break;
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
if (list) {
|
2021-12-05 23:40:51 +01:00
|
|
|
list->emplace_back(
|
|
|
|
PackageSearchResult(*this, myPackage, myPackageID), PackageSearchResult(*updateSource, updatePackage, updatePackageID));
|
2021-01-31 19:56:40 +01:00
|
|
|
}
|
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
return false;
|
|
|
|
});
|
2021-01-25 00:24:31 +01:00
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
PackageLocation Database::locatePackage(const string &packageName) const
|
|
|
|
{
|
|
|
|
PackageLocation res;
|
|
|
|
if (packageName.empty()) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
res.pathWithinRepo = localPkgDir % '/' + packageName;
|
|
|
|
try {
|
|
|
|
switch (std::filesystem::symlink_status(res.pathWithinRepo).type()) {
|
|
|
|
case std::filesystem::file_type::regular:
|
|
|
|
res.exists = true;
|
|
|
|
break;
|
|
|
|
case std::filesystem::file_type::symlink:
|
|
|
|
res.storageLocation = std::filesystem::read_symlink(res.pathWithinRepo);
|
|
|
|
if (res.storageLocation.is_absolute()) {
|
|
|
|
res.exists = std::filesystem::is_regular_file(res.storageLocation);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
res.storageLocation = argsToString(localPkgDir, '/', res.storageLocation);
|
|
|
|
if ((res.exists = std::filesystem::is_regular_file(res.storageLocation))) {
|
|
|
|
res.storageLocation = std::filesystem::canonical(res.storageLocation);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} catch (std::filesystem::filesystem_error &e) {
|
|
|
|
res.error = move(e);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Database::filesPathFromRegularPath() const
|
|
|
|
{
|
|
|
|
if (path.empty()) {
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
const auto ext = path.rfind(".db");
|
|
|
|
return ext == std::string::npos ? path : argsToString(std::string_view(path.data(), ext), ".files");
|
|
|
|
}
|
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
PackageUpdaterPrivate::PackageUpdaterPrivate(DatabaseStorage &storage)
|
|
|
|
: packagesTxn(storage.packages.getRWTransaction())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void PackageUpdaterPrivate::update(const PackageCache::StoreResult &res, const std::shared_ptr<Package> &package)
|
|
|
|
{
|
|
|
|
update(res.id, false, package);
|
|
|
|
if (res.oldPackage) {
|
|
|
|
update(res.id, true, res.oldPackage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PackageUpdaterPrivate::update(const StorageID packageID, bool removed, const std::shared_ptr<Package> &package)
|
|
|
|
{
|
|
|
|
addDependency(packageID, Dependency(package->name, package->version), removed, affectedProvidedDeps);
|
|
|
|
for (const auto &dependeny : package->provides) {
|
|
|
|
addDependency(packageID, dependeny, removed, affectedProvidedDeps);
|
|
|
|
}
|
|
|
|
for (const auto &lib : package->libprovides) {
|
|
|
|
addLibrary(packageID, lib, removed, affectedProvidedLibs);
|
|
|
|
}
|
|
|
|
for (const auto &dependeny : package->dependencies) {
|
|
|
|
addDependency(packageID, dependeny, removed, affectedRequiredDeps);
|
|
|
|
}
|
|
|
|
for (const auto &dependeny : package->optionalDependencies) {
|
|
|
|
addDependency(packageID, dependeny, removed, affectedRequiredDeps);
|
|
|
|
}
|
|
|
|
for (const auto &lib : package->libdepends) {
|
|
|
|
addLibrary(packageID, lib, removed, affectedRequiredLibs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PackageUpdaterPrivate::submit(const std::string &dependencyName, AffectedDeps::mapped_type &affected, DependencyStorage::RWTransaction &txn)
|
|
|
|
{
|
|
|
|
for (auto [i, end] = txn.equal_range<0>(dependencyName); i != end; ++i) {
|
|
|
|
auto &existingDependency = i.value();
|
|
|
|
if (static_cast<const Dependency &>(existingDependency).version != affected.version) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto &pkgs = existingDependency.relevantPackages;
|
|
|
|
auto size = pkgs.size();
|
|
|
|
pkgs.merge(affected.newPackages);
|
|
|
|
auto change = pkgs.size() != size;
|
|
|
|
for (auto &toRemove : affected.removedPackages) {
|
|
|
|
change = pkgs.erase(toRemove) || change;
|
|
|
|
}
|
|
|
|
if (change) {
|
|
|
|
txn.put(existingDependency, i.getID());
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto newDependency = DatabaseDependency(dependencyName, affected.version, affected.mode);
|
|
|
|
newDependency.relevantPackages.swap(affected.newPackages);
|
|
|
|
txn.put(newDependency);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PackageUpdaterPrivate::submit(const std::string &libraryName, AffectedLibs::mapped_type &affected, LibraryDependencyStorage::RWTransaction &txn)
|
|
|
|
{
|
|
|
|
for (auto [i, end] = txn.equal_range<0>(libraryName); i != end; ++i) {
|
|
|
|
auto &existingDependency = i.value();
|
|
|
|
auto &pkgs = existingDependency.relevantPackages;
|
|
|
|
auto size = pkgs.size();
|
|
|
|
pkgs.merge(affected.newPackages);
|
|
|
|
auto change = pkgs.size() != size;
|
|
|
|
for (auto &toRemove : affected.removedPackages) {
|
|
|
|
change = pkgs.erase(toRemove) || change;
|
|
|
|
}
|
|
|
|
if (change) {
|
|
|
|
txn.put(existingDependency, i.getID());
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto newDependency = DatabaseLibraryDependency(libraryName);
|
|
|
|
newDependency.relevantPackages.swap(affected.newPackages);
|
|
|
|
txn.put(newDependency);
|
|
|
|
}
|
|
|
|
PackageUpdaterPrivate::AffectedDeps::iterator PackageUpdaterPrivate::findDependency(const Dependency &dependency, AffectedDeps &affected)
|
|
|
|
{
|
|
|
|
for (auto range = affected.equal_range(dependency.name); range.first != range.second; ++range.first) {
|
|
|
|
if (dependency.version == range.first->second.version) {
|
|
|
|
return range.first;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return affected.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
void PackageUpdaterPrivate::addDependency(StorageID packageID, const Dependency &dependency, bool removed, AffectedDeps &affected)
|
|
|
|
{
|
|
|
|
auto iterator = findDependency(dependency, affected);
|
|
|
|
if (iterator == affected.end()) {
|
|
|
|
iterator = affected.insert(AffectedDeps::value_type(dependency.name, AffectedDeps::mapped_type()));
|
|
|
|
iterator->second.version = dependency.version;
|
|
|
|
iterator->second.mode = dependency.mode;
|
|
|
|
}
|
|
|
|
if (!removed) {
|
|
|
|
iterator->second.newPackages.emplace(packageID);
|
|
|
|
} else {
|
|
|
|
iterator->second.removedPackages.emplace(packageID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PackageUpdaterPrivate::addLibrary(StorageID packageID, const std::string &libraryName, bool removed, AffectedLibs &affected)
|
|
|
|
{
|
|
|
|
if (auto &affectedPackages = affected[libraryName]; !removed) {
|
|
|
|
affectedPackages.newPackages.emplace(packageID);
|
|
|
|
} else {
|
|
|
|
affectedPackages.removedPackages.emplace(packageID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PackageUpdater::PackageUpdater(Database &database)
|
|
|
|
: m_database(database)
|
|
|
|
, m_d(std::make_unique<PackageUpdaterPrivate>(*m_database.m_storage))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
PackageUpdater::~PackageUpdater()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
StorageID PackageUpdater::update(const std::shared_ptr<Package> &package)
|
|
|
|
{
|
|
|
|
const auto res = m_database.m_storage->packageCache.store(*m_database.m_storage, m_d->packagesTxn, package);
|
|
|
|
m_d->update(res, package);
|
|
|
|
return res.id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PackageUpdater::commit()
|
|
|
|
{
|
|
|
|
m_d->packagesTxn.commit();
|
|
|
|
{
|
|
|
|
auto txn = m_database.m_storage->providedDeps.getRWTransaction();
|
|
|
|
for (auto &[dependencyName, affected] : m_d->affectedProvidedDeps) {
|
|
|
|
m_d->submit(dependencyName, affected, txn);
|
|
|
|
}
|
|
|
|
txn.commit();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto txn = m_database.m_storage->requiredDeps.getRWTransaction();
|
|
|
|
for (auto &[dependencyName, affected] : m_d->affectedRequiredDeps) {
|
|
|
|
m_d->submit(dependencyName, affected, txn);
|
|
|
|
}
|
|
|
|
txn.commit();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto txn = m_database.m_storage->providedLibs.getRWTransaction();
|
|
|
|
for (auto &[libraryName, affected] : m_d->affectedProvidedLibs) {
|
|
|
|
m_d->submit(libraryName, affected, txn);
|
|
|
|
}
|
|
|
|
txn.commit();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto txn = m_database.m_storage->requiredLibs.getRWTransaction();
|
|
|
|
for (auto &[libraryName, affected] : m_d->affectedRequiredLibs) {
|
|
|
|
m_d->submit(libraryName, affected, txn);
|
|
|
|
}
|
|
|
|
txn.commit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
} // namespace LibPkg
|
|
|
|
|
|
|
|
namespace ReflectiveRapidJSON {
|
|
|
|
|
|
|
|
namespace JsonReflector {
|
|
|
|
|
|
|
|
template <>
|
|
|
|
LIBPKG_EXPORT void push<LibPkg::PackageSearchResult>(
|
|
|
|
const LibPkg::PackageSearchResult &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
|
|
|
|
{
|
|
|
|
// customize serialization of PackageSearchResult to render as if it was pkg itself with an additional db property
|
|
|
|
value.SetObject();
|
|
|
|
auto obj = value.GetObject();
|
|
|
|
auto &pkg = reflectable.pkg;
|
|
|
|
push(pkg->name, "name", obj, allocator);
|
|
|
|
push(pkg->origin, "origin", obj, allocator);
|
|
|
|
push(pkg->timestamp, "timestamp", obj, allocator);
|
|
|
|
push(pkg->version, "version", obj, allocator);
|
|
|
|
push(pkg->description, "description", obj, allocator);
|
|
|
|
if (const auto &pkgInfo = pkg->packageInfo) {
|
|
|
|
push(pkgInfo->arch, "arch", obj, allocator);
|
|
|
|
push(pkgInfo->buildDate, "buildDate", obj, allocator);
|
|
|
|
}
|
2021-08-26 22:56:48 +02:00
|
|
|
if (!pkg->archs.empty()) {
|
|
|
|
push(pkg->archs, "archs", obj, allocator);
|
|
|
|
} else if (const auto &srcInfo = pkg->sourceInfo) {
|
2021-01-25 00:24:31 +01:00
|
|
|
push(srcInfo->archs, "archs", obj, allocator);
|
|
|
|
}
|
|
|
|
if (const auto *const dbInfo = std::get_if<LibPkg::DatabaseInfo>(&reflectable.db)) {
|
|
|
|
if (!dbInfo->name.empty()) {
|
|
|
|
push(dbInfo->name, "db", obj, allocator);
|
|
|
|
}
|
|
|
|
if (!dbInfo->arch.empty()) {
|
|
|
|
push(dbInfo->arch, "dbArch", obj, allocator);
|
|
|
|
}
|
|
|
|
} else if (const auto *const db = std::get<LibPkg::Database *>(reflectable.db)) {
|
|
|
|
push(db->name, "db", obj, allocator);
|
|
|
|
if (!db->arch.empty()) {
|
|
|
|
push(db->arch, "dbArch", obj, allocator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
LIBPKG_EXPORT void pull<LibPkg::PackageSearchResult>(LibPkg::PackageSearchResult &reflectable,
|
|
|
|
const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
|
|
|
|
{
|
|
|
|
if (!value.IsObject()) {
|
|
|
|
if (errors) {
|
|
|
|
errors->reportTypeMismatch<LibPkg::PackageSearchResult>(value.GetType());
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto obj = value.GetObject();
|
|
|
|
auto &pkg = reflectable.pkg;
|
|
|
|
if (!pkg) {
|
|
|
|
pkg = make_shared<LibPkg::Package>();
|
|
|
|
}
|
|
|
|
ReflectiveRapidJSON::JsonReflector::pull(pkg->name, "name", obj, errors);
|
|
|
|
ReflectiveRapidJSON::JsonReflector::pull(pkg->origin, "origin", obj, errors);
|
|
|
|
ReflectiveRapidJSON::JsonReflector::pull(pkg->timestamp, "timestamp", obj, errors);
|
|
|
|
ReflectiveRapidJSON::JsonReflector::pull(pkg->version, "version", obj, errors);
|
|
|
|
ReflectiveRapidJSON::JsonReflector::pull(pkg->description, "description", obj, errors);
|
|
|
|
auto &pkgInfo = pkg->packageInfo;
|
|
|
|
if (!pkgInfo) {
|
|
|
|
pkgInfo = make_unique<LibPkg::PackageInfo>();
|
|
|
|
}
|
|
|
|
ReflectiveRapidJSON::JsonReflector::pull(pkgInfo->arch, "arch", obj, errors);
|
|
|
|
ReflectiveRapidJSON::JsonReflector::pull(pkgInfo->buildDate, "buildDate", obj, errors);
|
2021-08-26 22:56:48 +02:00
|
|
|
ReflectiveRapidJSON::JsonReflector::pull(pkg->archs, "archs", obj, errors);
|
2021-01-25 00:24:31 +01:00
|
|
|
auto &dbInfo = reflectable.db.emplace<LibPkg::DatabaseInfo>();
|
|
|
|
ReflectiveRapidJSON::JsonReflector::pull(dbInfo.name, "db", obj, errors);
|
|
|
|
ReflectiveRapidJSON::JsonReflector::pull(dbInfo.arch, "dbArch", obj, errors);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace JsonReflector
|
|
|
|
|
|
|
|
namespace BinaryReflector {
|
|
|
|
|
|
|
|
template <>
|
2021-07-03 20:00:58 +02:00
|
|
|
LIBPKG_EXPORT void writeCustomType<LibPkg::PackageSearchResult>(
|
|
|
|
BinarySerializer &serializer, const LibPkg::PackageSearchResult &packageSearchResult, BinaryVersion version)
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
|
|
|
if (const auto *const dbInfo = std::get_if<LibPkg::DatabaseInfo>(&packageSearchResult.db)) {
|
2021-07-03 20:00:58 +02:00
|
|
|
serializer.write(dbInfo->name, version);
|
2021-01-25 00:24:31 +01:00
|
|
|
} else if (const auto *const db = std::get<LibPkg::Database *>(packageSearchResult.db)) {
|
2021-07-03 20:00:58 +02:00
|
|
|
serializer.write(db->name, version);
|
2021-01-25 00:24:31 +01:00
|
|
|
} else {
|
2021-07-03 20:00:58 +02:00
|
|
|
serializer.write(std::string(), version);
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-07-03 20:00:58 +02:00
|
|
|
serializer.write(packageSearchResult.pkg, version);
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
2021-07-03 20:00:58 +02:00
|
|
|
LIBPKG_EXPORT BinaryVersion readCustomType<LibPkg::PackageSearchResult>(
|
|
|
|
BinaryDeserializer &deserializer, LibPkg::PackageSearchResult &packageSearchResult, BinaryVersion version)
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
2021-07-03 20:00:58 +02:00
|
|
|
deserializer.read(packageSearchResult.db.emplace<LibPkg::DatabaseInfo>().name, version);
|
|
|
|
deserializer.read(packageSearchResult.pkg, version);
|
|
|
|
return 0;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace BinaryReflector
|
|
|
|
|
|
|
|
} // namespace ReflectiveRapidJSON
|