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>
|
|
|
|
|
2022-05-15 00:27:51 +02:00
|
|
|
#include <iostream>
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
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>;
|
|
|
|
|
2022-03-05 18:55:52 +01:00
|
|
|
explicit PackageUpdaterPrivate(DatabaseStorage &storage, bool clear);
|
2021-12-05 23:40:51 +01:00
|
|
|
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);
|
|
|
|
|
2022-03-05 18:55:52 +01:00
|
|
|
bool clear = false;
|
|
|
|
std::unique_lock<std::mutex> lock;
|
2021-12-05 23:40:51 +01:00
|
|
|
PackageStorage::RWTransaction packagesTxn;
|
2022-04-18 20:39:02 +02:00
|
|
|
std::unordered_set<StorageID> handledIds;
|
2021-12-05 23:40:51 +01:00
|
|
|
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))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-01-31 20:48:02 +01:00
|
|
|
Database::Database(Database &&other) = default;
|
2021-12-05 23:40:51 +01:00
|
|
|
|
|
|
|
Database::~Database()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Database::initStorage(StorageDistribution &storage)
|
|
|
|
{
|
|
|
|
m_storage = storage.forDatabase(name % '@' + arch);
|
|
|
|
}
|
|
|
|
|
2022-05-15 00:27:51 +02:00
|
|
|
void LibPkg::Database::rebuildDb()
|
|
|
|
{
|
|
|
|
std::cerr << "Rebuilding package database \"" << name << "\"\n";
|
|
|
|
auto txn = m_storage->packages.getRWTransaction();
|
|
|
|
auto processed = std::size_t();
|
|
|
|
auto ok = std::size_t();
|
|
|
|
txn.rebuild([count = txn.size(), &processed, &ok](StorageID id, Package *package) mutable {
|
|
|
|
std::cerr << "Processing package " << ++processed << " / " << count << '\n';
|
|
|
|
if (!package) {
|
|
|
|
std::cerr << "Deleting package " << id << ": unable to deserialize\n";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (package->name.empty()) {
|
|
|
|
std::cerr << "Deleting package " << id << ": name is empty\n";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
++ok;
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
if (ok < processed) {
|
|
|
|
std::cerr << "Discarding " << (processed - ok) << " invalid packages from \"" << name << "\".\n";
|
|
|
|
} else {
|
|
|
|
std::cerr << "All " << ok << " packages from \"" << name << "\" are valid.\n";
|
|
|
|
}
|
|
|
|
std::cerr << "Committing changes to package database \"" << name << "\".\n";
|
|
|
|
txn.commit();
|
|
|
|
}
|
|
|
|
|
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";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-15 00:22:03 +01:00
|
|
|
void Database::resetConfiguration(bool keepLocalPaths)
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
|
|
|
path.clear();
|
|
|
|
filesPath.clear();
|
|
|
|
mirrors.clear();
|
|
|
|
usage = DatabaseUsage::None;
|
|
|
|
signatureLevel = SignatureLevel::Default;
|
|
|
|
arch = "x86_64";
|
|
|
|
dependencies.clear();
|
2022-03-15 00:22:03 +01:00
|
|
|
if (!keepLocalPaths) {
|
|
|
|
localPkgDir.clear();
|
|
|
|
localDbDir.clear();
|
|
|
|
}
|
2021-01-25 00:24:31 +01:00
|
|
|
syncFromMirror = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Database::clearPackages()
|
|
|
|
{
|
2022-03-05 18:55:52 +01:00
|
|
|
if (!m_storage) {
|
|
|
|
return;
|
2021-12-05 23:40:51 +01:00
|
|
|
}
|
2022-03-05 18:55:52 +01:00
|
|
|
const auto lock = std::unique_lock(m_storage->updateMutex);
|
|
|
|
m_storage->packageCache.clear(*m_storage);
|
|
|
|
lastUpdate = DateTime();
|
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
|
|
|
|
auto pkgs = std::vector<std::shared_ptr<Package>>();
|
|
|
|
auto txn = m_storage->packages.getROTransaction();
|
2022-02-19 00:11:59 +01:00
|
|
|
for (auto i = txn.begin<std::shared_ptr>(); i != txn.end(); ++i) {
|
2021-12-05 23:40:51 +01:00
|
|
|
if (pred(*this, *i)) {
|
2022-02-19 00:11:59 +01:00
|
|
|
pkgs.emplace_back(std::move(i.getPointer()));
|
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)
|
|
|
|
{
|
2022-03-10 22:45:11 +01:00
|
|
|
if (dependencyName.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
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
|
|
|
{
|
2022-03-10 22:45:11 +01:00
|
|
|
if (dependencyName.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-20 19:50:44 +01:00
|
|
|
void Database::allPackages(const PackageVisitorMove &visitor)
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
2021-12-05 23:40:51 +01:00
|
|
|
auto txn = m_storage->packages.getROTransaction();
|
2022-02-18 19:23:00 +01:00
|
|
|
for (auto i = txn.begin<std::shared_ptr>(); i != txn.end(); ++i) {
|
|
|
|
if (visitor(i.getID(), std::move(i.getPointer()))) {
|
2021-12-05 23:40:51 +01:00
|
|
|
return;
|
|
|
|
}
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-15 03:24:10 +02:00
|
|
|
void Database::allPackages(const PackageVisitorBase &visitor)
|
|
|
|
{
|
|
|
|
auto txn = m_storage->packages.getROTransaction();
|
|
|
|
for (auto i = txn.begin<std::shared_ptr, PackageBase>(); i != txn.end(); ++i) {
|
|
|
|
if (visitor(i.getID(), std::move(i.getPointer()))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-19 00:11:59 +01:00
|
|
|
void LibPkg::Database::allPackagesByName(const PackageVisitorByName &visitor)
|
|
|
|
{
|
|
|
|
auto txn = m_storage->packages.getROTransaction();
|
|
|
|
for (auto i = txn.begin_idx<0, std::shared_ptr>(); i != txn.end(); ++i) {
|
|
|
|
const auto packageName = i.getKey().get<string_view>();
|
2022-05-15 03:24:10 +02:00
|
|
|
if (visitor(packageName, [this, &txn, &i] { return m_storage->packageCache.retrieve(*m_storage, &txn, i.value()); })) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LibPkg::Database::allPackagesByName(const PackageVisitorByNameBase &visitor)
|
|
|
|
{
|
|
|
|
auto txn = m_storage->packages.getROTransaction();
|
|
|
|
for (auto i = txn.begin_idx<0, std::shared_ptr>(); i != txn.end(); ++i) {
|
|
|
|
const auto packageName = i.getKey().get<string_view>();
|
|
|
|
if (visitor(packageName, [&txn, &i] (PackageBase &pkg) { return txn.get(i.value(), pkg); })) {
|
2022-02-19 00:11:59 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-02-20 19:50:44 +01:00
|
|
|
void Database::providingPackages(const Dependency &dependency, bool reverse, const PackageVisitorConst &visitor)
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
2022-03-20 17:21:41 +01:00
|
|
|
if (dependency.name.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
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) {
|
2022-02-18 19:23:00 +01:00
|
|
|
const auto &providedDependency = i.value();
|
|
|
|
const auto &asDependency = static_cast<const Dependency &>(providedDependency);
|
|
|
|
if (!Dependency::matches(dependency.mode, dependency.version, asDependency.version)) {
|
2021-12-05 23:40:51 +01:00
|
|
|
continue;
|
|
|
|
}
|
2022-02-18 19:23:00 +01:00
|
|
|
for (const auto packageID : providedDependency.relevantPackages) {
|
2022-02-20 19:50:44 +01:00
|
|
|
auto res = m_storage->packageCache.retrieve(*m_storage, &packagesTxn, packageID);
|
2022-01-21 20:35:43 +01:00
|
|
|
if (res.pkg && visitor(packageID, res.pkg)) {
|
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
|
|
|
}
|
2021-01-25 00:24:31 +01:00
|
|
|
|
2022-05-31 19:40:12 +02:00
|
|
|
void Database::providingPackagesBase(const Dependency &dependency, bool reverse, const PackageVisitorBase &visitor)
|
|
|
|
{
|
|
|
|
if (dependency.name.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto providesTxn = (reverse ? m_storage->requiredDeps : m_storage->providedDeps).getROTransaction();
|
|
|
|
auto packagesTxn = m_storage->packages.getROTransaction();
|
|
|
|
auto package = std::shared_ptr<PackageBase>();
|
|
|
|
for (auto [i, end] = providesTxn.equal_range<0>(dependency.name); i != end; ++i) {
|
|
|
|
const auto &providedDependency = i.value();
|
|
|
|
const auto &asDependency = static_cast<const Dependency &>(providedDependency);
|
|
|
|
if (!Dependency::matches(dependency.mode, dependency.version, asDependency.version)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (const auto packageID : providedDependency.relevantPackages) {
|
|
|
|
if (!package) {
|
|
|
|
package = std::make_shared<PackageBase>();
|
|
|
|
} else {
|
|
|
|
package->clear();
|
|
|
|
}
|
|
|
|
;
|
|
|
|
if (packagesTxn.get<PackageBase>(packageID, *package) && visitor(packageID, std::move(package))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-20 19:50:44 +01:00
|
|
|
void Database::providingPackages(const std::string &libraryName, bool reverse, const PackageVisitorConst &visitor)
|
2021-12-05 23:40:51 +01:00
|
|
|
{
|
2022-03-20 17:21:41 +01:00
|
|
|
if (libraryName.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
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) {
|
2022-02-20 19:50:44 +01:00
|
|
|
auto res = m_storage->packageCache.retrieve(*m_storage, &packagesTxn, packageID);
|
2022-01-21 20:35:43 +01:00
|
|
|
if (res.pkg && visitor(packageID, res.pkg)) {
|
2021-12-05 23:40:51 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
2022-05-31 19:40:12 +02:00
|
|
|
void Database::providingPackagesBase(const std::string &libraryName, bool reverse, const PackageVisitorBase &visitor)
|
|
|
|
{
|
|
|
|
if (libraryName.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto providesTxn = (reverse ? m_storage->requiredLibs : m_storage->providedLibs).getROTransaction();
|
|
|
|
auto packagesTxn = m_storage->packages.getROTransaction();
|
|
|
|
auto package = std::shared_ptr<PackageBase>();
|
|
|
|
for (auto [i, end] = providesTxn.equal_range<0>(libraryName); i != end; ++i) {
|
|
|
|
for (const auto packageID : i->relevantPackages) {
|
|
|
|
if (packagesTxn.get<PackageBase>(packageID, *package) && visitor(packageID, std::move(package))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2022-03-20 17:21:41 +01:00
|
|
|
if (dependency.name.empty()) {
|
|
|
|
return false;
|
|
|
|
}
|
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
|
|
|
|
{
|
2022-03-20 17:21:41 +01:00
|
|
|
if (libraryName.empty()) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
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)
|
|
|
|
{
|
2022-01-20 23:33:02 +01:00
|
|
|
return m_storage->packageCache.retrieve(*m_storage, packageID).pkg;
|
2021-12-05 23:40:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-05-15 03:24:10 +02:00
|
|
|
StorageID Database::findBasePackageWithID(const std::string &packageName, PackageBase &basePackage)
|
|
|
|
{
|
|
|
|
auto txn = m_storage->packages.getROTransaction();
|
|
|
|
return txn.get<0, PackageBase>(packageName, basePackage);
|
|
|
|
}
|
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
void Database::removePackage(const std::string &packageName)
|
|
|
|
{
|
2022-03-05 18:55:52 +01:00
|
|
|
const auto lock = std::unique_lock(m_storage->updateMutex);
|
2021-12-05 23:40:51 +01:00
|
|
|
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
|
|
|
{
|
2022-03-10 22:45:11 +01:00
|
|
|
if (package->name.empty()) {
|
|
|
|
return 0;
|
|
|
|
}
|
2022-03-05 18:55:52 +01:00
|
|
|
const auto lock = std::unique_lock(m_storage->updateMutex);
|
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
|
|
|
}
|
2022-01-19 23:27:14 +01:00
|
|
|
if (res.oldEntry) {
|
|
|
|
removePackageDependencies(res.id, res.oldEntry);
|
2021-12-05 23:40:51 +01:00
|
|
|
}
|
|
|
|
addPackageDependencies(res.id, package);
|
|
|
|
return res.id;
|
|
|
|
}
|
|
|
|
|
|
|
|
StorageID Database::forceUpdatePackage(const std::shared_ptr<Package> &package)
|
|
|
|
{
|
2022-03-10 22:45:11 +01:00
|
|
|
if (package->name.empty()) {
|
|
|
|
return 0;
|
|
|
|
}
|
2022-03-05 18:55:52 +01:00
|
|
|
const auto lock = std::unique_lock(m_storage->updateMutex);
|
2021-12-05 23:40:51 +01:00
|
|
|
const auto res = m_storage->packageCache.store(*m_storage, package, true);
|
2022-01-19 23:27:14 +01:00
|
|
|
if (res.oldEntry) {
|
|
|
|
removePackageDependencies(res.id, res.oldEntry);
|
2021-12-05 23:40:51 +01:00
|
|
|
}
|
|
|
|
addPackageDependencies(res.id, package);
|
|
|
|
return res.id;
|
|
|
|
}
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
/*!
|
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);
|
2022-05-15 03:24:10 +02:00
|
|
|
unresolvedPackages[GenericPackageSpec(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;
|
|
|
|
}
|
|
|
|
|
2022-03-03 22:40:48 +01:00
|
|
|
// skip DLLs known to be provided by Windows (but can not be detected as provides of mingw-w64-crt)
|
|
|
|
if (requiredLib.name.find("api-ms-win") != std::string::npos && requiredLib.name.ends_with(".dll")) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
// 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);
|
2022-05-15 03:24:10 +02:00
|
|
|
unresolvedPackages[GenericPackageSpec(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();
|
2022-02-20 19:50:44 +01:00
|
|
|
allPackages([&](StorageID myPackageID, std::shared_ptr<Package> &&package) {
|
2021-01-31 19:56:40 +01:00
|
|
|
auto regularName = std::string();
|
2022-02-20 19:50:44 +01:00
|
|
|
auto used = false;
|
2021-01-31 19:56:40 +01:00
|
|
|
if (options & UpdateCheckOptions::ConsiderRegularPackage) {
|
2022-01-21 20:35:43 +01:00
|
|
|
const auto decomposedName = package->decomposeName();
|
2021-01-31 19:56:40 +01:00
|
|
|
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) {
|
2022-01-21 20:35:43 +01:00
|
|
|
const auto [updatePackageID, updatePackage] = updateSource->findPackageWithID(package->name);
|
2021-12-05 23:40:51 +01:00
|
|
|
if (!updatePackage) {
|
2021-01-25 00:24:31 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
foundPackage = true;
|
2022-01-21 20:35:43 +01:00
|
|
|
const auto versionDiff = package->compareVersion(*updatePackage);
|
2021-01-25 00:24:31 +01:00
|
|
|
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(
|
2022-01-21 20:35:43 +01:00
|
|
|
PackageSearchResult(*this, package, myPackageID), PackageSearchResult(*updateSource, updatePackage, updatePackageID));
|
2022-02-20 19:50:44 +01:00
|
|
|
used = true;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!foundPackage) {
|
2022-01-21 20:35:43 +01:00
|
|
|
results.orphans.emplace_back(PackageSearchResult(*this, package, myPackageID));
|
2022-02-20 19:50:44 +01:00
|
|
|
used = true;
|
|
|
|
}
|
|
|
|
if (!regularName.empty()) {
|
|
|
|
for (auto *const updateSource : updateSources) {
|
|
|
|
const auto [updatePackageID, updatePackage] = updateSource->findPackageWithID(regularName);
|
|
|
|
if (!updatePackage) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const auto versionDiff = package->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) {
|
|
|
|
list->emplace_back(
|
|
|
|
PackageSearchResult(*this, package, myPackageID), PackageSearchResult(*updateSource, updatePackage, updatePackageID));
|
|
|
|
used = true;
|
|
|
|
}
|
2021-01-31 19:56:40 +01:00
|
|
|
}
|
|
|
|
}
|
2022-02-20 19:50:44 +01:00
|
|
|
if (used) {
|
|
|
|
package.reset();
|
|
|
|
}
|
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");
|
|
|
|
}
|
|
|
|
|
2022-03-05 18:55:52 +01:00
|
|
|
PackageUpdaterPrivate::PackageUpdaterPrivate(DatabaseStorage &storage, bool clear)
|
|
|
|
: clear(clear)
|
|
|
|
, lock(storage.updateMutex)
|
|
|
|
, packagesTxn(storage.packages.getRWTransaction())
|
2021-12-05 23:40:51 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void PackageUpdaterPrivate::update(const PackageCache::StoreResult &res, const std::shared_ptr<Package> &package)
|
|
|
|
{
|
2022-03-10 22:45:11 +01:00
|
|
|
if (!res.id) {
|
|
|
|
return;
|
|
|
|
}
|
2022-04-18 20:39:02 +02:00
|
|
|
handledIds.emplace(res.id);
|
2021-12-05 23:40:51 +01:00
|
|
|
update(res.id, false, package);
|
2022-03-05 18:55:52 +01:00
|
|
|
if (!clear && res.oldEntry) {
|
2022-01-19 23:27:14 +01:00
|
|
|
update(res.id, true, res.oldEntry);
|
2021-12-05 23:40:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PackageUpdaterPrivate::update(const StorageID packageID, bool removed, const std::shared_ptr<Package> &package)
|
|
|
|
{
|
|
|
|
addDependency(packageID, Dependency(package->name, package->version), removed, affectedProvidedDeps);
|
2022-03-01 00:43:06 +01:00
|
|
|
for (const auto &dependency : package->provides) {
|
|
|
|
addDependency(packageID, dependency, removed, affectedProvidedDeps);
|
2021-12-05 23:40:51 +01:00
|
|
|
}
|
|
|
|
for (const auto &lib : package->libprovides) {
|
|
|
|
addLibrary(packageID, lib, removed, affectedProvidedLibs);
|
|
|
|
}
|
2022-03-01 00:43:06 +01:00
|
|
|
for (const auto &dependency : package->dependencies) {
|
|
|
|
addDependency(packageID, dependency, removed, affectedRequiredDeps);
|
2021-12-05 23:40:51 +01:00
|
|
|
}
|
2022-03-01 00:43:06 +01:00
|
|
|
for (const auto &dependency : package->optionalDependencies) {
|
|
|
|
addDependency(packageID, dependency, removed, affectedRequiredDeps);
|
2021-12-05 23:40:51 +01:00
|
|
|
}
|
|
|
|
for (const auto &lib : package->libdepends) {
|
|
|
|
addLibrary(packageID, lib, removed, affectedRequiredLibs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-04 17:57:11 +01:00
|
|
|
template <typename Dependency, typename MappedType, typename Txn>
|
|
|
|
static void submitExistingDependency(StorageID id, Dependency &existingDependency, MappedType &affected, Txn &txn)
|
|
|
|
{
|
|
|
|
auto &pkgs = existingDependency.relevantPackages;
|
|
|
|
auto change = false;
|
|
|
|
for (auto &toRemove : affected.removedPackages) {
|
|
|
|
change = pkgs.erase(toRemove) || change;
|
|
|
|
}
|
|
|
|
auto size = pkgs.size();
|
|
|
|
pkgs.merge(affected.newPackages);
|
|
|
|
change = change || pkgs.size() != size;
|
|
|
|
if (change) {
|
|
|
|
txn.put(existingDependency, id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
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;
|
|
|
|
}
|
2022-02-04 17:57:11 +01:00
|
|
|
submitExistingDependency(i.getID(), existingDependency, affected, txn);
|
2021-12-05 23:40:51 +01:00
|
|
|
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) {
|
2022-02-04 17:57:11 +01:00
|
|
|
submitExistingDependency(i.getID(), i.value(), affected, txn);
|
2021-12-05 23:40:51 +01:00
|
|
|
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)
|
|
|
|
{
|
2022-03-10 22:45:11 +01:00
|
|
|
if (dependency.name.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
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)
|
|
|
|
{
|
2022-03-10 22:45:11 +01:00
|
|
|
if (libraryName.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
if (auto &affectedPackages = affected[libraryName]; !removed) {
|
|
|
|
affectedPackages.newPackages.emplace(packageID);
|
|
|
|
} else {
|
|
|
|
affectedPackages.removedPackages.emplace(packageID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-05 18:55:52 +01:00
|
|
|
PackageUpdater::PackageUpdater(Database &database, bool clear)
|
2021-12-05 23:40:51 +01:00
|
|
|
: m_database(database)
|
2022-03-05 18:55:52 +01:00
|
|
|
, m_d(std::make_unique<PackageUpdaterPrivate>(*m_database.m_storage, clear))
|
2021-12-05 23:40:51 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
PackageUpdater::~PackageUpdater()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-05-15 03:24:10 +02:00
|
|
|
PackageSpec LibPkg::PackageUpdater::findPackageWithID(const std::string &packageName)
|
2022-01-31 20:51:45 +01:00
|
|
|
{
|
|
|
|
return m_database.m_storage->packageCache.retrieve(*m_database.m_storage, &m_d->packagesTxn, packageName);
|
|
|
|
}
|
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
StorageID PackageUpdater::update(const std::shared_ptr<Package> &package)
|
|
|
|
{
|
2022-03-05 18:55:52 +01:00
|
|
|
const auto &storage = m_database.m_storage;
|
|
|
|
const auto res = storage->packageCache.store(*m_database.m_storage, m_d->packagesTxn, package);
|
2021-12-05 23:40:51 +01:00
|
|
|
m_d->update(res, package);
|
|
|
|
return res.id;
|
|
|
|
}
|
|
|
|
|
2022-04-20 22:47:10 +02:00
|
|
|
bool PackageUpdater::insertFromDatabaseFile(const std::string &databaseFilePath)
|
|
|
|
{
|
|
|
|
LibPkg::Package::fromDatabaseFile(databaseFilePath, [this](const std::shared_ptr<LibPkg::Package> &package) {
|
|
|
|
if (const auto [id, existingPackage] = findPackageWithID(package->name); existingPackage) {
|
|
|
|
package->addDepsAndProvidesFromOtherPackage(*existingPackage);
|
|
|
|
}
|
|
|
|
update(package);
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-12-05 23:40:51 +01:00
|
|
|
void PackageUpdater::commit()
|
|
|
|
{
|
2022-03-05 18:55:52 +01:00
|
|
|
const auto &storage = m_database.m_storage;
|
2022-04-18 20:39:02 +02:00
|
|
|
auto &pkgTxn = m_d->packagesTxn;
|
|
|
|
if (m_d->clear) {
|
|
|
|
const auto &toPreserve = m_d->handledIds;
|
|
|
|
for (auto i = pkgTxn.begin<std::unique_ptr>(); i != pkgTxn.end(); ++i) {
|
|
|
|
if (!toPreserve.contains(i.getID())) {
|
|
|
|
i.del();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pkgTxn.commit();
|
2021-12-05 23:40:51 +01:00
|
|
|
{
|
2022-03-05 18:55:52 +01:00
|
|
|
auto txn = storage->providedDeps.getRWTransaction();
|
|
|
|
if (m_d->clear) {
|
|
|
|
txn.clear();
|
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
for (auto &[dependencyName, affected] : m_d->affectedProvidedDeps) {
|
|
|
|
m_d->submit(dependencyName, affected, txn);
|
|
|
|
}
|
|
|
|
txn.commit();
|
|
|
|
}
|
|
|
|
{
|
2022-03-05 18:55:52 +01:00
|
|
|
auto txn = storage->requiredDeps.getRWTransaction();
|
|
|
|
if (m_d->clear) {
|
|
|
|
txn.clear();
|
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
for (auto &[dependencyName, affected] : m_d->affectedRequiredDeps) {
|
|
|
|
m_d->submit(dependencyName, affected, txn);
|
|
|
|
}
|
|
|
|
txn.commit();
|
|
|
|
}
|
|
|
|
{
|
2022-03-05 18:55:52 +01:00
|
|
|
auto txn = storage->providedLibs.getRWTransaction();
|
|
|
|
if (m_d->clear) {
|
|
|
|
txn.clear();
|
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
for (auto &[libraryName, affected] : m_d->affectedProvidedLibs) {
|
|
|
|
m_d->submit(libraryName, affected, txn);
|
|
|
|
}
|
|
|
|
txn.commit();
|
|
|
|
}
|
|
|
|
{
|
2022-03-05 18:55:52 +01:00
|
|
|
auto txn = storage->requiredLibs.getRWTransaction();
|
|
|
|
if (m_d->clear) {
|
|
|
|
txn.clear();
|
|
|
|
}
|
2021-12-05 23:40:51 +01:00
|
|
|
for (auto &[libraryName, affected] : m_d->affectedRequiredLibs) {
|
|
|
|
m_d->submit(libraryName, affected, txn);
|
|
|
|
}
|
|
|
|
txn.commit();
|
|
|
|
}
|
2022-03-05 18:55:52 +01:00
|
|
|
m_d->lock.unlock();
|
2021-12-05 23:40:51 +01:00
|
|
|
}
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
} // namespace LibPkg
|
|
|
|
|
|
|
|
namespace ReflectiveRapidJSON {
|
|
|
|
|
|
|
|
namespace JsonReflector {
|
|
|
|
|
|
|
|
template <>
|
2022-03-05 18:55:52 +01:00
|
|
|
void push<LibPkg::PackageSearchResult>(
|
2021-01-25 00:24:31 +01:00
|
|
|
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);
|
2022-05-15 03:24:10 +02:00
|
|
|
if (!pkg->arch.empty()) {
|
|
|
|
push(pkg->arch, "arch", obj, allocator);
|
|
|
|
}
|
|
|
|
if (!pkg->buildDate.isNull()) {
|
|
|
|
push(pkg->buildDate, "buildDate", obj, allocator);
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2021-08-26 22:56:48 +02:00
|
|
|
if (!pkg->archs.empty()) {
|
|
|
|
push(pkg->archs, "archs", obj, allocator);
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
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 <>
|
2022-03-05 18:55:52 +01:00
|
|
|
void pull<LibPkg::PackageSearchResult>(LibPkg::PackageSearchResult &reflectable,
|
2021-01-25 00:24:31 +01:00
|
|
|
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);
|
2022-05-15 03:24:10 +02:00
|
|
|
ReflectiveRapidJSON::JsonReflector::pull(pkg->arch, "arch", obj, errors);
|
|
|
|
ReflectiveRapidJSON::JsonReflector::pull(pkg->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);
|
|
|
|
}
|
|
|
|
|
2022-05-15 03:24:10 +02:00
|
|
|
template <>
|
|
|
|
void push<LibPkg::PackageBaseSearchResult>(
|
|
|
|
const LibPkg::PackageBaseSearchResult &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
|
|
|
|
{
|
|
|
|
// serialize PackageBaseSearchResult object in accordance with PackageSearchResult
|
|
|
|
value.SetObject();
|
|
|
|
auto obj = value.GetObject();
|
|
|
|
if (auto &pkg = reflectable.pkg) {
|
|
|
|
push(*pkg, obj, allocator);
|
|
|
|
}
|
|
|
|
if (const auto &db = reflectable.db) {
|
|
|
|
push(db->name, "db", obj, allocator);
|
|
|
|
if (!db->arch.empty()) {
|
|
|
|
push(db->arch, "dbArch", obj, allocator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
void pull<LibPkg::PackageBaseSearchResult>(LibPkg::PackageBaseSearchResult &reflectable,
|
|
|
|
const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
|
|
|
|
{
|
|
|
|
CPP_UTILITIES_UNUSED(reflectable)
|
|
|
|
CPP_UTILITIES_UNUSED(value)
|
|
|
|
CPP_UTILITIES_UNUSED(errors)
|
|
|
|
throw std::logic_error("Attempt to deserialize LibPkg::PackageBaseSearchResult");
|
|
|
|
}
|
|
|
|
|
2022-03-05 18:55:52 +01:00
|
|
|
template <>
|
|
|
|
void push<LibPkg::AtomicDateTime>(
|
|
|
|
const LibPkg::AtomicDateTime &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
|
|
|
|
{
|
|
|
|
push<CppUtilities::DateTime>(reflectable.load(), value, allocator);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
void pull<LibPkg::AtomicDateTime>(LibPkg::AtomicDateTime &reflectable,
|
|
|
|
const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
|
|
|
|
{
|
|
|
|
auto d = CppUtilities::DateTime();
|
|
|
|
pull<CppUtilities::DateTime>(d, value, errors);
|
|
|
|
reflectable.store(d);
|
|
|
|
}
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
} // namespace JsonReflector
|
|
|
|
|
|
|
|
namespace BinaryReflector {
|
|
|
|
|
|
|
|
template <>
|
2022-03-05 18:55:52 +01:00
|
|
|
void writeCustomType<LibPkg::PackageSearchResult>(
|
2021-07-03 20:00:58 +02:00
|
|
|
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 <>
|
2022-03-05 18:55:52 +01:00
|
|
|
BinaryVersion readCustomType<LibPkg::PackageSearchResult>(
|
2021-07-03 20:00:58 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-03-05 18:55:52 +01:00
|
|
|
template <> void writeCustomType<LibPkg::AtomicDateTime>(BinarySerializer &serializer, const LibPkg::AtomicDateTime &dateTime, BinaryVersion version)
|
|
|
|
{
|
|
|
|
writeCustomType<CppUtilities::DateTime>(serializer, dateTime.load(), version);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
BinaryVersion readCustomType<LibPkg::AtomicDateTime>(BinaryDeserializer &deserializer, LibPkg::AtomicDateTime &dateTime, BinaryVersion version)
|
|
|
|
{
|
|
|
|
auto d = CppUtilities::DateTime();
|
|
|
|
auto v = readCustomType<CppUtilities::DateTime>(deserializer, d, version);
|
|
|
|
dateTime.store(d);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
} // namespace BinaryReflector
|
|
|
|
|
|
|
|
} // namespace ReflectiveRapidJSON
|