From 51b35a2d4305a2f302be62a370c4b00b2a215279 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Sat, 5 May 2018 21:37:17 +0300 Subject: Add support for --patch option --- bpkg/package.cxx | 26 +- bpkg/package.hxx | 5 + bpkg/pkg-build.cxx | 450 ++++++++++++++++++++++----- tests/common/satisfy/libbaz-0.1.0.tar.gz | Bin 0 -> 355 bytes tests/common/satisfy/t0c/libbaz-0.1.0.tar.gz | 1 + tests/pkg-build.test | 400 +++++++++++++++++++++--- 6 files changed, 755 insertions(+), 127 deletions(-) create mode 100644 tests/common/satisfy/libbaz-0.1.0.tar.gz create mode 120000 tests/common/satisfy/t0c/libbaz-0.1.0.tar.gz diff --git a/bpkg/package.cxx b/bpkg/package.cxx index 4880623..ccaf6ba 100644 --- a/bpkg/package.cxx +++ b/bpkg/package.cxx @@ -194,11 +194,9 @@ namespace bpkg { for (const shared_ptr r: rps) { - shared_ptr ar (filter (r, ap, prereq)); - - if (ar != nullptr) + if (shared_ptr rf = filter (r, ap, prereq)) { - aps.emplace_back (move (ap), move (ar)); + aps.emplace_back (move (ap), move (rf)); break; } } @@ -207,6 +205,26 @@ namespace bpkg return aps; } + pair, shared_ptr> + filter_one (const vector>& rps, + odb::result&& apr, + bool prereq) + { + using result = pair, + shared_ptr>; + + for (shared_ptr ap: pointer_result (apr)) + { + for (const shared_ptr r: rps) + { + if (shared_ptr rf = filter (r, ap, prereq)) + return result (move (ap), move (rf)); + } + } + + return result (); + } + void check_any_available (const dir_path& c, transaction& t, diff --git a/bpkg/package.hxx b/bpkg/package.hxx index f6bada3..1986e1f 100644 --- a/bpkg/package.hxx +++ b/bpkg/package.hxx @@ -599,6 +599,11 @@ namespace bpkg odb::result&&, bool prereq = true); + pair, shared_ptr> + filter_one (const vector>&, + odb::result&&, + bool prereq = true); + // Check if there are packages available in the configuration. If that's not // the case then print the info message into the diag record or, if it is // NULL, print the error message and fail. diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx index 423d12f..2d7c21a 100644 --- a/bpkg/pkg-build.cxx +++ b/bpkg/pkg-build.cxx @@ -12,6 +12,7 @@ #include // find_if() #include +#include #include #include @@ -1507,6 +1508,52 @@ namespace bpkg map map_; }; + // Return a patch version constraint for the selected package if it has a + // standard version, otherwise, if requested, issue a warning and return + // nullopt. + // + // Note that the function may also issue a warning and return nullopt if the + // selected package minor version reached the limit (see + // standard-version.cxx for details). + // + static optional + patch_constraint (const shared_ptr& sp, bool quiet = false) + { + const string& nm (sp->name); + const version& sv (sp->version); + + // Note that we don't pass allow_stub flag so the system wildcard version + // will (naturally) not be patched. + // + optional v (parse_standard_version (sv.string ())); + + if (!v) + { + if (!quiet) + warn << "unable to patch " << package_string (nm, sv) << + info << "package is not using semantic/standard version"; + + return nullopt; + } + + try + { + return dependency_constraint ("~" + sv.string ()); + } + // Note that the only possible reason for invalid_argument exception to + // be thrown is that minor version reached the 999 limit (see + // standard-version.cxx for details). + // + catch (const invalid_argument&) + { + if (!quiet) + warn << "unable to patch " << package_string (nm, sv) << + info << "minor version limit reached"; + + return nullopt; + } + } + // List of dependency packages (specified with ? on the command line). // struct dependency_package @@ -1515,6 +1562,7 @@ namespace bpkg bpkg::version version; // Empty if unspecified. shared_ptr selected; // NULL if not present. bool system; + bool patch; // Meaningful for an empty version. bool keep_out; }; using dependency_packages = vector; @@ -1550,6 +1598,8 @@ namespace bpkg const shared_ptr&, const version& desired, bool desired_sys, + bool patch, + bool explicitly, const set>&, const package_dependents&, bool ignore_unsatisfiable); @@ -1642,6 +1692,8 @@ namespace bpkg sp, dv, dsys, + i->patch, + true /* explicitly */, repo_frags, dependents, ignore_unsatisfiable); @@ -1652,28 +1704,16 @@ namespace bpkg const shared_ptr& sp, const version& dv, bool dsys, + bool patch, + bool explicitly, const set>& rfs, const package_dependents& dependents, bool ignore_unsatisfiable) { tracer trace ("evaluate_dependency"); - const string& nm (sp->name); - - // Build the list of available packages for the potential up/down-grade - // to, in the version-descending order. For a system package we put no - // constraints just to make sure that the package is recognized. - // - auto apr (dv.empty () || dsys - ? query_available (db, nm, nullopt) - : query_available (db, nm, dependency_constraint (dv))); - - vector, - shared_ptr>> afs ( - filter (vector> ( - rfs.begin (), - rfs.end ()), - move (apr))); + const string& nm (sp->name); + const version& sv (sp->version); auto no_change = [] () { @@ -1683,17 +1723,37 @@ namespace bpkg false /* system */}; }; - if (afs.empty ()) + // Build the list of available packages for the potential up/down-grade + // to, in the version-descending order. If patching, then we constrain the + // choice with the latest patch version and place no constraints if + // upgrading. For a system package we also put no constraints just to make + // sure that the package is recognized. + // + optional c; + + if (dv.empty ()) { - if (ignore_unsatisfiable) + assert (!dsys); // The version can't be empty for the system package. + + if (patch) { - l5 ([&]{trace << *sp << ": no repos";}); - return no_change (); - } + c = patch_constraint (sp, ignore_unsatisfiable); - fail << package_string (nm, dv.empty () || dsys ? version () : dv) - << " is not present in its dependents repositories"; + if (!c) + { + l5 ([&]{trace << *sp << ": non-patchable";}); + return no_change (); + } + } } + else if (!dsys) + c = dependency_constraint (dv); + + vector, + shared_ptr>> afs ( + filter (vector> (rfs.begin (), + rfs.end ()), + query_available (db, nm, c))); // Go through up/down-grade candidates and pick the first one that // satisfies all the dependents. Collect (and sort) unsatisfied dependents @@ -1714,7 +1774,7 @@ namespace bpkg vector> unsatisfiable; - const version& sv (sp->version); + bool stub (false); bool ssys (sp->system ()); assert (!dsys || system_repository.find (nm) != nullptr); @@ -1724,18 +1784,38 @@ namespace bpkg shared_ptr& ap (af.first); const version& av (!dsys ? ap->version : *ap->system_version ()); - // If we aim to upgrade to the highest possible version and it tends to - // be less then the selected one, then what we currently have is the - // best that we can get, and so we return the "no change" result. + // If we aim to upgrade to the latest version and it tends to be less + // then the selected one, then what we currently have is the best that + // we can get, and so we return the "no change" result. // - if (dv.empty () && av < sv && !ssys) + // Note that we also handle a package stub here. + // + if (dv.empty () && av < sv) { assert (!dsys); // Version can't be empty for the system package. - l5 ([&]{trace << *sp << ": best";}); - return no_change (); + // For the selected system package we still need to pick a source + // package version to downgrade to. + // + if (!ssys) + { + l5 ([&]{trace << *sp << ": best";}); + return no_change (); + } + + // We can not upgrade the (system) package to a stub version, so just + // skip it. + // + if (ap->stub ()) + { + stub = true; + continue; + } } + // Check if the version satisfies all the dependents and collect + // unsatisfied ones. + // bool satisfactory (true); sp_set unsatisfied_dependents; @@ -1787,9 +1867,9 @@ namespace bpkg move (ap), move (af.second), false /* unused */, dsys}; } - // If we aim to upgrade to the highest possible version, then what we - // currently have is the only thing that we can get, and so returning the - // "no change" result. + // If we aim to upgrade to the latest version, then what we currently have + // is the only thing that we can get, and so returning the "no change" + // result, unless we need to upgrade a package configured as system. // if (dv.empty () && !ssys) { @@ -1799,16 +1879,54 @@ namespace bpkg return no_change (); } - // If the desired dependency version is unsatisfiable for some dependents - // then we fail, unless requested not to do so. In the later case we - // return the "no change" result. + // If the desired dependency version is unavailable or unsatisfiable for + // some dependents then we fail, unless requested not to do so. In the + // later case we return the "no change" result. // if (ignore_unsatisfiable) { - l5 ([&]{trace << package_string (nm, dv, dsys) << ": unsatisfiable";}); + l5 ([&]{trace << package_string (nm, dv, dsys) + << (unsatisfiable.empty () + ? ": no source" + : ": unsatisfiable");}); + return no_change (); } + // If there are no unsatisfiable versions then the package is not present + // (or is not available in source) in its dependents' repositories. + // + if (unsatisfiable.empty ()) + { + diag_record dr (fail); + + if (dv.empty () && patch) + { + assert (ssys); // Otherwise, we would bail out earlier (see above). + + // Patch (as any upgrade) of a system package is always explicit, so + // we always fail and never treat the package as being up to date. + // + assert (explicitly); + + fail << "patch version for " << *sp << " is not available " + << "from its dependents' repositories"; + } + else if (!stub) + fail << package_string (nm, dsys ? version () : dv) + << " is not available from its dependents' repositories"; + else // The only available package is a stub. + { + // Note that we don't advise to "build" the package as a system one as + // it is already as such (see above). + // + assert (dv.empty () && !dsys && ssys); + + fail << package_string (nm, dv) << " is not available in source " + << "from its dependents' repositories"; + } + } + // Issue the diagnostics and fail. // diag_record dr (fail); @@ -1843,7 +1961,7 @@ namespace bpkg if (nv != unsatisfiable.size ()) dr << info << "and " << unsatisfiable.size () - nv << " more"; - dr << endf; + dr << endf; } // List of dependent packages whose immediate/recursive dependencies must be @@ -1858,9 +1976,10 @@ namespace bpkg using recursive_packages = vector; // Recursively check if immediate dependencies of this dependent must be - // upgraded. + // upgraded or patched. Return true if it must be upgraded, false if + // patched, and nullopt otherwise. // - static bool + static optional upgrade_dependencies (database& db, const string& nm, const recursive_packages& recs, @@ -1872,17 +1991,32 @@ namespace bpkg return i.name == nm; })); + optional r; + if (i != recs.end () && i->recursive >= recursion) - return true; + { + r = i->upgrade; + + if (*r) // Upgrade (vs patch)? + return r; + } for (const auto& pd: db.query ( query::name == nm)) { - if (upgrade_dependencies (db, pd.name, recs, true)) - return true; + if (optional u = upgrade_dependencies (db, pd.name, recs, true)) + { + if (!r || *r < *u) // Upgrade wins patch. + { + r = u; + + if (*r) // Upgrade (vs patch)? + return r; + } + } } - return false; + return r; } // Evaluate a package (not necessarily dependency) and return a new desired @@ -1920,22 +2054,25 @@ namespace bpkg // (immediate) dependents that have a hit (direct or indirect) in recs. // Note, however, that we collect constraints from all the dependents. // - bool upgrade (false); + optional upgrade; for (const auto& pd: pds) { shared_ptr dsp (db.load (pd.name)); dependents.emplace_back (dsp, move (pd.constraint)); - if (!upgrade_dependencies (db, pd.name, recs)) + if (optional u = upgrade_dependencies (db, pd.name, recs)) + { + if (!upgrade || *upgrade < *u) // Upgrade wins patch. + upgrade = u; + } + else continue; // While we already know that the dependency upgrade is required, we // continue to iterate over dependents, collecting the repository // fragments and the constraints. // - upgrade = true; - shared_ptr dap ( db.find ( available_package_id (dsp->name, dsp->version))); @@ -1962,6 +2099,8 @@ namespace bpkg sp, version () /* desired */, false /*desired_sys */, + !*upgrade /* patch */, + false /* explicitly */, repo_frags, dependents, ignore_unsatisfiable)); @@ -2399,7 +2538,50 @@ namespace bpkg order_by_version_desc (query::package::id.version))) { const shared_ptr& p (rp); - auto i (pvs.insert (make_pair (p->id.name, p->version))); + + if (p->stub ()) // Skip stubs. + continue; + + const string& nm (p->id.name); + + if (ps.options.patch ()) + { + shared_ptr sp ( + db.find (nm)); + + // It seems natural in the presence of --patch option to only + // patch the selected packages and not to build new packages if + // they are not specified explicitly. + // + // @@ Note that the dependencies may be held now, that can be + // unexpected for the user, who may think "I only asked to + // patch the packages". We probably could keep the hold flag + // for the patched packages unless --dependency option is + // specified explicitly. Sounds like a complication, so + // let's see if it ever becomes a problem. + // + // We still save these package names with the special empty + // version to later issue info messages about them. + // + if (sp == nullptr) + { + pvs.emplace (nm, version ()); + continue; + } + + optional c (patch_constraint (sp)); + + // Skip the non-patchable selected package. Note that the + // warning have already been issued in this case. + // + // We also skip versions that can not be considered as a + // patch for the selected package. + // + if (!c || !satisfies (p->version, c)) + continue; + } + + auto i (pvs.emplace (nm, p->version)); if (!i.second && i.first->second < p->version) i.first->second = p->version; @@ -2411,18 +2593,25 @@ namespace bpkg // Don't move options as they may be reused. // for (auto& pv: pvs) - pkg_args.push_back (arg_package (package_scheme::none, - pv.first, - move (pv.second), - ps.options)); + { + if (pv.second.empty ()) // Non-existent and so un-patchable? + info << "package " << pv.first << " is not present in " + << "configuration"; + else + pkg_args.push_back (arg_package (package_scheme::none, + pv.first, + move (pv.second), + ps.options)); + } } else // Packages with optional versions in the coma-separated list. { - for (size_t b (0); b != string::npos;) + for (size_t b (0), p; b != string::npos; + b = p != string::npos ? p + 1 : p) { // Extract the package. // - size_t p (ps.packages.find (',', b)); + p = ps.packages.find (',', b); string pkg (ps.packages, b, p != string::npos ? p - b : p); const char* s (pkg.c_str ()); @@ -2432,48 +2621,92 @@ namespace bpkg version v (parse_package_version (s)); // Check if the package is present in the repository and its - // complements, recursively. + // complements, recursively. If the version is not specified then + // find the latest allowed one. // // Note that for the system package we don't care about its exact // version available from the repository (which may well be a // stub). All we need is to make sure that it is present in the // repository. // - optional c ( - v.empty () || sc == package_scheme::sys - ? nullopt - : optional (v)); - bool complements (false); - shared_ptr ap; + + vector> rfs; + rfs.reserve (r->fragments.size ()); for (const repository::fragment_type& rf: r->fragments) { shared_ptr fr (rf.fragment.load ()); - ap = find_available (db, n, fr, c, false /* prereq */).first; - - if (ap != nullptr) - break; if (!fr->complements.empty ()) complements = true; + + rfs.push_back (move (fr)); } - if (ap == nullptr) + optional c; + shared_ptr sp; + + if (sc != package_scheme::sys) + { + if (v.empty ()) + { + if (ps.options.patch () && + (sp = db.find (n)) != nullptr) + { + c = patch_constraint (sp); + + // Skip the non-patchable selected package. Note that the + // warning have already been issued in this case. + // + if (!c) + continue; + } + } + else + c = dependency_constraint (v); + } + + shared_ptr ap ( + filter_one ( + rfs, query_available (db, n, c), false /* prereq */).first); + + // Fail if no available package is found or only a stub is + // available and we are building a source package. + // + if (ap == nullptr || (ap->stub () && sc != package_scheme::sys)) { diag_record dr (fail); - dr << "package " << pkg << " is not found in " << r->name; + + // If the selected package is loaded then we aim to patch it. + // + if (sp != nullptr) + dr << "patch version for " << *sp << " is not found in " + << r->name; + else if (ap == nullptr) + dr << "package " << pkg << " is not found in " << r->name; + else // Is a stub. + dr << "package " << pkg << " is not available in source from " + << r->name; if (complements) dr << " or its complements"; + + if (sp == nullptr && ap != nullptr) // Is a stub. + info << "specify sys:" << pkg << " if it is available " + << "from the system"; } + // Note that for a system package the wildcard version will be set + // (see arg_package() for details). + // + if (v.empty () && sc != package_scheme::sys) + v = ap->version; + // Don't move options as they may be reused. // pkg_args.push_back ( arg_package (sc, move (n), move (v), ps.options)); - - b = p != string::npos ? p + 1 : p; } } } @@ -2683,6 +2916,9 @@ namespace bpkg // Then it got to be a package name with optional version. // + shared_ptr sp; + bool patch (false); + if (ap == nullptr) { try @@ -2707,17 +2943,37 @@ namespace bpkg if (!pa.options.dependency ()) { - // Either get the user-specified version or the latest for a - // source code package. For a system package we pick the latest - // one just to make sure the package is recognized. + // Either get the user-specified version or the latest allowed + // for a source code package. For a system package we pick the + // latest one just to make sure the package is recognized. // - auto rp ( - pa.version.empty () || arg_sys (pa) - ? find_available (db, pa.name, root, nullopt) - : find_available (db, - pa.name, - root, - dependency_constraint (pa.version))); + optional c; + + if (pa.version.empty ()) + { + assert (!arg_sys (pa)); + + if (pa.options.patch () && + (sp = db.find (pa.name)) != nullptr) + { + c = patch_constraint (sp); + + // Skip the non-patchable selected package. Note that the + // warning have already been issued in this case. + // + if (!c) + { + ++i; + continue; + } + + patch = true; + } + } + else if (!arg_sys (pa)) + c = dependency_constraint (pa.version); + + auto rp (find_available (db, pa.name, root, c)); ap = move (rp.first); af = move (rp.second); } @@ -2783,26 +3039,29 @@ namespace bpkg check_any_available (c, t, &dr); } - shared_ptr sp ( // Save before the name move. - db.find (pa.name)); + // Save before the name move. + // + sp = db.find (pa.name); dep_pkgs.push_back (dependency_package {move (pa.name), move (pa.version), move (sp), sys, + pa.options.patch (), pa.options.keep_out ()}); continue; } // Add the held package to the list. // - // Load the package that may have already been selected and - // figure out what exactly we need to do here. The end goal + // Load the package that may have already been selected (if not done + // yet) and figure out what exactly we need to do here. The end goal // is the available_package object corresponding to the actual // package that we will be building (which may or may not be // the same as the selected package). // - shared_ptr sp (db.find (pa.name)); + if (sp == nullptr) + sp = db.find (pa.name); if (sp != nullptr && sp->state == package_state::broken) fail << "unable to build broken package " << pa.name << @@ -2893,6 +3152,11 @@ namespace bpkg if (!found) { + // We can always fallback to making available from the selected + // package. + // + assert (!patch); + diag_record dr (fail); if (!sys_advise) @@ -2986,7 +3250,21 @@ namespace bpkg continue; const string& name (sp->name); - auto apr (find_available (db, name, root, nullopt)); + + optional pc; + + if (o.patch ()) + { + pc = patch_constraint (sp); + + // Skip the non-patchable selected package. Note that the warning + // have already been issued in this case. + // + if (!pc) + continue; + } + + auto apr (find_available (db, name, root, pc)); shared_ptr ap (move (apr.first)); if (ap == nullptr || ap->stub ()) diff --git a/tests/common/satisfy/libbaz-0.1.0.tar.gz b/tests/common/satisfy/libbaz-0.1.0.tar.gz new file mode 100644 index 0000000..f8d4363 Binary files /dev/null and b/tests/common/satisfy/libbaz-0.1.0.tar.gz differ diff --git a/tests/common/satisfy/t0c/libbaz-0.1.0.tar.gz b/tests/common/satisfy/t0c/libbaz-0.1.0.tar.gz new file mode 120000 index 0000000..e95281e --- /dev/null +++ b/tests/common/satisfy/t0c/libbaz-0.1.0.tar.gz @@ -0,0 +1 @@ +../libbaz-0.1.0.tar.gz \ No newline at end of file diff --git a/tests/pkg-build.test b/tests/pkg-build.test index 7e34a52..9753a14 100644 --- a/tests/pkg-build.test +++ b/tests/pkg-build.test @@ -44,6 +44,7 @@ # | |-- libbar-1.0.0.tar.gz -> libfoo # | |-- libbaz-0.0.3.tar.gz -> libfoo # | |-- libbaz-0.0.4.tar.gz +# | |-- libbaz-0.1.0.tar.gz # | |-- libbox-0.0.1.tar.gz -> libbaz # | |-- libfix-0.0.3.tar.gz -> libbaz >= 0.0.3 # | |-- libfoo-1.0.0.tar.gz @@ -1314,7 +1315,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! $* libbar/0.0.1 2>!; - $pkg_status libbaz >'libbaz configured 0.0.1 available 0.0.4 0.0.3'; + $pkg_status libbaz >'libbaz configured 0.0.1 available 0.1.0 0.0.4 0.0.3'; $pkg_status libfox >'libfox configured 0.0.1'; $* libbar 2>>~%EOE%; @@ -1333,7 +1334,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! configured libbar/1.0.0 EOE - $pkg_status libbaz >'libbaz available 0.0.4 0.0.3 0.0.1'; + $pkg_status libbaz >'libbaz available 0.1.0 0.0.4 0.0.3 0.0.1'; $pkg_status libfox >'libfox available 0.0.1'; $pkg_drop libbar @@ -1353,7 +1354,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! $* libbar/0.0.1 2>!; - $pkg_status libbaz >'libbaz configured 0.0.1 available 0.0.4 0.0.3'; + $pkg_status libbaz >'libbaz configured 0.0.1 available 0.1.0 0.0.4 0.0.3'; $pkg_status libfox >'libfox configured 0.0.1'; $* ?libbar ?libbaz/0.0.3 2>>~%EOE%; @@ -1366,7 +1367,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! EOE $pkg_status libbar >'libbar available 1.0.0 0.0.3 0.0.1'; - $pkg_status libbaz >'libbaz available 0.0.4 0.0.3 0.0.1'; + $pkg_status libbaz >'libbaz available 0.1.0 0.0.4 0.0.3 0.0.1'; $pkg_status libfox >'libfox available 0.0.1' } } @@ -1413,7 +1414,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! error: unable to satisfy constraints on package libbaz info: libfix depends on (libbaz >= 0.0.3) info: libbiz depends on (libbaz <= 0.0.3) - info: available libbaz/0.0.4 + info: available libbaz/0.1.0 info: available libbaz/0.0.2 info: explicitly specify libbaz version to manually satisfy both constraints info: while satisfying libbiz/0.0.2 @@ -1438,7 +1439,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! configured libbiz/0.0.2 EOE - $pkg_status libbaz >'libbaz configured !0.0.3 available 0.0.4'; + $pkg_status libbaz >'libbaz configured !0.0.3 available 0.1.0 0.0.4'; $pkg_drop libbiz libfix } @@ -1474,7 +1475,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! configured libfix/0.0.3 EOE - $pkg_status libbaz >'libbaz configured !0.0.3 available 0.0.4'; + $pkg_status libbaz >'libbaz configured !0.0.3 available 0.1.0 0.0.4'; $pkg_drop libbiz libfix } @@ -1544,7 +1545,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! $* libbar/0.0.1 2>!; $* libbar/0.0.2 ?libbaz/0.0.1 2>!; - $pkg_status libbaz >'libbaz configured !0.0.1 available 0.0.4 0.0.3 0.0.2'; + $pkg_status libbaz >'libbaz configured !0.0.1 available 0.1.0 0.0.4 0.0.3 0.0.2'; $pkg_status libfox >'libfox configured 0.0.1'; $pkg_drop libbar @@ -1558,7 +1559,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! $* libbar/0.0.1 2>!; $* libbar/0.0.2 '?sys:libbaz/0.0.1' 2>!; - $pkg_status libbaz >'libbaz configured,system !0.0.1 available 0.0.4 0.0.3 0.0.2'; + $pkg_status libbaz >'libbaz configured,system !0.0.1 available 0.1.0 0.0.4 0.0.3 0.0.2'; $pkg_status libfox >'libfox available 0.0.1'; $pkg_drop libbar @@ -1572,7 +1573,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! $* libbar/0.0.1 '?sys:libbaz/0.0.1' 2>!; $* libbar/0.0.2 '?sys:libbaz' 2>!; - $pkg_status libbaz >'libbaz configured,system !* available 0.0.4 0.0.3 0.0.2 0.0.1'; + $pkg_status libbaz >'libbaz configured,system !* available 0.1.0 0.0.4 0.0.3 0.0.2 0.0.1'; $pkg_drop libbar } @@ -1585,7 +1586,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! $* libbar/0.0.1 '?sys:libbaz' 2>!; $* libbar/0.0.2 '?sys:libbaz/0.0.1' 2>!; - $pkg_status libbaz >'libbaz configured,system !0.0.1 available 0.0.4 0.0.3 0.0.2'; + $pkg_status libbaz >'libbaz configured,system !0.0.1 available 0.1.0 0.0.4 0.0.3 0.0.2'; $pkg_drop libbar } @@ -1862,7 +1863,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! $* libbar/1.0.0 2>!; $* ?libfoo/0.0.1 2>>EOE != 0; - error: libfoo/0.0.1 is not present in its dependents repositories + error: libfoo/0.0.1 is not available from its dependents' repositories EOE $pkg_drop libbar @@ -1876,7 +1877,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! $* libbar/0.0.1 2>!; - $pkg_status libbaz >'libbaz configured 0.0.1 available 0.0.4 0.0.3 0.0.2'; + $pkg_status libbaz >'libbaz configured 0.0.1 available 0.1.0 0.0.4 0.0.3 0.0.2'; $* libbar/0.0.2 ?libbaz 2>>~%EOE%; disfigured libbar/0.0.1 @@ -1897,7 +1898,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! configured libbar/0.0.2 EOE - $pkg_status libbaz >'libbaz configured 0.0.2 available 0.0.4 0.0.3'; + $pkg_status libbaz >'libbaz configured 0.0.2 available 0.1.0 0.0.4 0.0.3'; $rep_remove $rep/t0b && $rep_fetch; @@ -1911,7 +1912,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! configured libbox/0.0.1 EOE - $pkg_status libbaz >'libbaz configured 0.0.2 available 0.0.4 0.0.3'; + $pkg_status libbaz >'libbaz configured 0.0.2 available 0.1.0 0.0.4 0.0.3'; $rep_remove $rep/t0a && $rep_fetch; @@ -1934,7 +1935,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! configured libbar/0.0.2 EOE - $pkg_status libbaz >'libbaz configured,system !* available 0.0.4 0.0.3'; + $pkg_status libbaz >'libbaz configured,system !* available 0.1.0 0.0.4 0.0.3'; $pkg_drop libbar libbox } @@ -1946,14 +1947,14 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! $* libbar/0.0.1 2>!; - $pkg_status libbaz >'libbaz configured 0.0.1 available 0.0.4 0.0.3'; + $pkg_status libbaz >'libbaz configured 0.0.1 available 0.1.0 0.0.4 0.0.3'; $* ?libbaz/0.0.3 2>>EOE != 0; error: package libbaz doesn't satisfy its dependents info: libbaz/0.0.3 doesn't satisfy libbar/0.0.1 EOE - $pkg_status libbaz >'libbaz configured 0.0.1 available 0.0.4 0.0.3'; + $pkg_status libbaz >'libbaz configured 0.0.1 available 0.1.0 0.0.4 0.0.3'; $pkg_drop libbar } @@ -1966,7 +1967,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! $* libbox 2>!; - $pkg_status libbaz >'libbaz configured 0.0.3 available 0.0.4'; + $pkg_status libbaz >'libbaz configured 0.0.3 available 0.1.0 0.0.4'; $pkg_status libfoo >'libfoo configured 0.0.1 available 1.0.0'; $pkg_status libfox >'libfox available 0.0.1'; @@ -1994,7 +1995,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! configured libbox/0.0.1 EOE - $pkg_status libbaz >'libbaz configured !0.0.1 available 0.0.4 0.0.3'; + $pkg_status libbaz >'libbaz configured !0.0.1 available 0.1.0 0.0.4 0.0.3'; $pkg_status libfoo >'libfoo available 1.0.0 0.0.1'; $pkg_status libfox >'libfox configured 0.0.1'; @@ -2009,7 +2010,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! $* libbar/0.0.2 2>!; - $pkg_status libbaz >'libbaz configured 0.0.2 available 0.0.4 0.0.3'; + $pkg_status libbaz >'libbaz configured 0.0.2 available 0.1.0 0.0.4 0.0.3'; $pkg_status libfoo >'libfoo configured 1.0.0'; $* '?sys:libfoo' ?libbaz/0.0.2 2>>EOE; @@ -2131,8 +2132,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! # Note that libfoo building doesn't trigger libhello building as it is a # fake dependent, so build both explicitly. # - $* libhello --yes 2>!; - $* libfoo 2>!; + $* libfoo ?libhello 2>!; # Move libhello version ahead. # @@ -2263,6 +2263,10 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! +$* libbar/0.0.2 libbaz/0.0.2 libfoo/0.0.1 --yes 2>>~%EOE% %.* + %.*fetched libfix/0.0.1% + unpacked libfix/0.0.1 + configured libfix/0.0.1 + %.* %.*fetched libfoo/0.0.1% unpacked libfoo/0.0.1 configured libfoo/0.0.1 @@ -2287,9 +2291,9 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! disfigured libbar/0.0.2 disfigured libbaz/0.0.2 %.* - %.*fetched libbaz/0.0.4% - unpacked libbaz/0.0.4 - configured libbaz/0.0.4 + %.*fetched libbaz/0.1.0% + unpacked libbaz/0.1.0 + configured libbaz/0.1.0 %.* %.*fetched libbar/0.0.3% unpacked libbar/0.0.3 @@ -2297,7 +2301,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! EOE $pkg_status libbar >'!libbar configured !0.0.3 available 1.0.0'; - $pkg_status libbaz >'!libbaz configured !0.0.4'; + $pkg_status libbaz >'!libbaz configured !0.1.0'; $pkg_status libfoo >'!libfoo configured !0.0.1 available 1.0.0' } @@ -2315,9 +2319,9 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! unpacked libfoo/1.0.0 configured libfoo/1.0.0 %.* - %.*fetched libbaz/0.0.4% - unpacked libbaz/0.0.4 - configured libbaz/0.0.4 + %.*fetched libbaz/0.1.0% + unpacked libbaz/0.1.0 + configured libbaz/0.1.0 %.* %.*fetched libbar/0.0.3% unpacked libbar/0.0.3 @@ -2325,7 +2329,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! EOE $pkg_status libbar >'!libbar configured !0.0.3 available 1.0.0'; - $pkg_status libbaz >'!libbaz configured !0.0.4'; + $pkg_status libbaz >'!libbaz configured !0.1.0'; $pkg_status libfoo >'!libfoo configured !1.0.0' } @@ -2405,7 +2409,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! configured libbar/0.0.3 EOE - $pkg_status libbaz >'libbaz configured !0.0.3 available 0.0.4' + $pkg_status libbaz >'libbaz configured !0.0.3 available 0.1.0 0.0.4' } : unhold @@ -2432,20 +2436,21 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! EOE $pkg_status libbar >'!libbar configured !0.0.3 available 1.0.0'; - $pkg_status libbaz >'libbaz configured !0.0.3 available 0.0.4'; + $pkg_status libbaz >'libbaz configured !0.0.3 available 0.1.0 0.0.4'; $pkg_status libfoo >'libfoo configured 1.0.0' } : unavailable : + : Test that the selected dependency (libfix/0.0.1) is silently left + : unchanged if there is no package available from the dependents + : repositories. + : { $clone_cfg; - $rep_remove $rep/t0a $rep/t0b $rep/t0c; - $* libbar --recursive --yes 2>>EOE != 0 - error: libfix is not present in its dependents repositories - EOE + $* libbar --recursive --yes } -$pkg_drop libbar libbaz libfoo @@ -2547,6 +2552,284 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! } } +: patch +: +{ + test.arguments += --configure-only --yes + + +$clone_root_cfg + + : held + : + { + +$clone_cfg + +$rep_fetch $rep/t0c + + : success + : + { + $clone_cfg; + + $* libbaz/0.0.3 2>!; + + $* libbaz --patch 2>>~%EOE%; + disfigured libbaz/0.0.3 + disfigured libfoo/1.0.0 + purged libfoo/1.0.0 + %.* + %.*fetched libbaz/0.0.4% + unpacked libbaz/0.0.4 + configured libbaz/0.0.4 + EOE + + $pkg_drop libbaz + } + + : ignore + : + { + $clone_cfg; + + $* libbaz/0.0.3 --patch 2>>~%EOE%; + %.* + %.*fetched libfoo/1.0.0% + unpacked libfoo/1.0.0 + configured libfoo/1.0.0 + %.* + %.*fetched libbaz/0.0.3% + unpacked libbaz/0.0.3 + configured libbaz/0.0.3 + EOE + + $* libbaz/0.1.0 --patch 2>>~%EOE%; + disfigured libbaz/0.0.3 + disfigured libfoo/1.0.0 + purged libfoo/1.0.0 + %.* + %.*fetched libbaz/0.1.0% + unpacked libbaz/0.1.0 + configured libbaz/0.1.0 + EOE + + $pkg_drop libbaz + } + + : warn + : + { + $clone_cfg; + + $* 'sys:libbaz/0.0.3-alpha' 2>!; + + $* libbaz --patch 2>>~%EOE%; + warning: unable to patch libbaz/0.0.3-alpha + info: package is not using semantic/standard version + info: nothing to build + EOE + + $pkg_drop libbaz + } + } + + : dependency + : + { + +$clone_cfg + +$rep_fetch $rep/t0c + + +$* libbox libfix ?libbaz/0.0.3 2>>~%EOE% + %.* + %.*fetched libfoo/1.0.0% + unpacked libfoo/1.0.0 + configured libfoo/1.0.0 + %.* + %.*fetched libbaz/0.0.3% + unpacked libbaz/0.0.3 + configured libbaz/0.0.3 + %.* + %.*fetched libbox/0.0.1% + unpacked libbox/0.0.1 + configured libbox/0.0.1 + %.* + %.*fetched libfix/0.0.3% + unpacked libfix/0.0.3 + configured libfix/0.0.3 + EOE + + clone_cfg = cp --no-cleanup -r ../cfg ./ &cfg/*** + + : explicitly + : + : Here we also test that the package --path option overrides the global + : --upgrade option. + : + { + $clone_cfg; + + $* ?libbaz +{ --patch } --upgrade 2>>~%EOE% + disfigured libbox/0.0.1 + disfigured libfix/0.0.3 + disfigured libbaz/0.0.3 + disfigured libfoo/1.0.0 + purged libfoo/1.0.0 + %.* + %.*fetched libbaz/0.0.4% + unpacked libbaz/0.0.4 + configured libbaz/0.0.4 + configured libfix/0.0.3 + configured libbox/0.0.1 + EOE + } + + : warn + : + { + $clone_cfg; + + $* '?sys:libbaz/0.0.4-alpha' 2>!; + + $* ?libbaz --patch 2>>~%EOE% + warning: unable to patch libbaz/0.0.4-alpha + info: package is not using semantic/standard version + EOE + } + + : recursive + : + { + $clone_cfg; + + $* --patch --recursive 2>>~%EOE% + disfigured libfix/0.0.3 + disfigured libbox/0.0.1 + disfigured libbaz/0.0.3 + disfigured libfoo/1.0.0 + purged libfoo/1.0.0 + %.* + %.*fetched libbaz/0.0.4% + unpacked libbaz/0.0.4 + configured libbaz/0.0.4 + configured libbox/0.0.1 + configured libfix/0.0.3 + EOE + } + + : upgrade-wins-patch + : + : Test that --upgrade options wins --patch. + : + { + $clone_cfg; + + $* libbox +{ --upgrade-immediate } libfix +{ --patch-immediate } 2>>~%EOE% + disfigured libfix/0.0.3 + disfigured libbox/0.0.1 + disfigured libbaz/0.0.3 + disfigured libfoo/1.0.0 + purged libfoo/1.0.0 + %.* + %.*fetched libbaz/0.1.0% + unpacked libbaz/0.1.0 + configured libbaz/0.1.0 + configured libbox/0.0.1 + configured libfix/0.0.3 + EOE + } + + : unavailable + : + { + $clone_cfg; + + $* '?sys:libbaz/0.0.3' 2>>EOE; + disfigured libbox/0.0.1 + disfigured libfix/0.0.3 + disfigured libbaz/0.0.3 + disfigured libfoo/1.0.0 + purged libfoo/1.0.0 + purged libbaz/0.0.3 + configured sys:libbaz/0.0.3 + configured libfix/0.0.3 + configured libbox/0.0.1 + EOE + + $rep_remove $rep/t0c; + $rep_fetch $rep/t0b; + + $* ?libbaz --patch --yes 2>>EOE != 0 + error: patch version for sys:libbaz/0.0.3 is not available from its dependents' repositories + EOE + } + + -$pkg_drop libbox libfix libbaz libfoo + } + + : from-repository + : + { + test.arguments += --patch --auth all --trust-yes + + +$clone_cfg + + +$* "libbaz/0.0.3@$rep/t0c" 2>>~%EOE% + added pkg:build2.org/pkg-build/t0c + %.* + %.*fetching pkg:build2.org/pkg-build/t0c% + %.* + %.*fetched libfoo/1.0.0% + unpacked libfoo/1.0.0 + configured libfoo/1.0.0 + %.* + %.*fetched libbaz/0.0.3% + unpacked libbaz/0.0.3 + configured libbaz/0.0.3 + EOE + + clone_cfg = cp --no-cleanup -r ../cfg ./ &cfg/*** + + : explicit + : + { + $clone_cfg; + + $* "libbaz@$rep/t0c" 2>>~%EOE% + fetching pkg:build2.org/pkg-build/t0c + disfigured libbaz/0.0.3 + disfigured libfoo/1.0.0 + purged libfoo/1.0.0 + %.* + %.*fetched libbaz/0.0.4% + unpacked libbaz/0.0.4 + configured libbaz/0.0.4 + EOE + } + + : implicit + : + : Note that libfoo also becomes held. + : + { + $clone_cfg; + + $* "@$rep/t0c" 2>>~%EOE%; + fetching pkg:build2.org/pkg-build/t0c + info: package libbar is not present in configuration + info: package libbox is not present in configuration + info: package libfix is not present in configuration + disfigured libbaz/0.0.3 + %.* + %.*fetched libbaz/0.0.4% + unpacked libbaz/0.0.4 + configured libbaz/0.0.4 + EOE + + $pkg_status libfoo >'!libfoo configured !1.0.0' + } + + -$pkg_drop libbaz libfoo + } +} + : configure-only : : Test --configure-only option. @@ -2675,6 +2958,49 @@ rep_fetch += -d cfg --auth all --trust-yes 2>! $pkg_purge libfoo 2>'purged libfoo/1.1.0' } + : version + : + : Test that libfoo/0.0.1 package version is built (repository t0a), rather + : than libfoo/1.0.0 (repository t4a). + : + { + $clone_root_cfg; + + $rep_fetch $rep/t4c 2>!; + + $* "libfoo@$rep/t0a" 2>>~%EOE%; + %.+ + configured libfoo/0.0.1 + %info: .+libfoo-0.0.1.+ is up to date% + updated libfoo/0.0.1 + EOE + + $pkg_drop libfoo + } + + : no-patch + : + : Here we also test that --patch options is ignored if there is no selected + : package in the configuration. + : + { + $clone_root_cfg; + + $* "libfoo@$rep/t1" --patch 2>>~%EOE%; + %.+ + configured libfoo/1.0.0 + %info: .+libfoo-1.0.0.+ is up to date% + updated libfoo/1.0.0 + EOE + + $* "libfoo@$rep/t3" --patch 2>>~%EOE% != 0; + %.+ + error: patch version for libfoo/1.0.0 is not found in pkg:build2.org/pkg-build/t3 + EOE + + $pkg_drop libfoo + } + : package-in-complement : { -- cgit v1.1