#ifndef LIBPKG_DATA_DATABASE_H #define LIBPKG_DATA_DATABASE_H #include "./package.h" #include "./siglevel.h" #include "./storagefwd.h" #include "../global.h" #include #include #include #include #include #include namespace LibPkg { struct Config; struct Database; struct LIBPKG_EXPORT DatabaseInfo { std::string name; std::string arch; }; struct LIBPKG_EXPORT PackageSearchResult { PackageSearchResult(); PackageSearchResult(Database &database, const std::shared_ptr &package, StorageID id); PackageSearchResult(Database &database, std::shared_ptr &&package, StorageID id); PackageSearchResult(Database &database, Package &&package, StorageID id); bool operator==(const PackageSearchResult &other) const; /// \brief The related database. /// \remarks /// - The find functions always uses Database* and it is guaranteed to be never nullptr. /// - The deserialization functions always use DatabaseInfo and the values might be empty if the source was empty. /// - The serialization functions can cope with both alternatives. std::variant db; std::shared_ptr pkg; StorageID id; }; struct LIBPKG_EXPORT PackageBaseSearchResult { PackageBaseSearchResult() = default; PackageBaseSearchResult(const Database &database, const PackageBase &package, StorageID id); /// \brief The related database. /// \remarks /// - The find functions always uses Database* and it is guaranteed to be never nullptr. /// - The deserialization functions always use DatabaseInfo and the values might be empty if the source was empty. /// - The serialization functions can cope with both alternatives. const Database *db = nullptr; const PackageBase *pkg = nullptr; StorageID id = 0; }; /*! * \brief The DatabaseUsage enum specifies the usage of a database within pacman. */ enum class DatabaseUsage { None = 0, Sync = (1 << 0), /*! The database is used when synchronizing. */ Search = (1 << 1), /*! The database is used when searching. */ Install = (1 << 2), /*! The database is used to install packages. */ Upgrade = (1 << 3), /*! The database is used to upgrade packages. */ All = (1 << 4) - 1, /*! The database is used for everything. */ }; enum class UpdateCheckOptions { None = 0, ConsiderRegularPackage = (1 << 0), }; } // namespace LibPkg CPP_UTILITIES_MARK_FLAG_ENUM_CLASS(LibPkg, LibPkg::DatabaseUsage) CPP_UTILITIES_MARK_FLAG_ENUM_CLASS(LibPkg, LibPkg::UpdateCheckOptions) namespace LibPkg { struct LIBPKG_EXPORT PackageUpdate : public ReflectiveRapidJSON::JsonSerializable, public ReflectiveRapidJSON::BinarySerializable { PackageUpdate(PackageSearchResult &&oldVersion = PackageSearchResult(), PackageSearchResult &&newVersion = PackageSearchResult()) : oldVersion(oldVersion) , newVersion(newVersion) { } PackageSearchResult oldVersion; PackageSearchResult newVersion; }; struct LIBPKG_EXPORT PackageUpdates : public ReflectiveRapidJSON::JsonSerializable, public ReflectiveRapidJSON::BinarySerializable { std::vector versionUpdates; std::vector packageUpdates; std::vector downgrades; std::vector orphans; }; struct LIBPKG_EXPORT PackageLocation { std::filesystem::path pathWithinRepo; std::filesystem::path storageLocation; std::optional error; bool exists = false; }; struct LIBPKG_EXPORT UnresolvedDependencies : public ReflectiveRapidJSON::JsonSerializable, public ReflectiveRapidJSON::BinarySerializable { std::vector deps; std::vector libs; }; struct PackageUpdaterPrivate; struct LIBPKG_EXPORT PackageUpdater { explicit PackageUpdater(Database &database, bool clear = false); ~PackageUpdater(); PackageSpec findPackageWithID(const std::string &packageName); StorageID update(const std::shared_ptr &package); bool insertFromDatabaseFile(const std::string &databaseFilePath); void commit(); private: Database &m_database; std::unique_ptr m_d; }; struct AtomicDateTime : public std::atomic { AtomicDateTime(CppUtilities::DateTime value = CppUtilities::DateTime()) : std::atomic(value) { } AtomicDateTime(AtomicDateTime &&other) : std::atomic(other.load()) { } AtomicDateTime &operator=(AtomicDateTime &&other) { store(other.load()); return *this; } }; struct LIBPKG_EXPORT Database : public ReflectiveRapidJSON::JsonSerializable, public ReflectiveRapidJSON::BinarySerializable { using PackageVisitorBase = std::function &&)>; // package is invalidated/reused unless moved from!!! using PackageVisitorMove = std::function &&)>; // package is invalidated/reused unless moved from!!! using PackageVisitorConst = std::function &)>; using PackageVisitorByName = std::function &)>; using PackageVisitorByNameBase = std::function &)>; friend struct PackageUpdater; explicit Database(const std::string &name = std::string(), const std::string &path = std::string()); explicit Database(std::string &&name, std::string &&path); Database(Database &&other); ~Database(); Database &operator=(Database &&rhs) = default; void initStorage(StorageDistribution &storage); void rebuildDb(); void deducePathsFromLocalDirs(); void resetConfiguration(bool keepLocalPaths = false); void clearPackages(); void loadPackagesFromConfiguredPaths(bool withFiles = false, bool force = false); void loadPackages(const std::string &databaseFilePath, CppUtilities::DateTime lastModified); static bool isFileRelevant(const char *filePath, const char *fileName, mode_t); std::vector> findPackages(const std::function &pred); void allPackages(const PackageVisitorMove &visitor); void allPackages(const PackageVisitorBase &visitor); void allPackagesByName(const PackageVisitorByName &visitor); void allPackagesByName(const PackageVisitorByNameBase &visitor); std::size_t packageCount() const; void providingPackages(const Dependency &dependency, bool reverse, const PackageVisitorConst &visitor); void providingPackages(const std::string &libraryName, bool reverse, const PackageVisitorConst &visitor); bool provides(const Dependency &dependency, bool reverse = false) const; bool provides(const std::string &libraryName, bool reverse = false) const; std::shared_ptr findPackage(StorageID packageID); std::shared_ptr findPackage(const std::string &packageName); PackageSpec findPackageWithID(const std::string &packageName); StorageID findBasePackageWithID(const std::string &packageName, PackageBase &basePackage); void removePackage(const std::string &packageName); StorageID updatePackage(const std::shared_ptr &package); StorageID forceUpdatePackage(const std::shared_ptr &package); std::unordered_map detectUnresolvedPackages(Config &config, const std::vector> &newPackages, const DependencySet &removedPackages, const std::unordered_set &depsToIgnore = std::unordered_set(), const std::unordered_set &libsToIgnore = std::unordered_set()); PackageUpdates checkForUpdates(const std::vector &updateSources, UpdateCheckOptions options = UpdateCheckOptions::None); PackageLocation locatePackage(const std::string &packageName) const; std::string filesPathFromRegularPath() const; private: void removePackageDependencies(StorageID packageID, const std::shared_ptr &package); void addPackageDependencies(StorageID packageID, const std::shared_ptr &package); public: std::string name; std::string path; std::string filesPath; std::vector mirrors; DatabaseUsage usage = DatabaseUsage::None; SignatureLevel signatureLevel = SignatureLevel::Default; std::string arch = "x86_64"; std::vector dependencies; std::string localPkgDir; std::string localDbDir; AtomicDateTime lastUpdate; bool syncFromMirror = false; bool toBeDiscarded = false; private: std::unique_ptr m_storage; }; inline PackageSearchResult::PackageSearchResult() : db(nullptr) , id(0) { } inline PackageSearchResult::PackageSearchResult(Database &database, const std::shared_ptr &package, StorageID id) : db(&database) , pkg(package) , id(id) { } inline PackageSearchResult::PackageSearchResult(Database &database, std::shared_ptr &&package, StorageID id) : db(&database) , pkg(std::move(package)) , id(id) { } inline PackageSearchResult::PackageSearchResult(Database &database, Package &&package, StorageID id) : db(&database) , pkg(std::make_shared(std::move(package))) , id(id) { } inline bool PackageSearchResult::operator==(const PackageSearchResult &other) const { const auto *const *const db1 = std::get_if(&db); const auto *const *const db2 = std::get_if(&other.db); if (!db1 || !db2) { return false; } return ((!*db1 && !*db2) || (*db1 && *db2 && (**db1).name == (**db2).name)) && pkg == other.pkg; } inline PackageBaseSearchResult::PackageBaseSearchResult(const Database &database, const PackageBase &package, StorageID id) : db(&database) , pkg(&package) , id(id) { } } // namespace LibPkg namespace std { template <> struct hash { std::size_t operator()(const LibPkg::PackageSearchResult &res) const { using std::hash; const std::string *dbName = nullptr; if (const auto *const dbInfo = std::get_if(&res.db)) { dbName = &dbInfo->name; } else if (const auto *const db = std::get(res.db)) { dbName = &db->name; } return ((hash()(dbName ? *dbName : string()) ^ (hash>()(res.pkg) << 1)) >> 1); } }; } // namespace std namespace ReflectiveRapidJSON { namespace JsonReflector { // declare custom (de)serialization for PackageSearchResult template <> LIBPKG_EXPORT void push( const LibPkg::PackageSearchResult &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator); template <> LIBPKG_EXPORT void pull(LibPkg::PackageSearchResult &reflectable, const RAPIDJSON_NAMESPACE::GenericValue> &value, JsonDeserializationErrors *errors); // declare custom (de)serialization for PackageBaseSearchResult template <> LIBPKG_EXPORT void push( const LibPkg::PackageBaseSearchResult &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator); template <> LIBPKG_EXPORT void pull(LibPkg::PackageBaseSearchResult &reflectable, const RAPIDJSON_NAMESPACE::GenericValue> &value, JsonDeserializationErrors *errors); // declare custom (de)serialization for AtomicDateTime template <> LIBPKG_EXPORT void push( const LibPkg::AtomicDateTime &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator); template <> LIBPKG_EXPORT void pull(LibPkg::AtomicDateTime &reflectable, const RAPIDJSON_NAMESPACE::GenericValue> &value, JsonDeserializationErrors *errors); } // namespace JsonReflector namespace BinaryReflector { template <> LIBPKG_EXPORT void writeCustomType( BinarySerializer &serializer, const LibPkg::PackageSearchResult &packageSearchResult, BinaryVersion version); template <> LIBPKG_EXPORT BinaryVersion readCustomType( BinaryDeserializer &deserializer, LibPkg::PackageSearchResult &packageSearchResult, BinaryVersion version); template <> LIBPKG_EXPORT void writeCustomType( BinarySerializer &serializer, const LibPkg::AtomicDateTime &packageSearchResult, BinaryVersion version); template <> LIBPKG_EXPORT BinaryVersion readCustomType( BinaryDeserializer &deserializer, LibPkg::AtomicDateTime &packageSearchResult, BinaryVersion version); } // namespace BinaryReflector } // namespace ReflectiveRapidJSON #endif // LIBPKG_DATA_DATABASE_H