aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bpkg/pkg-build.cxx587
-rw-r--r--tests/pkg-build.testscript395
-rw-r--r--tests/pkg-system.testscript18
3 files changed, 804 insertions, 196 deletions
diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx
index 30713ec..db8dafb 100644
--- a/bpkg/pkg-build.cxx
+++ b/bpkg/pkg-build.cxx
@@ -770,6 +770,8 @@ namespace bpkg
using build_package_refs =
small_vector<reference_wrapper<const build_package>, 16>;
+ using add_priv_cfg_function = void (database&, dir_path&&);
+
struct build_packages: build_package_list
{
// Packages collection of whose prerequisites has been postponed due the
@@ -796,6 +798,14 @@ namespace bpkg
assert (p.second);
}
+ // Return true if a package is already in the map.
+ //
+ bool
+ entered (database& db, const package_name& name)
+ {
+ return map_.find (db, name) != map_.end ();
+ }
+
// Collect the package being built. Return its pointer if this package
// version was, in fact, added to the map and NULL if it was already there
// or the existing version was preferred. So can be used as bool.
@@ -817,7 +827,7 @@ namespace bpkg
build_package pkg,
const function<find_database_function>& fdb,
const repointed_dependents& rpt_depts,
- private_configs& priv_cfgs,
+ const function<add_priv_cfg_function>& apc,
postponed_packages* recursively = nullptr,
build_package_refs* dep_chain = nullptr)
{
@@ -996,7 +1006,7 @@ namespace bpkg
recursively,
fdb,
rpt_depts,
- priv_cfgs,
+ apc,
*dep_chain);
return &p;
@@ -1024,7 +1034,7 @@ namespace bpkg
postponed_packages* postponed,
const function<find_database_function>& fdb,
const repointed_dependents& rpt_depts,
- private_configs& priv_cfgs,
+ const function<add_priv_cfg_function>& apc,
build_package_refs& dep_chain)
{
tracer trace ("collect_build_prerequisites");
@@ -1417,7 +1427,7 @@ namespace bpkg
// containing configuration database, for their subsequent re-
// link.
//
- priv_cfgs.emplace_back (sdb, move (cd));
+ apc (sdb, move (cd));
db = &sdb.find_attached (*lc->id);
}
@@ -1623,7 +1633,7 @@ namespace bpkg
move (bp),
fdb,
rpt_depts,
- priv_cfgs,
+ apc,
postponed,
&dep_chain));
@@ -1686,7 +1696,7 @@ namespace bpkg
const repointed_dependents& rpt_depts,
build_packages::postponed_packages& postponed,
const function<find_database_function>& fdb,
- private_configs& priv_cfgs)
+ const function<add_priv_cfg_function>& apc)
{
for (const auto& rd: rpt_depts)
{
@@ -1752,7 +1762,7 @@ namespace bpkg
move (p),
fdb,
rpt_depts,
- priv_cfgs,
+ apc,
&postponed,
&dep_chain);
}
@@ -1848,7 +1858,7 @@ namespace bpkg
postponed_packages& postponed,
const function<find_database_function>& fdb,
const repointed_dependents& rpt_depts,
- private_configs& priv_cfgs)
+ const function<add_priv_cfg_function>& apc)
{
auto mi (map_.find (db, name));
assert (mi != map_.end ());
@@ -1860,7 +1870,7 @@ namespace bpkg
&postponed,
fdb,
rpt_depts,
- priv_cfgs,
+ apc,
dep_chain);
}
@@ -1869,7 +1879,7 @@ namespace bpkg
postponed_packages& pkgs,
const function<find_database_function>& fdb,
const repointed_dependents& rpt_depts,
- private_configs& priv_cfgs)
+ const function<add_priv_cfg_function>& apc)
{
// Try collecting postponed packages for as long as we are making
// progress.
@@ -1887,7 +1897,7 @@ namespace bpkg
prog ? &npkgs : nullptr,
fdb,
rpt_depts,
- priv_cfgs,
+ apc,
dep_chain);
}
@@ -2550,12 +2560,21 @@ namespace bpkg
// List of dependency packages (specified with ? on the command line).
//
+ // If configuration is not specified for a system dependency package (db is
+ // NULL), then the dependency is assumed to be specified for all current
+ // configurations and their explicitly linked configurations, recursively,
+ // including private configurations that can potentially be created during
+ // this run.
+ //
+ // The selected package is not NULL if the database is not NULL and the
+ // dependency package is present in this database.
+ //
struct dependency_package
{
- database& db;
+ database* db; // Can only be NULL if system.
package_name name;
optional<version_constraint> constraint; // nullopt if unspecified.
- shared_ptr<selected_package> selected; // NULL if not present.
+ shared_ptr<selected_package> selected;
bool system;
bool patch; // Only for an empty version.
bool keep_out;
@@ -2672,8 +2691,9 @@ namespace bpkg
}
// Search for the user expectations regarding this dependency by
- // matching the name and configuration type and fail if there are
- // multiple candidates.
+ // matching the package name and configuration type, if configuration is
+ // specified, preferring entries with configuration specified and fail
+ // if there are multiple candidates.
//
if (!cur_dbs.empty ())
{
@@ -2681,30 +2701,42 @@ namespace bpkg
j != deps.end ();
++j)
{
- if (j->name == nm && j->db.type == db.type)
+ if (j->name == nm && (j->db == nullptr || j->db->type == db.type))
{
- if (i == deps.end ())
+ if (i == deps.end () || i->db == nullptr)
+ {
i = j;
- else
+ }
+ else if (j->db != nullptr)
+ {
fail << "multiple " << db.type << " configurations specified "
<< "for dependency package " << nm <<
- info << i->db.config_orig <<
- info << j->db.config_orig;
+ info << i->db->config_orig <<
+ info << j->db->config_orig;
+ }
}
}
}
}
else
{
- i = find_if (deps.begin (), deps.end (),
- [&db, &nm] (const dependency_package& i)
- {
- return i.name == nm && i.db == db;
- });
+ for (dependency_packages::const_iterator j (deps.begin ());
+ j != deps.end ();
+ ++j)
+ {
+ if (j->name == nm && (i->db == nullptr || *i->db == db))
+ {
+ if (i == deps.end () || i->db == nullptr)
+ i = j;
+
+ if (i->db != nullptr)
+ break;
+ }
+ }
}
bool user_exp (i != deps.end ());
- bool copy_dep (user_exp && i->db != db);
+ bool copy_dep (user_exp && i->db != nullptr && *i->db != db);
// Collect the dependents for checking the version constraints, using
// their repository fragments for discovering available dependency package
@@ -2719,7 +2751,7 @@ namespace bpkg
if (copy_dep)
{
- for (database& db: i->db.dependent_configs ())
+ for (database& db: i->db->dependent_configs ())
{
if (find (cur_dbs.begin (), cur_dbs.end (), db) != cur_dbs.end ())
dep_dbs.push_back (db);
@@ -2772,7 +2804,7 @@ namespace bpkg
//
assert (i != deps.end ());
- database& ddb (i->db);
+ database& ddb (i->db != nullptr ? *i->db : db);
const optional<version_constraint>& dvc (i->constraint); // May be nullopt.
bool dsys (i->system);
@@ -3671,16 +3703,13 @@ namespace bpkg
add_db (*db);
}
+ // Note that unspecified package configuration in the multi-
+ // configurations mode is an error, unless this is a system
+ // dependency. We, however, do not parse the package scheme at this
+ // stage and so delay the potential failure.
+ //
if (dbs.empty ())
- {
- if (multi_config ())
- fail << "no configuration specified for " << a <<
- info << "configuration must be explicitly specified for each "
- << "package in multi-configurations mode" <<
- info << "use --config-uuid to specify its configuration";
-
dbs.push_back (mdb);
- }
if (!a.empty () && a[0] == '?')
{
@@ -3900,7 +3929,10 @@ namespace bpkg
//
struct pkg_arg
{
- reference_wrapper<database> db;
+ // NULL for system dependency with unspecified configuration.
+ //
+ database* db;
+
package_scheme scheme;
package_name name;
optional<version_constraint> constraint;
@@ -3909,71 +3941,6 @@ namespace bpkg
strings config_vars;
};
- // Create the parsed package argument.
- //
- auto arg_package = [] (database& db,
- package_scheme sc,
- package_name nm,
- optional<version_constraint> vc,
- pkg_options os,
- strings vs) -> pkg_arg
- {
- assert (!vc || !vc->empty ()); // May not be empty if present.
-
- pkg_arg r {
- db, sc, move (nm), move (vc), string (), move (os), move (vs)};
-
- switch (sc)
- {
- case package_scheme::sys:
- {
- if (!r.constraint)
- r.constraint = version_constraint (wildcard_version);
-
- // The system package may only have an exact/wildcard version
- // specified.
- //
- assert (r.constraint->min_version == r.constraint->max_version);
-
- assert (db.system_repository);
-
- const system_package* sp (db.system_repository->find (r.name));
-
- // Will deal with all the duplicates later.
- //
- if (sp == nullptr || !sp->authoritative)
- {
- assert (db.system_repository);
-
- db.system_repository->insert (r.name,
- *r.constraint->min_version,
- true /* authoritative */);
- }
-
- break;
- }
- case package_scheme::none: break; // Nothing to do.
- }
-
- return r;
- };
-
- // Create the unparsed package argument.
- //
- auto arg_raw = [] (database& db,
- string v,
- pkg_options os,
- strings vs) -> pkg_arg
- {
- return pkg_arg {db,
- package_scheme::none,
- package_name (),
- nullopt /* constraint */,
- move (v),
- move (os),
- move (vs)};
- };
-
auto arg_parsed = [] (const pkg_arg& a) {return !a.name.empty ();};
auto arg_sys = [&arg_parsed] (const pkg_arg& a)
@@ -4086,6 +4053,96 @@ namespace bpkg
return r;
};
+ // Add the system package authoritative information to the database's
+ // system repository, unless it already contains authoritative information
+ // for this package.
+ //
+ // Note that it is assumed that all the possible duplicates are handled
+ // elsewhere/later.
+ //
+ auto add_system_package = [] (database& db,
+ const package_name& nm,
+ const version& v)
+ {
+ assert (db.system_repository);
+
+ const system_package* sp (db.system_repository->find (nm));
+
+ if (sp == nullptr || !sp->authoritative)
+ db.system_repository->insert (nm, v, true /* authoritative */);
+ };
+
+ // Create the parsed package argument. Issue diagnostics and fail if the
+ // package specification is invalid.
+ //
+ auto arg_package = [&arg_string, &add_system_package]
+ (database* db,
+ package_scheme sc,
+ package_name nm,
+ optional<version_constraint> vc,
+ pkg_options os,
+ strings vs) -> pkg_arg
+ {
+ assert (!vc || !vc->empty ()); // May not be empty if present.
+
+ if (db == nullptr)
+ assert (sc == package_scheme::sys && os.dependency ());
+
+ pkg_arg r {
+ db, sc, move (nm), move (vc), string (), move (os), move (vs)};
+
+ // Verify that the package database is specified in the multi-config
+ // mode, unless this is a system dependency package.
+ //
+ if (multi_config () &&
+ !os.config_uuid_specified () &&
+ !(db == nullptr &&
+ sc == package_scheme::sys &&
+ os.dependency ()))
+ fail << "no configuration specified for " << arg_string (r) <<
+ info << "configuration must be explicitly specified for each "
+ << "package in multi-configurations mode" <<
+ info << "use --config-uuid to specify its configuration";
+
+ switch (sc)
+ {
+ case package_scheme::sys:
+ {
+ if (!r.constraint)
+ r.constraint = version_constraint (wildcard_version);
+
+ // The system package may only have an exact/wildcard version
+ // specified.
+ //
+ assert (r.constraint->min_version == r.constraint->max_version);
+
+ if (db != nullptr)
+ add_system_package (*db, r.name, *r.constraint->min_version);
+
+ break;
+ }
+ case package_scheme::none: break; // Nothing to do.
+ }
+
+ return r;
+ };
+
+ // Create the unparsed package argument.
+ //
+ auto arg_raw = [] (database& db,
+ string v,
+ pkg_options os,
+ strings vs) -> pkg_arg
+ {
+ return pkg_arg {&db,
+ package_scheme::none,
+ package_name (),
+ nullopt /* constraint */,
+ move (v),
+ move (os),
+ move (vs)};
+ };
+
vector<pkg_arg> pkg_args;
{
// Cache the system stubs to create the imaginary system repository at
@@ -4153,11 +4210,22 @@ namespace bpkg
if (sys && vc)
stubs.push_back (make_shared<available_package> (n));
- pkg_args.push_back (arg_package (ps.db,
+ pkg_options& o (ps.options);
+
+ // Disregard the (main) database for a system dependency with
+ // unspecified configuration.
+ //
+ bool no_db (sys &&
+ o.dependency () &&
+ !o.config_name_specified () &&
+ !o.config_id_specified () &&
+ !o.config_uuid_specified ());
+
+ pkg_args.push_back (arg_package (no_db ? nullptr : &ps.db.get (),
sc,
move (n),
move (vc),
- move (ps.options),
+ move (o),
move (ps.config_vars)));
}
else // Add unparsed.
@@ -4268,7 +4336,7 @@ namespace bpkg
info << "package " << pv.first << " is not present in "
<< "configuration";
else
- pkg_args.push_back (arg_package (pdb,
+ pkg_args.push_back (arg_package (&pdb,
package_scheme::none,
pv.first,
version_constraint (pv.second),
@@ -4383,7 +4451,11 @@ namespace bpkg
// Don't move options and variables as they may be reused.
//
- pkg_args.push_back (arg_package (pdb,
+ // Note that this cannot be a system dependency with unspecified
+ // configuration since location is specified and so we always pass
+ // the database to the constructor.
+ //
+ pkg_args.push_back (arg_package (&pdb,
sc,
move (n),
move (vc),
@@ -4398,9 +4470,9 @@ namespace bpkg
imaginary_stubs = move (stubs);
}
- // List of packages specified on the command line.
+ // List of package configurations specified on the command line.
//
- vector<config_package> conf_pkgs;
+ vector<config_package> pkg_confs;
// Separate the packages specified on the command line into to hold and to
// up/down-grade as dependencies, and save dependents whose dependencies
@@ -4414,14 +4486,34 @@ namespace bpkg
// Check if the package is a duplicate. Return true if it is but
// harmless.
//
- map<config_package, pkg_arg> package_map;
+ struct config_package_key // Like config_package but with NULL'able db.
+ {
+ package_name name;
+ database* db; // Can be NULL for system dependency.
+
+ config_package_key (package_name n, database* d)
+ : name (move (n)), db (d) {}
+
+ bool
+ operator< (const config_package_key& v) const
+ {
+ if (int r = name.compare (v.name))
+ return r < 0;
+
+ return db != nullptr && v.db != nullptr ? *db < *v.db :
+ db == nullptr && v.db == nullptr ? false :
+ db == nullptr;
+ }
+ };
+
+ map<config_package_key, pkg_arg> package_map;
auto check_dup = [&package_map, &arg_string, &arg_parsed]
(const pkg_arg& pa) -> bool
{
assert (arg_parsed (pa));
- auto r (package_map.emplace (config_package {pa.db, pa.name}, pa));
+ auto r (package_map.emplace (config_package_key {pa.name, pa.db}, pa));
const pkg_arg& a (r.first->second);
assert (arg_parsed (a));
@@ -4463,9 +4555,7 @@ namespace bpkg
for (auto i (pkg_args.begin ()); i != pkg_args.end (); )
{
pkg_arg& pa (*i);
- database& pdb (pa.db);
-
- lazy_shared_ptr<repository_fragment> root (pdb, empty_string);
+ database* pdb (pa.db);
// Reduce all the potential variations (archive, directory, package
// name, package name/version) to a single available_package object.
@@ -4478,6 +4568,10 @@ namespace bpkg
if (!arg_parsed (pa))
{
+ assert (pdb != nullptr); // Unparsed and so can't be system.
+
+ lazy_shared_ptr<repository_fragment> root (*pdb, empty_string);
+
const char* package (pa.value.c_str ());
// Is this a package archive?
@@ -4604,7 +4698,7 @@ namespace bpkg
//
if (optional<version> v =
package_iteration (o,
- pdb,
+ *pdb,
t,
d,
m.name,
@@ -4686,6 +4780,10 @@ namespace bpkg
if (!pa.options.dependency ())
{
+ assert (pdb != nullptr);
+
+ lazy_shared_ptr<repository_fragment> root (*pdb, empty_string);
+
// 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.
@@ -4697,7 +4795,7 @@ namespace bpkg
assert (!arg_sys (pa));
if (pa.options.patch () &&
- (sp = pdb.find<selected_package> (pa.name)) != nullptr)
+ (sp = pdb->find<selected_package> (pa.name)) != nullptr)
{
c = patch_constraint (sp);
@@ -4756,7 +4854,12 @@ namespace bpkg
l4 ([&]{trace << "stashing recursive package "
<< arg_string (pa);});
- rec_pkgs.push_back (recursive_package {pdb, pa.name, *u, *r});
+ // The above options are meaningless for system packages, so we
+ // just ignore them for a system dependency with unspecified
+ // configuration.
+ //
+ if (pdb != nullptr)
+ rec_pkgs.push_back (recursive_package {*pdb, pa.name, *u, *r});
}
}
@@ -4782,11 +4885,14 @@ namespace bpkg
check_any_available (repo_configs, t, &dr);
}
- // Save before the name move.
- //
- sp = pdb.find<selected_package> (pa.name);
+ if (pdb != nullptr)
+ {
+ // Save before the name move.
+ //
+ sp = pdb->find<selected_package> (pa.name);
- conf_pkgs.emplace_back (pdb, pa.name);
+ pkg_confs.emplace_back (*pdb, pa.name);
+ }
dep_pkgs.push_back (
dependency_package {pdb,
@@ -4806,6 +4912,10 @@ namespace bpkg
// Add the held package to the list.
//
+ assert (pdb != nullptr);
+
+ lazy_shared_ptr<repository_fragment> root (*pdb, empty_string);
+
// 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
@@ -4813,10 +4923,10 @@ namespace bpkg
// the same as the selected package).
//
if (sp == nullptr)
- sp = pdb.find<selected_package> (pa.name);
+ sp = pdb->find<selected_package> (pa.name);
if (sp != nullptr && sp->state == package_state::broken)
- fail << "unable to build broken package " << pa.name << pdb <<
+ fail << "unable to build broken package " << pa.name << *pdb <<
info << "use 'pkg-purge --force' to remove";
bool found (true);
@@ -4919,7 +5029,7 @@ namespace bpkg
// Let's help the new user out here a bit.
//
- check_any_available (pdb, t, &dr);
+ check_any_available (*pdb, t, &dr);
}
else
{
@@ -4942,7 +5052,7 @@ namespace bpkg
{
assert (sp != nullptr && sp->system () == arg_sys (pa));
- auto rp (make_available (o, pdb, sp));
+ auto rp (make_available (o, *pdb, sp));
ap = move (rp.first);
af = move (rp.second); // Could be NULL (orphan).
}
@@ -4963,7 +5073,7 @@ namespace bpkg
//
build_package p {
build_package::build,
- pdb,
+ *pdb,
move (sp),
move (ap),
move (af),
@@ -4994,7 +5104,7 @@ namespace bpkg
p.constraints.emplace_back (
mdb, "command line", move (*pa.constraint));
- conf_pkgs.emplace_back (p.db, p.name ());
+ pkg_confs.emplace_back (p.db, p.name ());
hold_pkgs.push_back (move (p));
}
@@ -5129,7 +5239,7 @@ namespace bpkg
// Also note that we rely on "small function object" optimization here.
//
const function<find_database_function> find_prereq_database (
- [&conf_pkgs] (database& db,
+ [&pkg_confs] (database& db,
const package_name& nm,
bool buildtime) -> database*
{
@@ -5137,7 +5247,7 @@ namespace bpkg
linked_databases ddbs (db.dependency_configs (nm, buildtime));
- for (const config_package& cp: conf_pkgs)
+ for (const config_package& cp: pkg_confs)
{
if (cp.name == nm &&
find (ddbs.begin (), ddbs.end (), cp.db) != ddbs.end ())
@@ -5283,6 +5393,20 @@ namespace bpkg
transaction t (mdb);
+ // Collect all configurations where dependency packages can
+ // potentially be built or amended during this run.
+ //
+ linked_databases dep_dbs;
+
+ for (database& cdb: current_configs)
+ {
+ for (database& db: cdb.dependency_configs ())
+ {
+ if (find (dep_dbs.begin (), dep_dbs.end (), db) == dep_dbs.end ())
+ dep_dbs.push_back (db);
+ }
+ }
+
// Temporarily add the replacement prerequisites to the repointed
// dependent prerequisites sets and persist the changes.
//
@@ -5318,6 +5442,63 @@ namespace bpkg
db.update (sp);
}
+ // Pre-enter dependency to keep track of the desired versions and
+ // options specified on the command line. In particular, if the
+ // version is specified and the dependency is used as part of the
+ // plan, then the desired version must be used. We also need it to
+ // distinguish user-driven dependency up/down-grades from the
+ // dependent-driven ones, not to warn/refuse.
+ //
+ // 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)
+ {
+ build_package bp {
+ nullopt, // Action.
+ db,
+ nullptr, // Selected package.
+ nullptr, // Available package/repo fragment.
+ nullptr,
+ false, // Hold package.
+ p.constraint.has_value (), // Hold version.
+ {}, // Constraints.
+ p.system,
+ p.keep_out,
+ false, // Configure-only.
+ p.checkout_root,
+ p.checkout_purge,
+ p.config_vars,
+ {config_package {mdb, ""}}, // Required by (command line).
+ false, // Required by dependents.
+ 0}; // State flags.
+
+ if (p.constraint)
+ bp.constraints.emplace_back (
+ mdb, "command line", *p.constraint);
+
+ pkgs.enter (p.name, move (bp));
+ };
+
+ // Add the system dependency to the database's system repository and
+ // pre-enter it to the build package map.
+ //
+ auto enter_system_dependency = [&add_system_package, &enter]
+ (database& db, const dependency_package& p)
+ {
+ // The system package may only have an exact/wildcard version
+ // specified.
+ //
+ add_system_package (db,
+ p.name,
+ (p.constraint
+ ? *p.constraint->min_version
+ : wildcard_version));
+
+ enter (db, p);
+ };
+
// Private configurations that were created during collection of the
// package builds.
//
@@ -5336,48 +5517,57 @@ namespace bpkg
//
private_configs priv_cfgs;
+ // Add a newly created private configuration to the private
+ // configurations and the dependency databases lists and pre-enter
+ // builds of system dependencies with unspecified configuration for
+ // this configuration.
+ //
+ const function<add_priv_cfg_function> add_priv_cfg (
+ [&priv_cfgs, &dep_dbs, &dep_pkgs, &enter_system_dependency]
+ (database& pdb, dir_path&& cfg)
+ {
+ database& db (pdb.find_attached (pdb.config / cfg,
+ false /* self */));
+
+ priv_cfgs.emplace_back (pdb, move (cfg));
+
+ dep_dbs.push_back (db);
+
+ for (const dependency_package& p: dep_pkgs)
+ {
+ if (p.db == nullptr)
+ enter_system_dependency (db, p);
+ }
+ });
+
build_packages::postponed_packages postponed;
if (scratch)
{
pkgs.clear ();
- // Pre-enter dependencies to keep track of the desired versions and
- // options specified on the command line. In particular, if the
- // version is specified and the dependency is used as part of the
- // plan, then the desired version must be used. We also need it to
- // distinguish user-driven dependency up/down-grades from the
- // dependent-driven ones, not to warn/refuse.
- //
- // Also, if a dependency package already has selected package that
- // is held, then we need to unhold it.
+ // Pre-enter dependencies with specified configurations.
//
for (const dependency_package& p: dep_pkgs)
{
- build_package bp {
- nullopt, // Action.
- p.db,
- nullptr, // Selected package.
- nullptr, // Available package/repository frag.
- nullptr,
- false, // Hold package.
- p.constraint.has_value (), // Hold version.
- {}, // Constraints.
- p.system,
- p.keep_out,
- false, // Configure-only.
- p.checkout_root,
- p.checkout_purge,
- p.config_vars,
- {config_package {mdb, ""}}, // Required by (command line).
- false, // Required by dependents.
- 0}; // State flags.
-
- if (p.constraint)
- bp.constraints.emplace_back (
- mdb, "command line", *p.constraint);
+ if (p.db != nullptr)
+ enter (*p.db, p);
+ }
- pkgs.enter (p.name, move (bp));
+ // Pre-enter system dependencies with unspecified configuration for
+ // all dependency configurations, excluding those which already have
+ // this dependency pre-entered.
+ //
+ for (const dependency_package& p: dep_pkgs)
+ {
+ if (p.db == nullptr)
+ {
+ for (database& db: dep_dbs)
+ {
+ if (!pkgs.entered (db, p.name))
+ enter_system_dependency (db, p);
+ }
+ }
}
// Pre-collect user selection to make sure dependency-forced
@@ -5389,7 +5579,7 @@ namespace bpkg
p,
find_prereq_database,
rpt_depts,
- priv_cfgs);
+ add_priv_cfg);
// Collect all the prerequisites of the user selection.
//
@@ -5400,7 +5590,7 @@ namespace bpkg
postponed,
find_prereq_database,
rpt_depts,
- priv_cfgs);
+ add_priv_cfg);
// Note that we need to collect unheld after prerequisites, not to
// overwrite the pre-entered entries before they are used to provide
@@ -5408,8 +5598,26 @@ namespace bpkg
//
for (const dependency_package& p: dep_pkgs)
{
- if (p.selected != nullptr && p.selected->hold_package)
- pkgs.collect_unhold (p.db, p.selected);
+ auto unhold = [&p, &pkgs] (database& db)
+ {
+ shared_ptr<selected_package> sp (
+ p.db != nullptr
+ ? p.selected
+ : db.find<selected_package> (p.name));
+
+ if (sp != nullptr && sp->hold_package)
+ pkgs.collect_unhold (db, sp);
+ };
+
+ if (p.db != nullptr)
+ {
+ unhold (*p.db);
+ }
+ else
+ {
+ for (database& db: dep_dbs)
+ unhold (db);
+ }
}
// Collect dependents whose dependencies need to be repointed to
@@ -5419,7 +5627,7 @@ namespace bpkg
rpt_depts,
postponed,
find_prereq_database,
- priv_cfgs);
+ add_priv_cfg);
scratch = false;
}
@@ -5478,7 +5686,7 @@ namespace bpkg
move (p),
find_prereq_database,
rpt_depts,
- priv_cfgs,
+ add_priv_cfg,
&postponed /* recursively */,
&dep_chain);
}
@@ -5491,7 +5699,7 @@ namespace bpkg
postponed,
find_prereq_database,
rpt_depts,
- priv_cfgs);
+ add_priv_cfg);
// Now that we have collected all the package versions that we need to
// build, arrange them in the "dependency order", that is, with every
@@ -5537,12 +5745,30 @@ namespace bpkg
//
for (const dependency_package& p: dep_pkgs)
{
- if (p.selected != nullptr && p.selected->hold_package)
- pkgs.order (p.db,
- p.name,
- nullopt /* buildtime */,
- find_prereq_database,
- false /* reorder */);
+ auto order_unheld = [&p, &pkgs, &find_prereq_database] (database& db)
+ {
+ shared_ptr<selected_package> sp (
+ p.db != nullptr
+ ? p.selected
+ : db.find<selected_package> (p.name));
+
+ if (sp != nullptr && sp->hold_package)
+ pkgs.order (db,
+ p.name,
+ nullopt /* buildtime */,
+ find_prereq_database,
+ false /* reorder */);
+ };
+
+ if (p.db != nullptr)
+ {
+ order_unheld (*p.db);
+ }
+ else
+ {
+ for (database& db: dep_dbs)
+ order_unheld (db);
+ }
}
// Now, as we are done with package builds collecting/ordering, erase
@@ -5750,7 +5976,7 @@ namespace bpkg
// make sure that the unsatisfiable dependency, if left, is
// reported.
//
- auto need_refinement = [&eval_dep, &deps, &rec_pkgs, &o] (
+ auto need_refinement = [&eval_dep, &deps, &rec_pkgs, &dep_dbs, &o] (
bool diag = false) -> bool
{
// Examine the new dependency set for any up/down-grade/drops.
@@ -5769,18 +5995,7 @@ namespace bpkg
// up/down-grading or dropping packages in configurations that
// only contain dependents, some of which we may only reconfigure.
//
- linked_databases dbs;
-
- for (database& cdb: current_configs)
- {
- for (database& db: cdb.dependency_configs ())
- {
- if (find (dbs.begin (), dbs.end (), db) == dbs.end ())
- dbs.push_back (db);
- }
- }
-
- for (database& db: dbs)
+ for (database& db: dep_dbs)
{
for (shared_ptr<selected_package> sp:
pointer_result (db.query<selected_package> (q)))
diff --git a/tests/pkg-build.testscript b/tests/pkg-build.testscript
index b413a14..fac4b1c 100644
--- a/tests/pkg-build.testscript
+++ b/tests/pkg-build.testscript
@@ -5360,7 +5360,8 @@ else
libbuild2-bar [h1/.bpkg/build2/] configured 1.0.0
EOO
- $* libbar '?sys:foo/1.2.0' ?libbaz +{ --config-name h2 } <<EOI 2>>~%EOE%;
+ $* libbar '?sys:foo/1.2.0' +{ --config-name h1 } \
+ ?libbaz +{ --config-name h2 } <<EOI 2>>~%EOE%;
y
EOI
% new libbaz/1.0.0 \[h2.\]%
@@ -6337,5 +6338,397 @@ else
sed -n -e 's/^config.libbaz = (.+)$/\1/p' \
cfg2/libbaz-1.0.0/build/config.build >'false'
}
+
+ : system-dependency
+ :
+ {
+ $cfg_create -d cfg --uuid $cfg_uuid &cfg/***;
+ $cfg_create -d cfg2 --uuid $cfg2_uuid &cfg2/***;
+ $cfg_create -d cfg3 --uuid $cfg3_uuid --type host &cfg3/***;
+
+ $cfg_link -d cfg cfg3;
+ $cfg_link -d cfg2 cfg3;
+
+ $rep_add $rep/t7a && $rep_fetch;
+ $rep_add -d cfg2 $rep/t7a && $rep_fetch -d cfg2;
+
+ test.arguments += -d cfg2; # Now refers 2 current dirs: cfg/ and cfg2/.
+
+ $* libbox +{ --config-uuid $cfg_uuid --config-uuid $cfg2_uuid } \
+ '?sys:foo' <<EOI 2>>~%EOE%;
+ y
+ EOI
+ % new libbaz/1.0.0 \[cfg.\] \(required by libbox \[cfg.\]\)%
+ % configure sys:foo/\* \[cfg3.\]%
+ % new libbox/1.0.0 \[cfg.\]%
+ % new libbaz/1.0.0 \[cfg2.\] \(required by libbox \[cfg2.\]\)%
+ % new libbox/1.0.0 \[cfg2.\]%
+ %continue\? \[Y/n\] fetched libbaz/1.0.0 \[cfg.\]%
+ %unpacked libbaz/1.0.0 \[cfg.\]%
+ %fetched libbox/1.0.0 \[cfg.\]%
+ %unpacked libbox/1.0.0 \[cfg.\]%
+ %fetched libbaz/1.0.0 \[cfg2.\]%
+ %unpacked libbaz/1.0.0 \[cfg2.\]%
+ %fetched libbox/1.0.0 \[cfg2.\]%
+ %unpacked libbox/1.0.0 \[cfg2.\]%
+ %configured libbaz/1.0.0 \[cfg.\]%
+ %configured sys:foo/\* \[cfg3.\]%
+ %configured libbox/1.0.0 \[cfg.\]%
+ %configured libbaz/1.0.0 \[cfg2.\]%
+ %configured libbox/1.0.0 \[cfg2.\]%
+ %info: cfg.+libbox-1.0.0.+ is up to date%
+ %info: cfg2.+libbox-1.0.0.+ is up to date%
+ %updated libbox/1.0.0 \[cfg.\]%
+ %updated libbox/1.0.0 \[cfg2.\]%
+ EOE
+
+ $pkg_status -d cfg -r >>/EOO;
+ !libbox configured 1.0.0
+ foo [cfg3/] configured,system !* available 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_status -d cfg2 -r >>/EOO
+ !libbox configured 1.0.0
+ foo [cfg3/] configured,system !* available 1.0.0
+ libbaz configured 1.0.0
+ EOO
+ }
+ }
+
+ : system
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t7a && $rep_fetch
+
+ : no-config
+ :
+ {
+ +$clone_cfg
+
+ : linked
+ :
+ {
+ $clone_cfg;
+
+ $cfg_create -d cfg2 --type host --name cfg2 &cfg2/***;
+ $cfg_link -d cfg cfg2;
+
+ $* libbox '?sys:foo' <<EOI 2>>~%EOE%;
+ y
+ EOI
+ % configure sys:foo/\* \[cfg2.\]%
+ new libbaz/1.0.0 (required by libbox)
+ new libbox/1.0.0
+ continue? [Y/n] fetched libbaz/1.0.0
+ unpacked libbaz/1.0.0
+ fetched libbox/1.0.0
+ unpacked libbox/1.0.0
+ %configured sys:foo/\* \[cfg2.\]%
+ configured libbaz/1.0.0
+ configured libbox/1.0.0
+ %info: cfg.+libbox-1.0.0.+ is up to date%
+ updated libbox/1.0.0
+ EOE
+
+ $pkg_status -r >>/EOO;
+ !libbox configured 1.0.0
+ foo [cfg2/] configured,system !* available 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop libbox
+ }
+
+ : private-host
+ :
+ {
+ $clone_cfg;
+
+ $* libbox '?sys:foo' &cfg/.bpkg/host/*** <<EOI 2>>~%EOE%;
+ y
+ EOI
+ % configure sys:foo/\* \[cfg..bpkg.host.\]%
+ new libbaz/1.0.0 (required by libbox)
+ new libbox/1.0.0
+ continue? [Y/n] fetched libbaz/1.0.0
+ unpacked libbaz/1.0.0
+ fetched libbox/1.0.0
+ unpacked libbox/1.0.0
+ %configured sys:foo/\* \[cfg..bpkg.host.\]%
+ configured libbaz/1.0.0
+ configured libbox/1.0.0
+ %info: cfg.+libbox-1.0.0.+ is up to date%
+ updated libbox/1.0.0
+ EOE
+
+ $pkg_status -r >>/EOO;
+ !libbox configured 1.0.0
+ foo [cfg/.bpkg/host/] configured,system !* available 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop libbox
+ }
+
+ : private-module
+ :
+ {
+ $clone_cfg;
+
+ $* libbox '?sys:libbuild2-bar' &cfg/.bpkg/host/*** &cfg/.bpkg/build2/*** <<EOI 2>>~%EOE%;
+ y
+ EOI
+ % configure sys:libbuild2-bar/\* \[cfg..bpkg.build2.\]%
+ % new libbaz/1.0.0 \[cfg..bpkg.host.\] \(required by foo \[cfg..bpkg.host.\]\)%
+ % new foo/1.0.0 \[cfg..bpkg.host.\] \(required by libbox\)%
+ new libbaz/1.0.0 (required by libbox)
+ new libbox/1.0.0
+ %continue\? \[Y/n\] fetched libbaz/1.0.0 \[cfg..bpkg.host.\]%
+ %unpacked libbaz/1.0.0 \[cfg..bpkg.host.\]%
+ %fetched foo/1.0.0 \[cfg..bpkg.host.\]%
+ %unpacked foo/1.0.0 \[cfg..bpkg.host.\]%
+ fetched libbaz/1.0.0
+ unpacked libbaz/1.0.0
+ fetched libbox/1.0.0
+ unpacked libbox/1.0.0
+ %configured sys:libbuild2-bar/\* \[cfg..bpkg.build2.\]%
+ %configured libbaz/1.0.0 \[cfg..bpkg.host.\]%
+ %configured foo/1.0.0 \[cfg..bpkg.host.\]%
+ configured libbaz/1.0.0
+ configured libbox/1.0.0
+ %info: cfg.+libbox-1.0.0.+ is up to date%
+ updated libbox/1.0.0
+ EOE
+
+ $pkg_status -r >>/EOO;
+ !libbox configured 1.0.0
+ foo [cfg/.bpkg/host/] configured 1.0.0
+ libbaz [cfg/.bpkg/host/] configured 1.0.0
+ libbuild2-bar [cfg/.bpkg/build2/] configured,system !* available 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop libbox
+ }
+ }
+
+ : config
+ :
+ {
+ +$clone_cfg
+
+ : linked
+ :
+ {
+ $clone_cfg;
+
+ $cfg_create -d cfg2 --type host --name cfg2 &cfg2/***;
+ $cfg_link -d cfg cfg2;
+
+ $cfg_create -d cfg3 --type host --name cfg3 &cfg3/***;
+ $cfg_link -d cfg cfg3;
+
+ $* libbox '?sys:foo' +{ --config-name cfg3 } <<EOI 2>>~%EOE%;
+ y
+ EOI
+ % configure sys:foo/\* \[cfg3.\]%
+ new libbaz/1.0.0 (required by libbox)
+ new libbox/1.0.0
+ continue? [Y/n] fetched libbaz/1.0.0
+ unpacked libbaz/1.0.0
+ fetched libbox/1.0.0
+ unpacked libbox/1.0.0
+ %configured sys:foo/\* \[cfg3.\]%
+ configured libbaz/1.0.0
+ configured libbox/1.0.0
+ %info: cfg.+libbox-1.0.0.+ is up to date%
+ updated libbox/1.0.0
+ EOE
+
+ $pkg_status -r >>/EOO;
+ !libbox configured 1.0.0
+ foo [cfg3/] configured,system !* available 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop libbox
+ }
+
+ : src-sys
+ :
+ {
+ $clone_cfg;
+
+ $cfg_create -d cfg2 --type host --name cfg2 &cfg2/***;
+ $cfg_link -d cfg cfg2;
+
+ $* libbox --yes 2>!;
+
+ $pkg_status -r >>/EOO;
+ !libbox configured 1.0.0
+ foo [cfg2/] configured 1.0.0
+ libbaz [cfg2/] configured 1.0.0
+ libbuild2-bar [cfg2/.bpkg/build2/] configured 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $* '?sys:foo' <<EOI 2>>~%EOE%;
+ y
+ y
+ EOI
+ % drop libbuild2-bar/1.0.0 \[cfg2..bpkg.build2.\] \(unused\)%
+ % drop libbaz/1.0.0 \[cfg2.\] \(unused\)%
+ % reconfigure sys:foo/\* \[cfg2.\]%
+ % reconfigure libbox \(dependent of foo \[cfg2.\]\)%
+ continue? [Y/n] update dependent packages? [Y/n] disfigured libbox/1.0.0
+ %disfigured foo/1.0.0 \[cfg2.\]%
+ %disfigured libbaz/1.0.0 \[cfg2.\]%
+ %disfigured libbuild2-bar/1.0.0 \[cfg2..bpkg.build2.\]%
+ %purged libbuild2-bar/1.0.0 \[cfg2..bpkg.build2.\]%
+ %purged libbaz/1.0.0 \[cfg2.\]%
+ %purged foo/1.0.0 \[cfg2.\]%
+ %configured sys:foo/\* \[cfg2.\]%
+ configured libbox/1.0.0
+ %info: cfg.+libbox-1.0.0.+ is up to date%
+ updated libbox/1.0.0
+ EOE
+
+ $pkg_status -r >>/EOO;
+ !libbox configured 1.0.0
+ foo [cfg2/] configured,system !* available 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop libbox
+ }
+
+ : src-sys-upgrade
+ :
+ {
+ $clone_cfg;
+
+ $cfg_create -d cfg2 --type host --name cfg2 &cfg2/***;
+ $cfg_link -d cfg cfg2;
+
+ $* libbox --yes 2>!;
+
+ $pkg_status -r >>/EOO;
+ !libbox configured 1.0.0
+ foo [cfg2/] configured 1.0.0
+ libbaz [cfg2/] configured 1.0.0
+ libbuild2-bar [cfg2/.bpkg/build2/] configured 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $* '?sys:foo/1.1.0' <<EOI 2>>~%EOE%;
+ y
+ y
+ EOI
+ % drop libbuild2-bar/1.0.0 \[cfg2..bpkg.build2.\] \(unused\)%
+ % drop libbaz/1.0.0 \[cfg2.\] \(unused\)%
+ % reconfigure sys:foo/1.1.0 \[cfg2.\]%
+ % reconfigure libbox \(dependent of foo \[cfg2.\]\)%
+ continue? [Y/n] update dependent packages? [Y/n] disfigured libbox/1.0.0
+ %disfigured foo/1.0.0 \[cfg2.\]%
+ %disfigured libbaz/1.0.0 \[cfg2.\]%
+ %disfigured libbuild2-bar/1.0.0 \[cfg2..bpkg.build2.\]%
+ %purged libbuild2-bar/1.0.0 \[cfg2..bpkg.build2.\]%
+ %purged libbaz/1.0.0 \[cfg2.\]%
+ %purged foo/1.0.0 \[cfg2.\]%
+ %configured sys:foo/1.1.0 \[cfg2.\]%
+ configured libbox/1.0.0
+ %info: cfg.+libbox-1.0.0.+ is up to date%
+ updated libbox/1.0.0
+ EOE
+
+ $pkg_status -r >>/EOO;
+ !libbox configured 1.0.0
+ foo [cfg2/] configured,system !1.1.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop libbox
+ }
+
+ : src-sys-unhold
+ :
+ {
+ $clone_cfg;
+
+ $cfg_create -d cfg2 --type host --name cfg2 &cfg2/***;
+ $cfg_link -d cfg cfg2;
+
+ $rep_add -d cfg2 $rep/t7a && $rep_fetch -d cfg2;
+
+ $* libbox foo +{ --config-name cfg2 } --yes 2>!;
+
+ $pkg_status -r >>/EOO;
+ !libbox configured 1.0.0
+ !foo [cfg2/] configured 1.0.0
+ libbaz [cfg2/] configured 1.0.0
+ libbuild2-bar [cfg2/.bpkg/build2/] configured 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $* '?sys:foo' <<EOI 2>>~%EOE%;
+ y
+ y
+ EOI
+ % drop libbuild2-bar/1.0.0 \[cfg2..bpkg.build2.\] \(unused\)%
+ % drop libbaz/1.0.0 \[cfg2.\] \(unused\)%
+ % reconfigure/unhold sys:foo/\* \[cfg2.\]%
+ % reconfigure libbox \(dependent of foo \[cfg2.\]\)%
+ continue? [Y/n] update dependent packages? [Y/n] disfigured libbox/1.0.0
+ %disfigured foo/1.0.0 \[cfg2.\]%
+ %disfigured libbaz/1.0.0 \[cfg2.\]%
+ %disfigured libbuild2-bar/1.0.0 \[cfg2..bpkg.build2.\]%
+ %purged libbuild2-bar/1.0.0 \[cfg2..bpkg.build2.\]%
+ %purged libbaz/1.0.0 \[cfg2.\]%
+ %purged foo/1.0.0 \[cfg2.\]%
+ %configured sys:foo/\* \[cfg2.\]%
+ configured libbox/1.0.0
+ %info: cfg.+libbox-1.0.0.+ is up to date%
+ updated libbox/1.0.0
+ EOE
+
+ $pkg_status -r >>/EOO;
+ !libbox configured 1.0.0
+ foo [cfg2/] configured,system !* available 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop libbox
+ }
+
+ : sys-unhold
+ :
+ {
+ $clone_cfg;
+
+ $cfg_create -d cfg2 --type host --name cfg2 &cfg2/***;
+ $cfg_link -d cfg cfg2;
+
+ $rep_add -d cfg2 $rep/t7a && $rep_fetch -d cfg2;
+
+ $* libbox 'sys:foo' +{ --config-name cfg2 } --yes 2>!;
+
+ $pkg_status -r >>/EOO;
+ !libbox configured 1.0.0
+ !foo [cfg2/] configured,system !* available 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $* '?sys:foo';
+
+ $pkg_status -r >>/EOO;
+ !libbox configured 1.0.0
+ foo [cfg2/] configured,system !* available 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop libbox
+ }
+ }
}
}
diff --git a/tests/pkg-system.testscript b/tests/pkg-system.testscript
index 3ff1b55..e300afd 100644
--- a/tests/pkg-system.testscript
+++ b/tests/pkg-system.testscript
@@ -90,28 +90,28 @@ rep_remove += -d cfg 2>!
{
$clone_cfg;
- $pkg_build 'sys:libbar' '?sys:libbar' 2>>EOE != 0;
+ $pkg_build 'sys:libbar' 'sys:libbar/1.0.0' 2>>EOE != 0;
error: duplicate package libbar
info: first mentioned as sys:libbar
- info: second mentioned as ?sys:libbar
+ info: second mentioned as sys:libbar/1.0.0
EOE
- $pkg_build '?sys:libbar' 'sys:libbar' 2>>EOE != 0;
+ $pkg_build '?sys:libbar' '?sys:libbar/1.0.0' 2>>EOE != 0;
error: duplicate package libbar
info: first mentioned as ?sys:libbar
- info: second mentioned as sys:libbar
+ info: second mentioned as ?sys:libbar/1.0.0
EOE
- $pkg_build '?sys:libbar' libbar 2>>EOE != 0;
+ $pkg_build 'sys:libbar' libbar 2>>EOE != 0;
error: duplicate package libbar
- info: first mentioned as ?sys:libbar
+ info: first mentioned as sys:libbar
info: second mentioned as libbar
EOE
- $pkg_build libbar '?sys:libbar' 2>>EOE != 0;
+ $pkg_build ?libbar '?sys:libbar' +{ --config-id 0 } 2>>EOE != 0;
error: duplicate package libbar
- info: first mentioned as libbar
- info: second mentioned as ?sys:libbar
+ info: first mentioned as ?libbar
+ info: second mentioned as ?sys:libbar +{ --config-id 0 }
EOE
$pkg_build 'sys:libbar' libbar 2>>EOE != 0;