From b453087907850073244e5ce1f1ea52728402734d Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 9 Feb 2023 21:37:17 +0300 Subject: Add system_package_manager::system_package_version() --- bpkg/system-package-manager.cxx | 113 +++++++++++++++++++++++++++++++++++----- bpkg/system-package-manager.hxx | 23 ++++++++ 2 files changed, 123 insertions(+), 13 deletions(-) diff --git a/bpkg/system-package-manager.cxx b/bpkg/system-package-manager.cxx index f25c0e0..8e3bf3b 100644 --- a/bpkg/system-package-manager.cxx +++ b/bpkg/system-package-manager.cxx @@ -219,7 +219,7 @@ namespace bpkg static pair parse_distribution (string&& d, const string& value_name, - const shared_ptr& ap, + const available_package& ap, const lazy_shared_ptr& af) { string dn (move (d)); // [_] @@ -270,8 +270,8 @@ namespace bpkg diag_record dr (fail); dr << "invalid distribution version '" << string (dn, p + 1) - << "' in value " << value_name << " for package " << ap->id.name - << ' ' << ap->version; + << "' in value " << value_name << " for package " << ap.id.name + << ' ' << ap.version; if (db != nullptr) dr << *db; @@ -321,13 +321,15 @@ namespace bpkg if (optional d = dv.distribution ("-name")) { pair dnv ( - parse_distribution (move (*d), dv.name, ap, a.second)); + parse_distribution (move (*d), dv.name, *ap, a.second)); - if (dnv.first == n && dnv.second <= v) + semantic_version& dvr (dnv.second); + + if (dnv.first == n && dvr <= v) { // Add the name/version pair to the sorted vector. // - name_version nv (make_pair (dv.value, move (dnv.second))); + name_version nv (make_pair (dv.value, move (dvr))); nvs.insert (upper_bound (nvs.begin (), nvs.end (), nv, [] (const name_version& x, @@ -376,6 +378,89 @@ namespace bpkg return r; } + optional system_package_manager:: + system_package_version (const available_package& ap, + const lazy_shared_ptr& af, + const string& name_id, + const string& version_id, + const vector& like_ids) + { + semantic_version vid (parse_version_id (version_id, name_id)); + + // Iterate over the [_]-version distribution values of the + // passed available package. Only consider those values whose + // component matches the specified distribution name and the + // component (assumed as "0" if not present) is less or equal the + // specified distribution version. Return the system package version if + // the distribution version is equal to the specified one. Otherwise (the + // version is less), continue iterating while preferring system version + // candidates for greater distribution versions. Note that here we are + // trying to pick the system version which distribution version closest + // (but never greater) to the specified distribution version, similar to + // what we do in downstream_package_version() (see its + // downstream_version() lambda for details). + // + auto system_version = [&ap, &af] (const string& n, + const semantic_version& v) + -> optional + { + optional r; + semantic_version rv; + + for (const distribution_name_value& dv: ap.distribution_values) + { + if (optional d = dv.distribution ("-version")) + { + pair dnv ( + parse_distribution (move (*d), dv.name, ap, af)); + + semantic_version& dvr (dnv.second); + + if (dnv.first == n && dvr <= v) + { + // If the distribution version is equal to the specified one, then + // we are done. Otherwise, save the system version if it is + // preferable and continue iterating. + // + if (dvr == v) + return move (dv.value); + + if (!r || rv < dvr) + { + r = move (dv.value); + rv = move (dvr); + } + } + } + } + + return r; + }; + + // Try to deduce the system package version using the + // -version values that match the name id and refer to the + // version which is less or equal than the version id. + // + optional r (system_version (name_id, vid)); + + // If the system package version is not deduced and the like ids are + // specified, then re-try but now using the like id and "0" version id + // instead. + // + if (!r) + { + for (const string& like_id: like_ids) + { + r = system_version (like_id, semantic_version (0, 0, 0)); + if (r) + break; + } + } + + return r; + + } + optional system_package_manager:: downstream_package_version (const string& system_version, const available_packages& aps, @@ -423,9 +508,11 @@ namespace bpkg if (optional d = nv.distribution ("-to-downstream-version")) { pair dnv ( - parse_distribution (move (*d), nv.name, ap, a.second)); + parse_distribution (move (*d), nv.name, *ap, a.second)); + + semantic_version& dvr (dnv.second); - if (dnv.first == n && dnv.second <= v) + if (dnv.first == n && dvr <= v) { auto bad_value = [&nv, &ap, &a] (const string& d) { @@ -504,21 +591,21 @@ namespace bpkg version ver (dv); // If the distribution version is equal to the specified one, - // then we are done. Otherwise, save the version if it is - // preferable and continue iterating. + // then we are done. Otherwise, save the downstream version if + // it is preferable and continue iterating. // // Note that bailing out immediately in the former case is // essential. Otherwise, we can potentially fail later on, for // example, some ill-formed regex which is already fixed in // some newer package. // - if (dnv.second == v) + if (dvr == v) return ver; - if (!r || rv < dnv.second) + if (!r || rv < dvr) { r = move (ver); - rv = move (dnv.second); + rv = move (dvr); } } catch (const invalid_argument& e) diff --git a/bpkg/system-package-manager.hxx b/bpkg/system-package-manager.hxx index 81adeee..7e4f89c 100644 --- a/bpkg/system-package-manager.hxx +++ b/bpkg/system-package-manager.hxx @@ -271,6 +271,29 @@ namespace bpkg const string& version_id, const vector& like_ids); + // Given the available package and the repository fragment it belongs to, + // return the system package version as mapped by one of the + // -version values. + // + // The rest of the arguments as well as the overalls semantics is the same + // as in system_package_names() above. That is, first consider + // -version values corresponding to name_id. If none match, + // then repeat the above process for every like_ids entry with version_id + // equal 0. If still no match, then return nullopt (in which case the + // caller may choose to fallback to the upstream package version or do + // something more elaborate). + // + // Note that lazy_shared_ptr is used only for + // diagnostics and conveys the database the available package object + // belongs to. + // + static optional + system_package_version (const available_package&, + const lazy_shared_ptr&, + const string& name_id, + const string& version_id, + const vector& like_ids); + // Given the system package version and available packages (as returned by // find_available_all()) return the downstream package version as mapped // by one of the -to-downstream-version values. -- cgit v1.1