From e6587668fa1f74bf32e0017666bdf2152434dbfb Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Tue, 14 Mar 2023 23:28:08 +0300 Subject: Fix Fedora package mapping for consumption --- bpkg/system-package-manager-fedora.cxx | 61 +++++++++--- bpkg/system-package-manager-fedora.hxx | 8 +- bpkg/system-package-manager-fedora.test.cxx | 21 +++- bpkg/system-package-manager-fedora.test.testscript | 106 ++++++++++----------- 4 files changed, 126 insertions(+), 70 deletions(-) diff --git a/bpkg/system-package-manager-fedora.cxx b/bpkg/system-package-manager-fedora.cxx index cfaa636..8ea1866 100644 --- a/bpkg/system-package-manager-fedora.cxx +++ b/bpkg/system-package-manager-fedora.cxx @@ -543,7 +543,8 @@ namespace bpkg vector> system_package_manager_fedora:: dnf_repoquery_requires (const string& name, const string& ver, - const string& qarch) + const string& qarch, + bool installed) { assert (!name.empty () && !ver.empty () && !arch.empty ()); @@ -559,14 +560,36 @@ namespace bpkg // check: ' printed to stderr. It does not appear to affect // error diagnostics (try specifying an unknown option). // - const char* args[] = { + cstrings args { "dnf", "repoquery", "--requires", "--quiet", "--cacheonly", // Don't automatically update the metadata. "--resolve", // Resolve requirements to packages/versions. - "--qf", "%{name} %{arch} %{epoch}:%{version}-%{release}", - spec.c_str (), - nullptr}; + "--qf", "%{name} %{arch} %{epoch}:%{version}-%{release}"}; + + // Note that installed packages which are not available from configured + // repositories (e.g. packages installed from local rpm files or temporary + // local repositories, package versions not available anymore from their + // original repositories, etc) are not seen by `dnf repoquery` by + // default. It also turned out that the --installed option not only limits + // the resulting set to the installed packages, but also makes `dnf + // repoquery` to see all the installed packages, including the unavailable + // ones. Thus, we always add this option to query dependencies of the + // installed packages. + // + if (installed) + { + args.push_back ("--installed"); + + // dnf(8) also recommends to use --disableexcludes together with + // --install to make sure that all installed packages will be listed and + // no configuration file may influence the result. + // + args.push_back ("--disableexcludes=all"); + } + + args.push_back (spec.c_str ()); + args.push_back (nullptr); // Note that for this command there seems to be no need to run with the C // locale since the output is presumably not localizable. But let's do it @@ -599,7 +622,7 @@ namespace bpkg evars); else { - simulation::package k {name, ver, qarch}; + simulation::package k {name, ver, qarch, installed}; const path* f (nullptr); if (fetched_) @@ -1222,10 +1245,11 @@ namespace bpkg // auto guess_main = [this, &pn] (package_status& s, const string& ver, - const string& qarch) + const string& qarch, + bool installed) { vector> depends ( - dnf_repoquery_requires (s.devel, ver, qarch)); + dnf_repoquery_requires (s.devel, ver, qarch, installed)); s.main = main_from_devel (s.devel, ver, depends); @@ -1369,7 +1393,11 @@ namespace bpkg if (devel.installed_version.empty ()) continue; - guess_main (ps, devel.installed_version, devel.installed_arch); + guess_main (ps, + devel.installed_version, + devel.installed_arch, + true /* installed */); + pis.emplace (pis.begin (), ps.main); ps.package_infos_main++; dnf_list (pis, 1); @@ -1483,7 +1511,11 @@ namespace bpkg if (devel.candidate_version.empty ()) continue; // Not installable. - guess_main (ps, devel.candidate_version, devel.candidate_arch); + guess_main (ps, + devel.candidate_version, + devel.candidate_arch, + devel.candidate_version == devel.installed_version); + pis.emplace (pis.begin (), ps.main); ps.package_infos_main++; dnf_list (pis, 1); @@ -1604,12 +1636,19 @@ namespace bpkg if (!v) { // Fallback to using system version as downstream version. But first - // strip the epoch, if any. + // strip the epoch, if any. Also convert the potential pre-release + // separator to the bpkg version pre-release separator. // size_t p (sv.find (':')); if (p != string::npos) sv.erase (0, p + 1); + // @@ Do the same for Debian? + // + p = sv.find ('~'); + if (p != string::npos) + sv[p] = '-'; + try { v = version (sv); diff --git a/bpkg/system-package-manager-fedora.hxx b/bpkg/system-package-manager-fedora.hxx index 8da8863..28aff96 100644 --- a/bpkg/system-package-manager-fedora.hxx +++ b/bpkg/system-package-manager-fedora.hxx @@ -249,7 +249,7 @@ namespace bpkg dnf_list (vector&, size_t = 0); vector> - dnf_repoquery_requires (const string&, const string&, const string&); + dnf_repoquery_requires (const string&, const string&, const string&, bool); void dnf_makecache (); @@ -306,6 +306,7 @@ namespace bpkg string name; string version; string arch; + bool installed; bool operator< (const package& p) const @@ -316,7 +317,10 @@ namespace bpkg if (int r = version.compare (p.version)) return r < 0; - return arch < p.arch; + if (int r = arch.compare (p.arch)) + return r < 0; + + return installed < p.installed; } }; diff --git a/bpkg/system-package-manager-fedora.test.cxx b/bpkg/system-package-manager-fedora.test.cxx index 75b4642..893d938 100644 --- a/bpkg/system-package-manager-fedora.test.cxx +++ b/bpkg/system-package-manager-fedora.test.cxx @@ -83,6 +83,12 @@ namespace bpkg // os_release osr {"fedora", {}, "35", "", "Fedora Linux", "", ""}; + auto to_bool = [] (const string& s) + { + assert (s == "true" || s == "false"); + return s == "true"; + }; + if (cmd == "dnf-list") { assert (argc >= 3); // ... @@ -122,9 +128,9 @@ namespace bpkg } else if (cmd == "dnf-repoquery-requires") { - assert (argc == 5); // + assert (argc == 6); // - package key {argv[2], argv[3], argv[4]}; + package key {argv[2], argv[3], argv[4], to_bool (argv[5])}; system_package_manager_fedora::simulation s; s.dnf_repoquery_requires_.emplace (key, path ("-")); @@ -141,7 +147,10 @@ namespace bpkg m.simulate_ = &s; for (const pair& d: - m.dnf_repoquery_requires (key.name, key.version, key.arch)) + m.dnf_repoquery_requires (key.name, + key.version, + key.arch, + key.installed)) { cout << d.first << ' ' << d.second << '\n'; } @@ -282,12 +291,16 @@ namespace bpkg string f (l, q + 1); trim (f); q = n.rfind (' '); assert (q != string::npos); + bool i (to_bool (string (n, q + 1))); + n.resize (q); + + q = n.rfind (' '); assert (q != string::npos); string a (n, q + 1); n.resize (q); q = n.find (' '); assert (q != string::npos); - package pkg {string (n, 0, q), string (n, q + 1), move (a)}; + package pkg {string (n, 0, q), string (n, q + 1), move (a), i}; if (f == "!") f.clear (); diff --git a/bpkg/system-package-manager-fedora.test.testscript b/bpkg/system-package-manager-fedora.test.testscript index ef37f07..ab3590a 100644 --- a/bpkg/system-package-manager-fedora.test.testscript +++ b/bpkg/system-package-manager-fedora.test.testscript @@ -98,7 +98,7 @@ : basics : - $* openssl-devel '1:1.1.1q-1.fc35' x86_64 <>EOE >>EOO + $* openssl-devel '1:1.1.1q-1.fc35' x86_64 true <>EOE >>EOO opae-devel x86_64 0:2.0.0-2.3.fc35 openssl-devel i686 1:1.1.1q-1.fc35 openssl-devel x86_64 1:1.1.1q-1.fc35 @@ -109,7 +109,7 @@ pkgconf-pkg-config i686 0:1.8.0-1.fc35 pkgconf-pkg-config x86_64 0:1.8.0-1.fc35 EOI - LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" openssl-devel-1:1.1.1q-1.fc35.x86_64 <- + LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" --installed --disableexcludes=all openssl-devel-1:1.1.1q-1.fc35.x86_64 <- EOE opae-devel 2.0.0-2.3.fc35 openssl-libs 1:1.1.1q-1.fc35 @@ -120,7 +120,7 @@ : no-arch : - $* rust-uuid+std-devel 1.2.1-1.fc35 noarch <>EOE >>EOO + $* rust-uuid+std-devel 1.2.1-1.fc35 noarch false <>EOE >>EOO cargo x86_64 0:1.65.0-1.fc35 rust-uuid-devel noarch 0:1.2.1-1.fc35 EOI @@ -132,7 +132,7 @@ : no-arch-dependency : - $* dhcp-client '12:4.4.3-4.P1.fc35' x86_64 <>EOE >>EOO + $* dhcp-client '12:4.4.3-4.P1.fc35' x86_64 true <>EOE >>EOO bash i686 0:5.1.8-3.fc35 bash x86_64 0:5.1.8-3.fc35 coreutils x86_64 0:8.32-36.fc35 @@ -151,7 +151,7 @@ systemd i686 0:249.13-6.fc35 systemd x86_64 0:249.13-6.fc35 EOI - LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" dhcp-client-12:4.4.3-4.P1.fc35.x86_64 <- + LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" --installed --disableexcludes=all dhcp-client-12:4.4.3-4.P1.fc35.x86_64 <- EOE bash 5.1.8-3.fc35 coreutils 8.32-36.fc35 @@ -170,13 +170,13 @@ : no-depends : - $* glibc 2.34-38.fc35 x86_64 <:'' 2>>EOE >:'' - LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" glibc-2.34-38.fc35.x86_64 <- + $* glibc 2.34-38.fc35 x86_64 true <:'' 2>>EOE >:'' + LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" --installed --disableexcludes=all glibc-2.34-38.fc35.x86_64 <- EOE : unknown : - $* glibg 2.34-38.fc35 x86_64 <:'' 2>>EOE >:'' + $* glibg 2.34-38.fc35 x86_64 false <:'' 2>>EOE >:'' LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" glibg-2.34-38.fc35.x86_64 <- EOE } @@ -294,12 +294,12 @@ libpq.i686 13.4-1.fc35 fedora EOI $* libpq --install libpq <>EOE >>EOO - dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info - dnf-repoquery-requires: libpq-devel 13.4-1.fc35 x86_64 libpq-devel.requires - dnf-list: libpq libpq.info + dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info + dnf-repoquery-requires: libpq-devel 13.4-1.fc35 x86_64 true libpq-devel.requires + dnf-list: libpq libpq.info EOI LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm >EOE >>EOO - dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info - dnf-repoquery-requires: libpq-devel 13.4-1.fc35 x86_64 libpq-devel.requires - dnf-list: libpq libpq.info + dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info + dnf-repoquery-requires: libpq-devel 13.4-1.fc35 x86_64 false libpq-devel.requires + dnf-list: libpq libpq.info EOI LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm >EOE >>EOO - dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info - dnf-list-fetched: libpq-devel pq-devel libpq-devel+pq-devel.info-fetched - dnf-repoquery-requires: libpq-devel 13.4-1.fc35 x86_64 libpq-devel.requires-fetched - dnf-list-fetched: libpq libpq.info-fetched - dnf-list-installed: libpq libpq.info-installed + dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info + dnf-list-fetched: libpq-devel pq-devel libpq-devel+pq-devel.info-fetched + dnf-repoquery-requires: libpq-devel 13.4-1.fc35 x86_64 false libpq-devel.requires-fetched + dnf-list-fetched: libpq libpq.info-fetched + dnf-list-installed: libpq libpq.info-installed EOI LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm >EOE >>EOO != 0 - dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info - dnf-repoquery-requires: libpq-devel 13.3-3.fc35 x86_64 libpq-devel.requires - dnf-list: libpq libpq.info - dnf-list-installed: libpq libpq.info-installed + dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info + dnf-repoquery-requires: libpq-devel 13.3-3.fc35 x86_64 false libpq-devel.requires + dnf-list: libpq libpq.info + dnf-list-installed: libpq libpq.info-installed EOI LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm >EOE >>EOO - dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info - dnf-repoquery-requires: libpq-devel 13.4-1.fc35 x86_64 libpq-devel.requires - dnf-list: libpq libpq.info - dnf-list-installed: libpq libpq.info-installed + dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info + dnf-repoquery-requires: libpq-devel 13.4-1.fc35 x86_64 false libpq-devel.requires + dnf-list: libpq libpq.info + dnf-list-installed: libpq libpq.info-installed EOI LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm >EOE >>EOO manifest: libsqlite3 libsqlite3.manifest - dnf-list: libsqlite3-devel sqlite-devel libsqlite3-devel+sqlite-devel.info - dnf-repoquery-requires: sqlite-devel 3.36.0-3.fc35 x86_64 sqlite-devel.requires - dnf-list: sqlite-libs sqlite-libs.info + dnf-list: libsqlite3-devel sqlite-devel libsqlite3-devel+sqlite-devel.info + dnf-repoquery-requires: sqlite-devel 3.36.0-3.fc35 x86_64 true sqlite-devel.requires + dnf-list: sqlite-libs sqlite-libs.info EOI LC_ALL=C dnf list --all --cacheonly --quiet libsqlite3-devel sqlite-devel rpm >EOE >>EOO manifest: libsqlite3 libsqlite3.manifest - dnf-list: libsqlite3-devel sqlite-devel libsqlite3-devel+sqlite-devel.info - dnf-repoquery-requires-fetched: sqlite-devel 3.36.0-3.fc35 x86_64 sqlite-devel.requires-fetched - dnf-list-fetched: libsqlite3-devel sqlite-devel libsqlite3-devel+sqlite-devel.info-fetched - dnf-list-fetched: sqlite-libs sqlite-libs.info-fetched - dnf-list-installed: sqlite-libs sqlite-libs.info-installed + dnf-list: libsqlite3-devel sqlite-devel libsqlite3-devel+sqlite-devel.info + dnf-repoquery-requires-fetched: sqlite-devel 3.36.0-3.fc35 x86_64 false sqlite-devel.requires-fetched + dnf-list-fetched: libsqlite3-devel sqlite-devel libsqlite3-devel+sqlite-devel.info-fetched + dnf-list-fetched: sqlite-libs sqlite-libs.info-fetched + dnf-list-installed: sqlite-libs sqlite-libs.info-installed EOI LC_ALL=C dnf list --all --cacheonly --quiet libsqlite3-devel sqlite-devel rpm