aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2023-10-25 18:14:35 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2023-11-02 14:04:09 +0300
commitad53b2152e10b133165c95f08f218e80f1dd8580 (patch)
tree2f2a0a09d776767ad302663fb5496a093d318854
parentb28f172537ae14d0fd386de63f7b62bfa6612d3a (diff)
Improve pkg-build's 'unable to upgrade package' diagnostics
-rw-r--r--bpkg/database.hxx5
-rw-r--r--bpkg/package.cxx33
-rw-r--r--bpkg/package.hxx66
-rw-r--r--bpkg/pkg-build-collect.cxx283
-rw-r--r--bpkg/pkg-build-collect.hxx71
-rw-r--r--bpkg/pkg-build.cxx35
-rw-r--r--bpkg/rep-create.cxx12
-rw-r--r--tests/pkg-build.testscript65
-rw-r--r--tests/pkg-system.testscript2
9 files changed, 417 insertions, 155 deletions
diff --git a/bpkg/database.hxx b/bpkg/database.hxx
index 684dc9d..a9e1da5 100644
--- a/bpkg/database.hxx
+++ b/bpkg/database.hxx
@@ -504,8 +504,9 @@ namespace bpkg
linked_databases implicit_links_;
};
- // NOTE: remember to update config_package comparison operators and
- // compare_lazy_ptr if changing the database comparison operators.
+ // NOTE: remember to update package_key and package_version_key comparison
+ // operators and compare_lazy_ptr if changing the database comparison
+ // operators.
//
// Note that here we use the database address as the database identity since
// we don't suppose two database instances for the same configuration to
diff --git a/bpkg/package.cxx b/bpkg/package.cxx
index aca3550..4beba8e 100644
--- a/bpkg/package.cxx
+++ b/bpkg/package.cxx
@@ -70,6 +70,39 @@ namespace bpkg
return r != 0 ? (r < 0) : (db < v.db);
}
+ // package_version_key
+ //
+ string package_version_key::
+ string (bool ignore_version) const
+ {
+ std::string r (name.string ());
+
+ if (version && !version->empty () && !ignore_version)
+ {
+ r += '/';
+ r += version->string ();
+ }
+
+ const std::string& d (db.get ().string);
+
+ if (!d.empty ())
+ {
+ r += ' ';
+ r += d;
+ }
+
+ return r;
+ }
+
+ bool package_version_key::
+ operator< (const package_version_key& v) const
+ {
+ if (int r = name.compare (v.name))
+ return r < 0;
+
+ return version != v.version ? (version < v.version) : (db < v.db);
+ }
+
// available_package
//
const version* available_package::
diff --git a/bpkg/package.hxx b/bpkg/package.hxx
index 06278cd..8f4b46c 100644
--- a/bpkg/package.hxx
+++ b/bpkg/package.hxx
@@ -1614,12 +1614,6 @@ namespace bpkg
package_key (database& d, package_name n): db (d), name (move (n)) {}
- // Create a pseudo-package (command line as a dependent, etc).
- //
- package_key (database& d, string n)
- : db (d),
- name (n.empty () ? package_name () : package_name (move (n))) {}
-
bool
operator== (const package_key& v) const
{
@@ -1651,6 +1645,66 @@ namespace bpkg
return os << p.string ();
}
+ // Database, package name, and package version.
+ //
+ // It is normally used as a key for maps containing data for package
+ // versions across multiple linked configurations. Assumes that the
+ // respective databases are not detached during such map lifetimes.
+ // Considers all package name, package version, and database for objects
+ // comparison.
+ //
+ // The package name can be a pseudo-package (command line as a dependent,
+ // etc), in which case the version is absent. The version can also be empty,
+ // denoting a package of an unknown version.
+ //
+ struct package_version_key
+ {
+ reference_wrapper<database> db;
+ package_name name;
+ optional<bpkg::version> version;
+
+ package_version_key (database& d, package_name n, bpkg::version v)
+ : db (d), name (move (n)), version (move (v)) {}
+
+ // Create a pseudo-package (command line as a dependent, etc).
+ //
+ package_version_key (database& d, string n)
+ : db (d),
+ name (move (n), package_name::raw_string) {}
+
+ bool
+ operator== (const package_version_key& v) const
+ {
+ // See operator==(database, database).
+ //
+ return name == v.name &&
+ version == v.version &&
+ &db.get () == &v.db.get ();
+ }
+
+ bool
+ operator!= (const package_version_key& v) const
+ {
+ return !(*this == v);
+ }
+
+ bool
+ operator< (const package_version_key&) const;
+
+ // Return the package string representation in the form:
+ //
+ // <name>[/<version>] [ <config-dir>]
+ //
+ std::string
+ string (bool ignore_version = false) const;
+ };
+
+ inline ostream&
+ operator<< (ostream& os, const package_version_key& p)
+ {
+ return os << p.string ();
+ }
+
// Return a count of repositories that contain this repository fragment.
//
#pragma db view table("main.repository_fragments")
diff --git a/bpkg/pkg-build-collect.cxx b/bpkg/pkg-build-collect.cxx
index 918242c..b1306b5 100644
--- a/bpkg/pkg-build-collect.cxx
+++ b/bpkg/pkg-build-collect.cxx
@@ -62,7 +62,8 @@ namespace bpkg
bool build_package::
user_selection () const
{
- return required_by.find (package_key {db.get ().main_database (), ""}) !=
+ return required_by.find (package_version_key (db.get ().main_database (),
+ "command line")) !=
required_by.end ();
}
@@ -303,7 +304,7 @@ namespace bpkg
// Propagate the user-selection tag.
//
- required_by.emplace (db.get ().main_database (), "");
+ required_by.emplace (db.get ().main_database (), "command line");
}
// Copy the required-by package names only if semantics matches.
@@ -320,10 +321,7 @@ namespace bpkg
if (find_if (constraints.begin (), constraints.end (),
[&c] (const constraint_type& v)
{
- return v.db.get () == c.db.get () &&
- v.dependent == c.dependent &&
- v.value == c.value;
-
+ return v.dependent == c.dependent && v.value == c.value;
}) == constraints.end ())
{
constraints.push_back (move (c));
@@ -525,8 +523,8 @@ namespace bpkg
//
int ud (sp->version.compare (av));
- // Otherwise, the dependent must be satisfied with the already configured
- // dependency.
+ // Otherwise, the dependent must be satisfied with the already
+ // configured dependency.
//
assert (ud != 0);
@@ -542,24 +540,81 @@ namespace bpkg
else
dr << av; // Can't be the wildcard otherwise would satisfy.
- dr << info << "because package " << dk << " depends on (" << n << ' '
- << c << ')';
+ shared_ptr<selected_package> dsp (
+ dk.db.get ().load<selected_package> (dk.name));
+
+ assert (dsp != nullptr); // By definition.
+ dr << info << "because configured package " << *dsp << dk.db
+ << " depends on (" << n << ' ' << c << ')';
+
+ // Print the dependency constraints tree for this unsatisfied dependent,
+ // which only contains constraints which come from its selected
+ // dependents, recursively.
+ //
{
set<package_key> printed;
- pkgs.print_constraints (dr, dk, indent, printed);
+ pkgs.print_constraints (dr,
+ dk,
+ indent,
+ printed,
+ true /* selected_dependent */);
}
- string rb;
+ // If the dependency we failed to up/downgrade is not explicitly
+ // specified on the command line, then print its dependency constraints
+ // tree which only contains constraints which come from its being built
+ // dependents, recursively.
+ //
if (!p->user_selection ())
{
- for (const package_key& pk: p->required_by)
- rb += (rb.empty () ? " " : ", ") + pk.string ();
- }
+ // The dependency upgrade is always required by someone, the command
+ // line or a package.
+ //
+ assert (!p->required_by.empty ());
+
+ dr << info << "package " << p->available_name_version_db ();
+
+ // Note that if the required_by member contains the dependencies,
+ // rather than the dependents, we will subsequently print the
+ // dependency constraints trees for these dependencies rather than a
+ // single constraints tree (rooted in the dependency we failed to
+ // up/downgrade). Also note that in this case we will still reuse the
+ // same printed packages cache for all print_constraints() calls,
+ // since it will likely be considered as a single dependency graph by
+ // the user.
+ //
+ bool rbd (p->required_by_dependents);
+ dr << (rbd ? " required by" : " dependent of");
- if (!rb.empty ())
- dr << info << "package " << p->available_name_version ()
- << " required by" << rb;
+ set<package_key> printed;
+ for (const package_version_key& pvk: p->required_by)
+ {
+ dr << '\n' << indent << pvk;
+
+ if (rbd)
+ {
+ const vector<build_package::constraint_type>& cs (p->constraints);
+ auto i (find_if (cs.begin (), cs.end (),
+ [&pvk] (const build_package::constraint_type& v)
+ {
+ return v.dependent == pvk;
+ }));
+
+ if (i != cs.end ())
+ dr << " (" << p->name () << ' ' << i->value << ')';
+ }
+
+ indent += " ";
+ pkgs.print_constraints (dr,
+ package_key (pvk.db, pvk.name),
+ indent,
+ printed,
+ false /* selected_dependent */);
+
+ indent.resize (indent.size () - 2);
+ }
+ }
dr << info << "consider re-trying with --upgrade|-u potentially combined "
<< "with --recursive|-r" <<
@@ -576,8 +631,8 @@ namespace bpkg
{
const build_package::constraint_type& c (uc.constraint);
- dr << info << c.dependent << c.db << " depends on (" << n
- << ' ' << c.value << ")";
+ dr << info << c.dependent << " depends on (" << n << ' ' << c.value
+ << ')';
if (const build_package* d = pkgs.dependent_build (c))
{
@@ -1268,17 +1323,16 @@ namespace bpkg
dependent_build (const build_package::constraint_type& c) const
{
const build_package* r (nullptr);
- const string& d (c.dependent);
- if (d != "command line")
+ if (c.dependent.version)
try
{
- r = entered_build (c.db, package_name (d));
+ r = entered_build (c.dependent.db, c.dependent.name);
assert (r != nullptr); // Expected to be collected.
}
catch (const invalid_argument&)
{
- // Must be a package name, unless it is 'command line'.
+ // Must be a package name since the version is specified.
//
assert (false);
}
@@ -1943,7 +1997,8 @@ namespace bpkg
replaced_vers,
postponed_recs,
postponed_cfgs,
- unsatisfied_depts);
+ unsatisfied_depts,
+ true /* add_required_by */);
}
// Postpone the recursive collection of a dependency if the existing
@@ -2473,15 +2528,15 @@ namespace bpkg
*dr << error << "unable to satisfy constraints on package "
<< dn <<
info << nm << pdb << " depends on (" << dn << ' '
- << *dp.constraint << ")";
+ << *dp.constraint << ')';
{
set<package_key> printed;
print_constraints (*dr, pkg, indent, printed);
}
- *dr << info << c.dependent << c.db << " depends on (" << dn
- << ' ' << c.value << ")";
+ *dr << info << c.dependent << " depends on (" << dn << ' '
+ << c.value << ')';
if (const build_package* d = dependent_build (c))
{
@@ -2725,7 +2780,7 @@ namespace bpkg
assert (dr == nullptr); // Should fail on the "silent" run.
fail << "multiple possible " << type << " configurations "
- << "for build-time dependency (" << dp << ")" <<
+ << "for build-time dependency (" << dp << ')' <<
info << db->config_orig <<
info << ldb.config_orig <<
info << "use --config-* to select the configuration";
@@ -3106,7 +3161,7 @@ namespace bpkg
info << package_string (dn,
*dap->system_version (*ddb),
true /* system */)
- << " does not satisfy the constrains";
+ << " does not satisfy the constrains";
return precollect_result (false /* postpone */);
}
@@ -3181,7 +3236,11 @@ namespace bpkg
{
using constraint_type = build_package::constraint_type;
- constraint_type c1 {pdb, nm.string (), *d.constraint};
+ constraint_type c1 (*d.constraint,
+ pdb,
+ nm,
+ pkg.available_version (),
+ false /* selected_dependent */);
if (!satisfies (v2, c1.value))
{
@@ -3204,8 +3263,8 @@ namespace bpkg
*dr << error << "unable to satisfy constraints on "
<< "package " << n <<
- info << c2.dependent << c2.db << " depends on ("
- << n << ' ' << c2.value << ")";
+ info << c2.dependent << " depends on (" << n
+ << ' ' << c2.value << ')';
if (const build_package* d = dependent_build (c2))
{
@@ -3213,9 +3272,8 @@ namespace bpkg
print_constraints (*dr, *d, indent, printed);
}
- *dr << info << c1.dependent << c1.db
- << " depends on (" << n << ' '
- << c1.value << ")";
+ *dr << info << c1.dependent << " depends on ("
+ << n << ' ' << c1.value << ')';
if (const build_package* d = dependent_build (c1))
{
@@ -3308,6 +3366,8 @@ namespace bpkg
postponed_deps.erase (d);
}));
+ package_version_key pvk (pk.db, pk.name, pkg.available_version ());
+
for (prebuild& b: bs)
{
build_package bpk {
@@ -3331,7 +3391,7 @@ namespace bpkg
nullopt, // Checkout root.
false, // Checkout purge.
strings (), // Configuration variables.
- {pk}, // Required by (dependent).
+ {pvk}, // Required by (dependent).
true, // Required by dependents.
0}; // State flags.
@@ -3346,7 +3406,11 @@ namespace bpkg
// both constraints for completeness.
//
if (constraint)
- bpk.constraints.emplace_back (pdb, nm.string (), *constraint);
+ bpk.constraints.emplace_back (*constraint,
+ pdb,
+ nm,
+ pkg.available_version (),
+ false /* selected_dependent */);
// Now collect this prerequisite. If it was actually collected
// (i.e., it wasn't already there) and we are forcing a downgrade
@@ -5073,13 +5137,19 @@ namespace bpkg
// Add the prerequisite replacements as the required-by packages.
//
- set<package_key> required_by;
+ set<package_version_key> required_by;
for (const auto& prq: rd.second)
{
if (prq.second) // Prerequisite replacement?
{
const package_key& pk (prq.first);
- required_by.emplace (pk.db, pk.name);
+
+ // Note that the dependency can potentially be just pre-entered, in
+ // which case its version is not known at this point.
+ //
+ assert (entered_build (pk) != nullptr);
+
+ required_by.emplace (pk.db, pk.name, version ());
}
}
@@ -5630,7 +5700,8 @@ namespace bpkg
replaced_vers,
postponed_recs,
postponed_cfgs,
- unsatisfied_depts);
+ unsatisfied_depts,
+ true /* add_required_by */);
}
}
}
@@ -6515,12 +6586,18 @@ namespace bpkg
<< "existing dependent " << *ed.selected
<< ed.db;});
+ // Note that we pass false as the add_required_by argument since
+ // the package builds collection state has been restored and the
+ // originating dependency for this existing dependent may not be
+ // collected anymore.
+ //
recollect_existing_dependent (o,
ed,
replaced_vers,
postponed_recs,
postponed_cfgs,
- unsatisfied_depts);
+ unsatisfied_depts,
+ false /* add_required_by */);
}
}
}
@@ -6691,12 +6768,17 @@ namespace bpkg
<< ed.db << " due to bogus postponement of "
<< "dependency " << pk;});
+ // Note that we pass false as the add_required_by argument since
+ // the postponment is bogus and thus the originating dependency
+ // for this existing dependent may not be collected.
+ //
recollect_existing_dependent (o,
ed,
replaced_vers,
postponed_recs,
postponed_cfgs,
- unsatisfied_depts);
+ unsatisfied_depts,
+ false /* add_required_by */);
prog = true;
break;
}
@@ -7072,6 +7154,8 @@ namespace bpkg
//
assert (!dsp->system ());
+ package_version_key pvk (pdb, n, version ());
+
return build_package {
build_package::adjust,
ddb,
@@ -7093,7 +7177,7 @@ namespace bpkg
nullopt, // Checkout root.
false, // Checkout purge.
strings (), // Configuration variables.
- {package_key {pdb, n}}, // Required by (dependency).
+ {move (pvk)}, // Required by (dependency).
false, // Required by dependents.
build_package::adjust_reconfigure};
};
@@ -7160,11 +7244,29 @@ namespace bpkg
i->second.position = insert (pos, i->second.package);
}
- // Add this dependent's contraint, if present, to the dependency's
- // constraints list for completeness.
+ // Add this dependent's constraint, if present, to the dependency's
+ // constraints list for completeness, while suppressing duplicates.
//
if (dc)
- p.constraints.emplace_back (ddb, move (dn).string (), move (*dc));
+ {
+ using constraint_type = build_package::constraint_type;
+
+ constraint_type c (move (*dc),
+ ddb,
+ move (dn),
+ i->second.package.selected->version,
+ true /* selected_dependent */);
+
+ if (find_if (p.constraints.begin (), p.constraints.end (),
+ [&c] (const constraint_type& v)
+ {
+ return v.dependent == c.dependent &&
+ v.value == c.value;
+ }) == p.constraints.end ())
+ {
+ p.constraints.emplace_back (move (c));
+ }
+ }
// Recursively collect our own dependents inserting them before us.
//
@@ -7200,7 +7302,8 @@ namespace bpkg
print_constraints (diag_record& dr,
const build_package& p,
string& indent,
- set<package_key>& printed) const
+ set<package_key>& printed,
+ optional<bool> selected_dependent) const
{
using constraint_type = build_package::constraint_type;
@@ -7216,33 +7319,35 @@ namespace bpkg
for (const constraint_type& c: cs)
{
- if (const build_package* d = dependent_build (c))
+ if (!selected_dependent ||
+ *selected_dependent == c.selected_dependent)
{
- dr << '\n' << indent << c.dependent << '/';
+ if (const build_package* d = dependent_build (c))
+ {
+ dr << '\n' << indent << c.dependent << " requires (" << pk
+ << ' ' << c.value << ')';
- // The dependent can only be collected as a build or adjustment.
- //
- assert (d->action &&
- d->action != build_package::drop &&
- (d->available || d->selected));
-
- dr << (d->available != nullptr
- ? d->available_version ()
- : d->selected->version) << c.db << " requires (" << pk
- << ' ' << c.value << ")";
-
- indent += " ";
- print_constraints (dr, *d, indent, printed);
- indent.resize (indent.size () - 2);
+ indent += " ";
+ print_constraints (dr, *d, indent, printed, selected_dependent);
+ indent.resize (indent.size () - 2);
+ }
+ else
+ dr << '\n' << indent << c.dependent << " requires (" << pk << ' '
+ << c.value << ')';
}
- else
- dr << '\n' << indent << c.dependent << " requires (" << pk << ' '
- << c.value << ")";
}
}
else
{
- dr << '\n' << indent << "...";
+ for (const constraint_type& c: cs)
+ {
+ if (!selected_dependent ||
+ *selected_dependent == c.selected_dependent)
+ {
+ dr << '\n' << indent << "...";
+ break;
+ }
+ }
}
}
}
@@ -7251,11 +7356,12 @@ namespace bpkg
print_constraints (diag_record& dr,
const package_key& pk,
string& indent,
- set<package_key>& printed) const
+ set<package_key>& printed,
+ optional<bool> selected_dependent) const
{
const build_package* p (entered_build (pk));
assert (p != nullptr); // Expected to be collected.
- print_constraints (dr, *p, indent, printed);
+ print_constraints (dr, *p, indent, printed, selected_dependent);
}
void build_packages::
@@ -7570,8 +7676,8 @@ namespace bpkg
const shared_ptr<selected_package>& dsp (ed.selected);
- package_key dpt (ed.db, dsp->name);
- const package_key& dep (*ed.dependency);
+ package_version_key dpt (ed.db, dsp->name, dsp->version);
+ const package_key& dep (*ed.dependency);
lazy_shared_ptr<selected_package> lsp (dep.db.get (), dep.name);
shared_ptr<selected_package> sp (lsp.load ());
@@ -7614,9 +7720,11 @@ namespace bpkg
assert (i != dsp->prerequisites.end ());
if (i->second.constraint)
- p.constraints.emplace_back (dpt.db,
- dpt.name.string (),
- *i->second.constraint);
+ p.constraints.emplace_back (*i->second.constraint,
+ dpt.db,
+ dpt.name,
+ *dpt.version,
+ true /* selected_package */);
}
// Note: not recursive.
@@ -7641,6 +7749,11 @@ namespace bpkg
lazy_shared_ptr<repository_fragment>> rp (
find_available_fragment (o, ed.db, ed.selected));
+ set<package_version_key> rb;
+
+ for (package_key& p: ds)
+ rb.emplace (p.db, move (p.name), version ());
+
build_package p {
build_package::build,
ed.db,
@@ -7662,9 +7775,7 @@ namespace bpkg
nullopt, // Checkout root.
false, // Checkout purge.
strings (), // Configuration variables.
- set<package_key> ( // Required by (dependency).
- make_move_iterator (ds.begin ()),
- make_move_iterator (ds.end ())),
+ move (rb), // Required by (dependency).
false, // Required by dependents.
build_package::build_reevaluate};
@@ -7680,7 +7791,8 @@ namespace bpkg
replaced_versions& replaced_vers,
postponed_packages& postponed_recs,
postponed_configurations& postponed_cfgs,
- unsatisfied_dependents& unsatisfied_depts)
+ unsatisfied_dependents& unsatisfied_depts,
+ bool add_required_by)
{
pair<shared_ptr<available_package>,
lazy_shared_ptr<repository_fragment>> rp (
@@ -7693,6 +7805,17 @@ namespace bpkg
if (!ed.dependency)
flags |= build_package::adjust_reconfigure;
+ set<package_version_key> rb;
+
+ if (add_required_by)
+ {
+ const package_key& pk (ed.originating_dependency);
+
+ assert (entered_build (pk) != nullptr); // Expected to be collected.
+
+ rb.emplace (pk.db, pk.name, version ());
+ }
+
build_package p {
build_package::build,
ed.db,
@@ -7714,7 +7837,7 @@ namespace bpkg
nullopt, // Checkout root.
false, // Checkout purge.
strings (), // Configuration variables.
- {ed.originating_dependency}, // Required by (dependency).
+ move (rb), // Required by (dependency).
false, // Required by dependents.
flags};
diff --git a/bpkg/pkg-build-collect.hxx b/bpkg/pkg-build-collect.hxx
index 5a5a397..e34fc25 100644
--- a/bpkg/pkg-build-collect.hxx
+++ b/bpkg/pkg-build-collect.hxx
@@ -196,24 +196,43 @@ namespace bpkg
optional<bool> hold_package;
optional<bool> hold_version;
- // Constraint value plus, normally, the dependent package name that placed
- // this constraint but can also be some other name for the initial
- // selection. This is why we use the string type, rather than
- // package_name. Currently, the only valid non-package name is "command
- // line", which is used when the package version is specified by the user
- // on the command line.
+ // Constraint value plus, normally, the dependent package name/version
+ // that placed this constraint but can also be some other name (in which
+ // case the version is absent) for the initial selection. Currently, the
+ // only valid non-package name is 'command line', which is used when the
+ // package version is constrained by the user on the command line.
//
// Note that if the dependent is a package name, then this package is
// expected to be collected (present in the map).
//
struct constraint_type
{
- reference_wrapper<database> db; // Main database for non-packages.
- string dependent;
version_constraint value;
- constraint_type (database& d, string dp, version_constraint v)
- : db (d), dependent (move (dp)), value (move (v)) {}
+ package_version_key dependent;
+
+ // False for non-packages. Otherwise, indicates whether the constraint
+ // comes from the selected dependent or not.
+ //
+ bool selected_dependent;
+
+ // Create constraint for a package dependent.
+ //
+ constraint_type (version_constraint v,
+ database& db,
+ package_name nm,
+ version ver,
+ bool s)
+ : value (move (v)),
+ dependent (db, move (nm), move (ver)),
+ selected_dependent (s) {}
+
+ // Create constraint for a non-package dependent.
+ //
+ constraint_type (version_constraint v, database& db, string nm)
+ : value (move (v)),
+ dependent (db, move (nm)),
+ selected_dependent (false) {}
};
vector<constraint_type> constraints;
@@ -273,11 +292,23 @@ namespace bpkg
strings config_vars;
// Set of packages (dependents or dependencies but not a mix) that caused
- // this package to be built or adjusted. Empty name signifies user
- // selection and can be present regardless of the required_by_dependents
- // flag value.
+ // this package to be built or adjusted. The 'command line' name signifies
+ // user selection and can be present regardless of the
+ // required_by_dependents flag value.
//
- std::set<package_key> required_by;
+ // Note that if this is a package name, then this package is expected to
+ // be collected (present in the map), potentially just pre-entered if
+ // required_by_dependents is false.
+ //
+ // Also note that if required_by_dependents is true, then all the
+ // dependent package versions in the required_by set are expected to be
+ // known (the version members are not empty). Otherwise (the required_by
+ // set contains dependencies), since it's not always easy to deduce the
+ // dependency versions at the time of collecting the dependent build (see
+ // collect_repointed_dependents() implementation for details), the
+ // dependency package versions are expected to all be unknown.
+ //
+ std::set<package_version_key> required_by;
// If this flags is true, then required_by contains dependents.
//
@@ -1583,17 +1614,22 @@ namespace bpkg
// constraints for the same package twice, printing "..." instead. Noop if
// there are no constraints for this package.
//
+ // Optionally, only print constraints from the selected or being built
+ // dependents (see build_package::constraint_type for details).
+ //
void
print_constraints (diag_record&,
const build_package&,
string& indent,
- std::set<package_key>& printed) const;
+ std::set<package_key>& printed,
+ optional<bool> selected_dependent = nullopt) const;
void
print_constraints (diag_record&,
const package_key&,
string& indent,
- std::set<package_key>& printed) const;
+ std::set<package_key>& printed,
+ optional<bool> selected_dependent = nullopt) const;
// Verify that builds ordering is consistent across all the data
// structures and the ordering expectations are fulfilled (real build
@@ -1698,7 +1734,8 @@ namespace bpkg
replaced_versions&,
postponed_packages& postponed_recs,
postponed_configurations&,
- unsatisfied_dependents&);
+ unsatisfied_dependents&,
+ bool add_required_by);
struct package_ref
{
diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx
index 588d29c..5c41204 100644
--- a/bpkg/pkg-build.cxx
+++ b/bpkg/pkg-build.cxx
@@ -1660,6 +1660,10 @@ namespace bpkg
? empty_string
: '[' + config_dirs[0].representation () + ']'));
+ // Command line as a dependent.
+ //
+ package_version_key cmd_line (mdb, "command line");
+
current_configs.push_back (mdb);
if (config_dirs.size () != 1)
@@ -3609,7 +3613,7 @@ namespace bpkg
: optional<dir_path> ()),
pa.options.checkout_purge (),
move (pa.config_vars),
- {package_key {mdb, ""}}, // Required by (command line).
+ {cmd_line}, // Required by (command line).
false, // Required by dependents.
replace ? build_package::build_replace : uint16_t (0)};
@@ -3623,7 +3627,7 @@ namespace bpkg
//
if (pa.constraint)
p.constraints.emplace_back (
- mdb, "command line", move (*pa.constraint));
+ move (*pa.constraint), cmd_line.db, cmd_line.name.string ());
pkg_confs.emplace_back (p.db, p.name ());
@@ -3741,7 +3745,7 @@ namespace bpkg
nullopt, // Checkout root.
false, // Checkout purge.
strings (), // Configuration variables.
- {package_key {mdb, ""}}, // Required by (command line).
+ {cmd_line}, // Required by (command line).
false, // Required by dependents.
deorphan ? build_package::build_replace : uint16_t (0)};
@@ -4082,7 +4086,8 @@ namespace bpkg
// Also, if a dependency package already has selected package that
// is held, then we need to unhold it.
//
- auto enter = [&mdb, &pkgs] (database& db, const dependency_package& p)
+ auto enter = [&pkgs, &cmd_line] (database& db,
+ const dependency_package& p)
{
build_package bp {
nullopt, // Action.
@@ -4105,13 +4110,14 @@ namespace bpkg
p.checkout_root,
p.checkout_purge,
p.config_vars,
- {package_key {mdb, ""}}, // Required by (command line).
+ {cmd_line}, // Required by (command line).
false, // Required by dependents.
0}; // State flags.
if (p.constraint)
- bp.constraints.emplace_back (
- mdb, "command line", *p.constraint);
+ bp.constraints.emplace_back (*p.constraint,
+ cmd_line.db,
+ cmd_line.name.string ());
pkgs.enter (p.name, move (bp));
};
@@ -4403,7 +4409,7 @@ namespace bpkg
nullopt, // Checkout root.
false, // Checkout purge.
strings (), // Configuration variables.
- {package_key {mdb, ""}}, // Required by (command line).
+ {cmd_line}, // Required by (command line).
false, // Required by dependents.
(d.existing || d.deorphan
? build_package::build_replace
@@ -5600,12 +5606,17 @@ namespace bpkg
// can a dependent-dependency structure change without any of
// the package versions changing? Doesn't feel like it should.
//
- for (const package_key& pk: p.required_by)
+ for (const package_version_key& pvk: p.required_by)
{
- // Skip the command-line dependent.
+ // Skip the command-line, etc dependents and don't print the
+ // package version (which is not always available; see
+ // build_package::required_by for details).
//
- if (!pk.name.empty ())
- rb += (rb.empty () ? " " : ", ") + pk.string ();
+ if (pvk.version) // Is it a real package?
+ {
+ rb += (rb.empty () ? " " : ", ") +
+ pvk.string (true /* ignore_version */);
+ }
}
// If not user-selected, then there should be another (implicit)
diff --git a/bpkg/rep-create.cxx b/bpkg/rep-create.cxx
index 67cca95..9b9bdeb 100644
--- a/bpkg/rep-create.cxx
+++ b/bpkg/rep-create.cxx
@@ -24,7 +24,7 @@ using namespace butl;
namespace bpkg
{
- struct package_version_key
+ struct package_name_version
{
package_name name;
bpkg::version version;
@@ -34,20 +34,20 @@ namespace bpkg
// revision.
//
bool
- operator< (const package_version_key& y) const
+ operator< (const package_name_version& y) const
{
int r (name.compare (y.name));
return r < 0 || (r == 0 && version.compare (y.version, true) < 0);
}
};
- struct package_version_data
+ struct package_data
{
path archive;
package_manifest manifest;
};
- using package_map = map<package_version_key, package_version_data>;
+ using package_map = map<package_name_version, package_data>;
static void
collect (const rep_create_options& o,
@@ -116,8 +116,8 @@ namespace bpkg
//
m.location = a.leaf (root);
- package_version_key k {m.name, m.version}; // Argument evaluation order.
- auto r (map.emplace (move (k), package_version_data {a, move (m)}));
+ package_name_version k {m.name, m.version}; // Argument evaluation order.
+ auto r (map.emplace (move (k), package_data {a, move (m)}));
// Diagnose duplicates.
//
diff --git a/tests/pkg-build.testscript b/tests/pkg-build.testscript
index 0efe4ff..eec268e 100644
--- a/tests/pkg-build.testscript
+++ b/tests/pkg-build.testscript
@@ -1392,7 +1392,7 @@ test.arguments += --sys-no-query
$* libfoo/1.0.0 2>>EOE != 0;
error: unable to downgrade package libfoo/1.1.0 to 1.0.0
- info: because package libbar depends on (libfoo == 1.1.0)
+ info: because configured package libbar/1.1.0 depends on (libfoo == 1.1.0)
info: consider re-trying with --upgrade|-u potentially combined with --recursive|-r
info: or explicitly request up/downgrade of package libbar
info: or explicitly specify package libfoo version to manually satisfy these constraints
@@ -1428,7 +1428,7 @@ test.arguments += --sys-no-query
$* libfoo/1.0.0 +{ --config-id 1 } 2>>~%EOE% != 0;
%error: unable to downgrade package libfoo/1.1.0 \[cfg.\] to 1.0.0%
- % info: because package libbar \[cfg.\] depends on \(libfoo == 1.1.0\)%
+ % info: because configured package libbar/1.1.0 \[cfg.\] depends on \(libfoo == 1.1.0\)%
info: consider re-trying with --upgrade|-u potentially combined with --recursive|-r
info: or explicitly request up/downgrade of package libbar
info: or explicitly specify package libfoo version to manually satisfy these constraints
@@ -2164,8 +2164,8 @@ test.arguments += --sys-no-query
#
$* foo 2>>EOE != 0;
error: unable to satisfy constraints on package libbar
- info: libbaz depends on (libbar ^2.0.0)
- info: libbox depends on (libbar ^1.0.0)
+ info: libbaz/2.0.0 depends on (libbar ^2.0.0)
+ info: libbox/1.0.0 depends on (libbar ^1.0.0)
info: available libbar/2.0.0
info: available libbar/1.0.0
info: while satisfying libbox/1.0.0
@@ -2234,8 +2234,9 @@ test.arguments += --sys-no-query
#
$* ?libbaz 2>>EOE != 0;
error: unable to upgrade package libbar/1.0.0 to 2.0.0
- info: because package libbox depends on (libbar ^1.0.0)
- info: package libbar/2.0.0 required by libbaz
+ info: because configured package libbox/1.0.0 depends on (libbar ^1.0.0)
+ info: package libbar/2.0.0 required by
+ libbaz/2.0.0 (libbar ^2.0.0)
info: consider re-trying with --upgrade|-u potentially combined with --recursive|-r
info: or explicitly request up/downgrade of package libbox
info: or explicitly specify package libbar version to manually satisfy these constraints
@@ -2259,8 +2260,8 @@ test.arguments += --sys-no-query
#
$* foo 2>>EOE != 0;
error: unable to satisfy constraints on package libbar
- info: libbaz depends on (libbar ^2.0.0)
- info: libbox depends on (libbar ^1.0.0)
+ info: libbaz/2.0.0 depends on (libbar ^2.0.0)
+ info: libbox/1.1.0 depends on (libbar ^1.0.0)
info: available libbar/2.0.0
info: available libbar/1.0.0
info: while satisfying libbox/1.1.0
@@ -2329,8 +2330,9 @@ test.arguments += --sys-no-query
#
$* foo ?libbaz 2>>EOE != 0;
error: unable to upgrade package libbar/1.0.0 to 2.0.0
- info: because package libbox depends on (libbar ^1.0.0)
- info: package libbar/2.0.0 required by libbaz
+ info: because configured package libbox/1.0.0 depends on (libbar ^1.0.0)
+ info: package libbar/2.0.0 required by
+ libbaz/2.0.0 (libbar ^2.0.0)
info: consider re-trying with --upgrade|-u potentially combined with --recursive|-r
info: or explicitly request up/downgrade of package libbox
info: or explicitly specify package libbar version to manually satisfy these constraints
@@ -2341,8 +2343,8 @@ test.arguments += --sys-no-query
#
$* foo ?libbaz ?libbox 2>>EOE != 0;
error: unable to satisfy constraints on package libbar
- info: libbaz depends on (libbar ^2.0.0)
- info: libbox depends on (libbar ^1.0.0)
+ info: libbaz/2.0.0 depends on (libbar ^2.0.0)
+ info: libbox/1.1.0 depends on (libbar ^1.0.0)
info: available libbar/2.0.0
info: available libbar/1.0.0
info: while satisfying libbox/1.1.0
@@ -2833,8 +2835,8 @@ test.arguments += --sys-no-query
$* libfix libbiz 2>>EOE != 0;
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: libfix/0.0.3 depends on (libbaz >= 0.0.3)
+ info: libbiz/0.0.2 depends on (libbaz <= 0.0.3)
info: available libbaz/0.1.0
info: available libbaz/0.0.2
info: while satisfying libbiz/0.0.2
@@ -2907,8 +2909,8 @@ test.arguments += --sys-no-query
$* libbiz 2>>EOE != 0;
error: unable to satisfy constraints on package libfoo
- info: libbox depends on (libfoo == 1.0.0)
- info: libfox depends on (libfoo == 0.0.1)
+ info: libbox/0.0.2 depends on (libfoo == 1.0.0)
+ info: libfox/0.0.2 depends on (libfoo == 0.0.1)
info: available libfoo/1.0.0
info: available libfoo/0.0.1
info: while satisfying libbox/0.0.2
@@ -4448,7 +4450,7 @@ test.arguments += --sys-no-query
$* box +{ config.box.extras=true } libbox/0.1.0 2>>EOE != 0;
error: unable to satisfy constraints on package libbox
info: command line depends on (libbox == 0.1.0)
- info: box depends on (libbox >= 0.1.1)
+ info: box/1.0.0 depends on (libbox >= 0.1.1)
info: available libbox/0.1.0
info: available libbox/1.0.0
info: while satisfying box/1.0.0
@@ -5815,8 +5817,9 @@ test.arguments += --sys-no-query
$* tax 2>>EOE != 0;
error: unable to downgrade package libfoo/2.0.0 to 1.0.0
- info: because package tpx depends on (libfoo >= 2.0.0)
- info: package libfoo/1.0.0 required by tax
+ info: because configured package tpx/1.0.0 depends on (libfoo >= 2.0.0)
+ info: package libfoo/1.0.0 required by
+ tax/1.0.0 (libfoo == 1.0.0)
info: consider re-trying with --upgrade|-u potentially combined with --recursive|-r
info: or explicitly request up/downgrade of package tpx
info: or explicitly specify package libfoo version to manually satisfy these constraints
@@ -5829,7 +5832,7 @@ test.arguments += --sys-no-query
#
$* tax tpx ?libfoo/1.0.0 2>>EOE != 0;
error: unable to downgrade package libfoo/2.0.0 to 1.0.0
- info: because package tpx depends on (libfoo >= 2.0.0)
+ info: because configured package tpx/1.0.0 depends on (libfoo >= 2.0.0)
info: consider re-trying with --upgrade|-u potentially combined with --recursive|-r
info: or explicitly request up/downgrade of package tpx
info: or explicitly specify package libfoo version to manually satisfy these constraints
@@ -9647,8 +9650,8 @@ test.arguments += --sys-no-query
trace: execute_plan: while configuring dependent tez/1.0.0 in simulation mode unconstrain (toz == 0.1.0)
%.*
error: unable to satisfy constraints on package toz
- info: tvz depends on (toz == 0.2.0)
- info: tez depends on (toz == 0.1.0)
+ info: tvz/1.0.0 depends on (toz == 0.2.0)
+ info: tez/1.0.0 depends on (toz == 0.1.0)
info: available toz/0.2.0
info: available toz/0.1.0
info: while satisfying tez/1.0.0
@@ -9841,9 +9844,9 @@ test.arguments += --sys-no-query
trace: execute_plan: while configuring dependent tez/1.0.0 in simulation mode unconstrain (toz == 0.1.0)
%.*
error: unable to satisfy constraints on package toz
- info: tvz depends on (toz == 0.2.0)
+ info: tvz/0.1.0 depends on (toz == 0.2.0)
command line requires (tvz == 0.1.0)
- info: tez depends on (toz == 0.1.0)
+ info: tez/1.0.0 depends on (toz == 0.1.0)
info: available toz/0.2.0
info: available toz/0.1.0
info: while satisfying tez/1.0.0
@@ -16957,8 +16960,8 @@ test.arguments += --sys-no-query
#
$* tvz --verbose 1 2>>EOE != 0;
error: unable to satisfy constraints on package toz
- info: tvz depends on (toz == 0.2.0)
- info: tez depends on (toz == 0.1.0)
+ info: tvz/1.0.0 depends on (toz == 0.2.0)
+ info: tez/1.0.0 depends on (toz == 0.1.0)
info: available toz/0.2.0
info: available toz/0.1.0
info: while satisfying tez/1.0.0
@@ -24765,7 +24768,7 @@ else
$* ?libbaz/1.0.0 +{ --config-name h2 } 2>>~%EOE% != 0;
%error: unable to downgrade package libbaz/1.1.0 \[h2.\] to 1.0.0%
- % info: because package foo \[h2.\] depends on \(libbaz \^1.1.0\)%
+ % info: because configured package foo/1.1.0 \[h2.\] depends on \(libbaz \^1.1.0\)%
info: consider re-trying with --upgrade|-u potentially combined with --recursive|-r
info: or explicitly request up/downgrade of package foo
info: or explicitly specify package libbaz version to manually satisfy these constraints
@@ -28185,7 +28188,7 @@ else
$* libbar $src/libfoo-1.0.0.tar.gz 2>>~%EOE% != 0
error: unable to satisfy constraints on package libfoo
info: command line depends on (libfoo == 1.0.0)
- info: libbar depends on (libfoo == 1.1.0)
+ info: libbar/1.1.0 depends on (libfoo == 1.1.0)
info: available libfoo/1.0.0
info: available libfoo/1.1.0
info: while satisfying libbar/1.1.0
@@ -28204,7 +28207,7 @@ else
$* $src/libbar-1.1.0.tar.gz $src/libfoo-1.0.0.tar.gz 2>>~%EOE% != 0
error: unable to satisfy constraints on package libfoo
info: command line depends on (libfoo == 1.0.0)
- info: libbar depends on (libfoo == 1.1.0)
+ info: libbar/1.1.0 depends on (libfoo == 1.1.0)
command line requires (libbar == 1.1.0)
info: available libfoo/1.0.0
info: available libfoo/1.1.0
@@ -28615,7 +28618,7 @@ else
$* libbar $d/libfoo-1.0.0/ 2>>~%EOE% != 0
error: unable to satisfy constraints on package libfoo
info: command line depends on (libfoo == 1.0.0)
- info: libbar depends on (libfoo == 1.1.0)
+ info: libbar/1.1.0 depends on (libfoo == 1.1.0)
info: available libfoo/1.0.0
info: available libfoo/1.1.0
info: while satisfying libbar/1.1.0
@@ -28634,7 +28637,7 @@ else
$* $d/libbar-1.1.0/ $d/libfoo-1.0.0/ 2>>~%EOE% != 0
error: unable to satisfy constraints on package libfoo
info: command line depends on (libfoo == 1.0.0)
- info: libbar depends on (libfoo == 1.1.0)
+ info: libbar/1.1.0 depends on (libfoo == 1.1.0)
command line requires (libbar == 1.1.0)
info: available libfoo/1.0.0
info: available libfoo/1.1.0
diff --git a/tests/pkg-system.testscript b/tests/pkg-system.testscript
index 8aaabd9..11ed1cc 100644
--- a/tests/pkg-system.testscript
+++ b/tests/pkg-system.testscript
@@ -711,7 +711,7 @@ rep_remove += -d cfg 2>!
$pkg_build foo 'sys:libbar/1' 2>>EOE != 0;
error: unable to satisfy constraints on package libbar
info: command line depends on (libbar == 1)
- info: foo depends on (libbar >= 2)
+ info: foo/2 depends on (libbar >= 2)
info: available sys:libbar/1
info: available sys:libbar/2
info: while satisfying foo/2