From 7a572b703b7207bb9bc7b2d8d3443152aac42d19 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 17 Jan 2023 10:51:29 +0200 Subject: Continue sketching system package manager interface --- bpkg/host-os-release.hxx | 6 ++- bpkg/pkg-build.cxx | 3 ++ bpkg/system-package-manager-debian.cxx | 28 ++++++++++++ bpkg/system-package-manager-debian.hxx | 35 +++++++++++++++ bpkg/system-package-manager.cxx | 4 ++ bpkg/system-package-manager.hxx | 80 ++++++++++++++++++++++++++++++---- 6 files changed, 145 insertions(+), 11 deletions(-) create mode 100644 bpkg/system-package-manager-debian.cxx create mode 100644 bpkg/system-package-manager-debian.hxx diff --git a/bpkg/host-os-release.hxx b/bpkg/host-os-release.hxx index c2d6672..3f85cb2 100644 --- a/bpkg/host-os-release.hxx +++ b/bpkg/host-os-release.hxx @@ -47,8 +47,10 @@ namespace bpkg string variant; // VARIANT }; - // Return the release information for the specified host or nullopt if - // the specific host is unknown/unsupported. + // Return the release information for the specified host or nullopt if the + // specific host is unknown/unsupported. Note that "host" here implies that + // we may be examining files, environment variables, etc., of the machine we + // are running on. // optional host_os_release (const target_triplet& host); diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx index 61bd1da..f452d50 100644 --- a/bpkg/pkg-build.cxx +++ b/bpkg/pkg-build.cxx @@ -1762,6 +1762,9 @@ namespace bpkg // no_db_system_repository or some such, which add_system_package() // can use if db == NULL. // + // @@ Actually, I think this should just be assert() since the only + // source of authoritative information is system package manager + // and it caches its results. } return vc; diff --git a/bpkg/system-package-manager-debian.cxx b/bpkg/system-package-manager-debian.cxx new file mode 100644 index 0000000..1e43206 --- /dev/null +++ b/bpkg/system-package-manager-debian.cxx @@ -0,0 +1,28 @@ +// file : bpkg/system-package-manager-debian.cxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#include + +#include + +namespace bpkg +{ + // Do we use apt or apt-get? From apt(8): + // + // "The apt(8) commandline is designed as an end-user tool and it may change + // behavior between versions. [...] + // + // All features of apt(8) are available in dedicated APT tools like + // apt-get(8) and apt-cache(8) as well. [...] So you should prefer using + // these commands (potentially with some additional options enabled) in + // your scripts as they keep backward compatibility as much as possible." + + // @@ We actually need to fetch if some are not installed to get their + // versions. We can do it as part of the call, no? Keep track if + // already fetched. + + // @@ We may map multiple our packages to the same system package + // (e.g., openssl-devel) so probably should track the status of + // individual system packages. What if we "installed any version" + // first and then need to install specific? +} diff --git a/bpkg/system-package-manager-debian.hxx b/bpkg/system-package-manager-debian.hxx new file mode 100644 index 0000000..5b1f764 --- /dev/null +++ b/bpkg/system-package-manager-debian.hxx @@ -0,0 +1,35 @@ +// file : bpkg/system-package-manager-debian.hxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#ifndef BPKG_SYSTEM_PACKAGE_MANAGER_DEBIAN_HXX +#define BPKG_SYSTEM_PACKAGE_MANAGER_DEBIAN_HXX + +#include +#include + +#include + +namespace bpkg +{ + // The system package manager implementation for Debian and alike (Ubuntu, + // etc) using the APT frontend. + // + class system_package_manager_debian: public system_package_manager + { + public: + virtual optional + pkg_status (const package_name&, + const available_packages*, + bool install, + bool fetch) override; + + public: + explicit + system_package_manager_debian (os_release&& osr) + : system_package_manager (move (osr)) {} + + protected: + }; +} + +#endif // BPKG_SYSTEM_PACKAGE_MANAGER_DEBIAN_HXX diff --git a/bpkg/system-package-manager.cxx b/bpkg/system-package-manager.cxx index e5503f6..3d5bda7 100644 --- a/bpkg/system-package-manager.cxx +++ b/bpkg/system-package-manager.cxx @@ -10,6 +10,8 @@ #include #include +#include + using namespace std; using namespace butl; @@ -41,6 +43,8 @@ namespace bpkg { // @@ TODO: verify name if specified. + // @@ TMP + // //r.reset (new system_package_manager_debian (move (*osr))); } } diff --git a/bpkg/system-package-manager.hxx b/bpkg/system-package-manager.hxx index 131c670..fb90e2c 100644 --- a/bpkg/system-package-manager.hxx +++ b/bpkg/system-package-manager.hxx @@ -23,23 +23,85 @@ namespace bpkg public: struct package_status { + // Downstream (as in, bpkg package) version. + // bpkg::version version; - // The system package can be either "available already installed" - // or "available not yet installed". - // - // If the package is partially installed (for example, libfoo but not - // libfoo-dev is installed), then installed should be false (and perhaps - // only a single available version should be returned). + // The system package can be either "available already installed", + // "available partially installed" (for example, libfoo but not + // libfoo-dev is installed) or "available not yet installed". // - bool installed; + enum {installed, partially_installed, not_installed} status; + // System (as in, distribution package) name and version. + // + // @@ But these could be multiple. Do we really need this? + /* string system_name; string system_version; + */ }; - // @@ We actually need to fetch is some are not installed to get their - // versions. We can do it as part of the call, no? + // Query the system package status. + // + // This function has two modes: cache-only (available_packages is NULL) + // and full (available_packages is not NULL). In the cache-only mode this + // function returns the status of this package if it has already been + // queried and nullopt otherwise. This allows the caller to only collect + // all the available packages (for the name/version mapping information) + // if really necessary. + // + // The returned value can be NULL, which indicates that no such package is + // available from the system package manager. Note that NULL is returned + // if no fully installed package is available from the system and install + // is false. + // + // If fetch is false, then do not re-fetch the system package repository + // metadata (that is, available packages/versions) before querying for + // the available version of the not yet installed or partially installed + // packages. + // + // Note that currently the result is a single available version. While + // some package managers may support installing multiple versions in + // parallel, this is unlikely to be suppored for the packages we are + // interested in due to the underlying limitations. + // + // Specifically, the packages that we are primarily interested in are + // libraries with headers and executables (tools). While most package + // managers (e.g., Debian, Fedora) are able to install multiple libraries + // in parallel, they normally can only install a single set of headers, + // static libraries, pkg-config files, etc., (e.g., -dev/-devel package) + // at a time due to them being installed into the same location (e.g., + // /usr/include). The same holds for executables, which are installed into + // the same location (e.g., /usr/bin). + // + // @@ But it's still plausible to have multiple available versions but + // only being able to install one at a time? + // + // It is possible that a certain library has made arrangements for + // multiple of its versions to co-exist. For example, hypothetically, our + // libssl package could be mapped to both libssl1.1 libssl1.1-dev and + // libssl3 libssl3-dev which could be installed at the same time (note + // that it is not the case in reality; there is only libssl-dev). However, + // in this case, we should probably also have two packages with separate + // names (e.g., libssl and libssl3) that can also co-exist. An example of + // this would be libQt5Core and libQt6Core. (Note that strictly speaking + // there could be different degrees of co-existence: for the system + // package manager it is sufficient for different versions not to clobber + // each other's files while for us we may also need the ability to use + // different versions in the base build). + // + // Note also that the above reasoning is quite C/C++-centric and it's + // possible that multiple versions of libraries (or equivalent) for other + // languages (e.g., Rust) can always co-exist. In this case we may need to + // revise this decision to only return a single version (and pick the best + // suitable version as part of the constraint resolution). + // + virtual optional + pkg_status (const package_name&, + const available_packages*, + bool install, + bool fetch) = 0; public: virtual -- cgit v1.1