aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2022-05-16 21:31:16 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2022-05-17 13:13:36 +0300
commit76068d27d5911b69a8c68c82fc869ca53ba712a3 (patch)
treec632f1a8c833d540261f4c553f3bb3bd1a5a3e3d
parent456833d1ed693b946c29bead4c073f3de3481715 (diff)
Add dependency alternatives positions to selected package prerequisites
-rw-r--r--bpkg/package.hxx67
-rw-r--r--bpkg/package.xml7
-rw-r--r--bpkg/pkg-build.cxx54
-rw-r--r--bpkg/pkg-configure.cxx83
-rw-r--r--bpkg/pkg-configure.hxx14
-rw-r--r--bpkg/pkg-status.cxx2
6 files changed, 188 insertions, 39 deletions
diff --git a/bpkg/package.hxx b/bpkg/package.hxx
index b473917..9a7c572 100644
--- a/bpkg/package.hxx
+++ b/bpkg/package.hxx
@@ -27,7 +27,7 @@
//
#define DB_SCHEMA_VERSION_BASE 7
-#pragma db model version(DB_SCHEMA_VERSION_BASE, 18, closed)
+#pragma db model version(DB_SCHEMA_VERSION_BASE, 19, closed)
namespace bpkg
{
@@ -1032,21 +1032,63 @@ namespace bpkg
}
// A map of "effective" prerequisites (i.e., pointers to other selected
- // packages) to optional version constraint. Note that because it is a
- // single constraint, we don't support multiple dependencies on the same
- // package (e.g., two ranges of versions). See pkg_configure().
+ // packages) to optional version constraint (plus some other info). Note
+ // that because it is a single constraint, we don't support multiple
+ // dependencies on the same package (e.g., two ranges of versions). See
+ // pkg_configure().
//
// Note also that the pointer can refer to a selected package in another
// database.
//
class selected_package;
+ #pragma db value
+ struct prerequisite_info
+ {
+ // The "tightest" version constraint among all dependencies resolved to
+ // this prerequisite.
+ //
+ optional<version_constraint> constraint;
+
+ // Position of the first dependency alternative with a configuration
+ // clause, if any.
+ //
+ // Specifically, if there is such an alternative then this is a pair of
+ // 1-based indexes of the respective depends value (first) and the
+ // dependency alternative (second) in the dependent's manifest. Otherwise,
+ // this is a pair of zeros.
+ //
+ // For example, for the following dependent the position for libfoo/1.2.0
+ // prerequisite will be {2,2}:
+ //
+ // libbar: depends: libfoo >= 1.1.0
+ // depends: libfox | libfoo >= 1.2.0 {require {...}}
+ //
+ pair<size_t, size_t> config_position;
+
+ // Database mapping.
+ //
+ #pragma db member(constraint) column("")
+
+ #pragma db member(config_position) transient
+
+ #pragma db member(config_dependency_index) \
+ virtual(size_t) \
+ access(config_position.first) \
+ default(0)
+
+ #pragma db member(config_alternative_index) \
+ virtual(size_t) \
+ access(config_position.second) \
+ default(0)
+ };
+
// Note that the keys for this map need to be created with the database
// passed to their constructor, which is required for persisting them (see
// _selected_package_ref() implementation for details).
//
using package_prerequisites = std::map<lazy_shared_ptr<selected_package>,
- optional<version_constraint>,
+ prerequisite_info,
compare_lazy_ptr>;
// Database mapping for lazy_shared_ptr<selected_package> to configuration
@@ -1486,6 +1528,21 @@ namespace bpkg
#pragma db column("pp.package")
package_name name;
+ #pragma db transient
+ pair<size_t, size_t> config_position;
+
+ #pragma db member(config_dependency_index) \
+ column("pp.config_dependency_index") \
+ virtual(size_t) \
+ access(config_position.first) \
+ default(0)
+
+ #pragma db member(config_alternative_index) \
+ column("pp.config_alternative_index") \
+ virtual(size_t) \
+ access(config_position.second) \
+ default(0)
+
#pragma db column("pp.")
optional<version_constraint> constraint;
};
diff --git a/bpkg/package.xml b/bpkg/package.xml
index 904d0f6..8959529 100644
--- a/bpkg/package.xml
+++ b/bpkg/package.xml
@@ -1,4 +1,11 @@
<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="sqlite" version="1">
+ <changeset version="19">
+ <alter-table name="main.selected_package_prerequisites">
+ <add-column name="config_dependency_index" type="INTEGER" null="true" default="0"/>
+ <add-column name="config_alternative_index" type="INTEGER" null="true" default="0"/>
+ </alter-table>
+ </changeset>
+
<changeset version="18">
<add-table name="main.selected_package_config_variables" kind="container">
<column name="package" type="TEXT" null="true" options="COLLATE NOCASE"/>
diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx
index 8d125ce..aa3b58e 100644
--- a/bpkg/pkg-build.cxx
+++ b/bpkg/pkg-build.cxx
@@ -613,6 +613,11 @@ namespace bpkg
//
optional<bpkg::dependencies> dependencies;
+ // Indexes of the selected dependency alternatives stored in the above
+ // dependencies member.
+ //
+ optional<vector<size_t>> alternatives;
+
// If we end up collecting the prerequisite builds for this package, then
// this member stores the skeleton of the package being built.
//
@@ -2713,9 +2718,10 @@ namespace bpkg
//
const dependencies& deps (ap->dependencies);
- // Must both be either present or not.
+ // Must all be either present or not.
//
- assert (pkg.dependencies.has_value () == pkg.skeleton.has_value ());
+ assert (pkg.dependencies.has_value () == pkg.skeleton.has_value () &&
+ pkg.dependencies.has_value () == pkg.alternatives.has_value ());
// Note that the selected alternatives list can be filled partially (see
// build_package::dependencies for details). In this case we continue
@@ -2726,9 +2732,13 @@ namespace bpkg
l5 ([&]{trace << "begin " << pkg.available_name_version_db ();});
pkg.dependencies = dependencies ();
+ pkg.alternatives = vector<size_t> ();
if (size_t n = deps.size ())
+ {
pkg.dependencies->reserve (n);
+ pkg.alternatives->reserve (n);
+ }
optional<dir_path> src_root (pkg.external_dir ());
@@ -2746,7 +2756,10 @@ namespace bpkg
else
l5 ([&]{trace << "resume " << pkg.available_name_version_db ();});
- dependencies& sdeps (*pkg.dependencies);
+ dependencies& sdeps (*pkg.dependencies);
+ vector<size_t>& salts (*pkg.alternatives);
+
+ assert (sdeps.size () == salts.size ()); // Must be parallel.
// Check if there is nothing to collect anymore.
//
@@ -2796,6 +2809,7 @@ namespace bpkg
if (toolchain_buildtime_dependency (options, das, &nm))
{
sdeps.push_back (move (sdas));
+ salts.push_back (0); // Keep parallel to sdeps.
continue;
}
@@ -2824,6 +2838,7 @@ namespace bpkg
if (edas.empty ())
{
sdeps.push_back (move (sdas));
+ salts.push_back (0); // Keep parallel to sdeps.
continue;
}
@@ -3626,6 +3641,7 @@ namespace bpkg
b.available,
move (b.repository_fragment),
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
false, // Recursive collection.
@@ -4079,8 +4095,8 @@ namespace bpkg
// present.
//
bool selected (false);
- auto select = [&sdeps, &sdas, &skel, di, &selected]
- (const dependency_alternative& da)
+ auto select = [&sdeps, &salts, &sdas, &skel, di, &selected]
+ (const dependency_alternative& da, size_t dai)
{
assert (sdas.empty ());
@@ -4094,6 +4110,7 @@ namespace bpkg
da /* dependencies */);
sdeps.push_back (move (sdas));
+ salts.push_back (dai);
if (da.reflect)
skel.evaluate_reflect (*da.reflect, di);
@@ -4234,7 +4251,7 @@ namespace bpkg
return true;
}
- select (da);
+ select (da, dai);
// Make sure no more true alternatives are selected during
// this function call.
@@ -4288,7 +4305,7 @@ namespace bpkg
break;
}
- select (da);
+ select (da, dai);
}
// If an alternative is selected, then we are done.
@@ -4450,6 +4467,7 @@ namespace bpkg
move (rp.first),
move (rp.second),
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
false, // Recursive collection.
@@ -4537,6 +4555,7 @@ namespace bpkg
nullptr,
nullptr,
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
false, // Recursive collection.
@@ -4627,6 +4646,7 @@ namespace bpkg
nullptr,
nullptr,
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
false, // Recursive collection.
@@ -4882,6 +4902,7 @@ namespace bpkg
move (di.available),
move (di.repository_fragment),
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
false, // Recursive collection.
@@ -4952,6 +4973,7 @@ namespace bpkg
b->recursive_collection = true;
b->dependencies = dependencies ();
+ b->alternatives = vector<size_t> ();
optional<dir_path> src_root (b->external_dir ());
@@ -5083,6 +5105,7 @@ namespace bpkg
{
const bpkg::dependencies& deps (b->available->dependencies);
bpkg::dependencies& sdeps (*b->dependencies);
+ vector<size_t>& salts (*b->alternatives);
size_t di (sdeps.size ());
@@ -5121,6 +5144,7 @@ namespace bpkg
assert (j != pdas.end ());
const dependency_alternative& da (j->first);
+ size_t dai (j->second);
// Select the dependency alternative and position to the next
// depends value.
@@ -5136,6 +5160,7 @@ namespace bpkg
da /* dependencies */);
sdeps.push_back (move (sdas));
+ salts.push_back (dai);
// Evaluate reflect, if present.
//
@@ -5771,6 +5796,7 @@ namespace bpkg
nullptr, // No available pkg/repo fragment.
nullptr,
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
false, // Recursive collection.
@@ -8914,6 +8940,7 @@ namespace bpkg
move (ap),
move (af),
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
false, // Recursive collection.
@@ -9026,6 +9053,7 @@ namespace bpkg
move (ap),
move (apr.second),
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
false, // Recursive collection.
@@ -9271,9 +9299,8 @@ namespace bpkg
// Temporarily add the replacement prerequisites to the repointed
// dependent prerequisites sets and persist the changes.
//
- // Note that we don't copy the prerequisite constraints into the
- // replacements, since they are unused in the collecting/ordering
- // logic.
+ // Note that we don't copy the prerequisite information into the
+ // replacements, since it is unused in the collecting/ordering logic.
//
for (auto& rd: rpt_depts)
{
@@ -9291,7 +9318,7 @@ namespace bpkg
auto i (sp->prerequisites.emplace (
lazy_shared_ptr<selected_package> (cp.db.get (),
cp.name),
- nullopt));
+ prerequisite_info {nullopt, make_pair (0, 0)}));
// The selected package should only contain the old
// prerequisites at this time, so adding a replacement should
@@ -9358,6 +9385,7 @@ namespace bpkg
nullptr, // Available package/repo fragment.
nullptr,
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
false, // Recursive collection.
@@ -9636,6 +9664,7 @@ namespace bpkg
d.available,
d.repository_fragment,
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
false, // Recursive collection.
@@ -11307,6 +11336,7 @@ namespace bpkg
t,
sp,
*p.dependencies,
+ &*p.alternatives,
move (*p.skeleton),
nullptr /* previous_prerequisites */,
simulate,
@@ -11328,6 +11358,7 @@ namespace bpkg
t,
sp,
ap->dependencies,
+ nullptr /* alternatives */,
package_skeleton (o,
pdb,
*ap,
@@ -11369,6 +11400,7 @@ namespace bpkg
t,
sp,
dap->dependencies,
+ nullptr /* alternatives */,
package_skeleton (o,
pdb,
*dap,
diff --git a/bpkg/pkg-configure.cxx b/bpkg/pkg-configure.cxx
index 65cbf05..ee123d5 100644
--- a/bpkg/pkg-configure.cxx
+++ b/bpkg/pkg-configure.cxx
@@ -48,6 +48,7 @@ namespace bpkg
database& db,
transaction&,
const dependencies& deps,
+ const vector<size_t>* alts,
package_skeleton&& ps,
const vector<package_name>* prev_prereqs,
bool simulate,
@@ -57,6 +58,11 @@ namespace bpkg
strings vars;
vector<config_variable> srcs;
+ // Alternatives argument must be parallel to the dependencies argument if
+ // specified.
+ //
+ assert (alts == nullptr || alts->size () == deps.size ());
+
for (size_t di (0); di != deps.size (); ++di)
{
// Skip the toolchain build-time dependencies and dependencies without
@@ -64,19 +70,38 @@ namespace bpkg
//
const dependency_alternatives_ex& das (deps[di]);
- if (das.empty () || toolchain_buildtime_dependency (o, das, &ps.name ()))
+ if (das.empty ())
continue;
- small_vector<reference_wrapper<const dependency_alternative>, 2> edas;
+ small_vector<pair<reference_wrapper<const dependency_alternative>,
+ size_t>,
+ 2> edas;
- for (const dependency_alternative& da: das)
+ if (alts == nullptr)
{
- if (!da.enable || ps.evaluate_enable (*da.enable, di))
- edas.push_back (da);
+ if (toolchain_buildtime_dependency (o, das, &ps.name ()))
+ continue;
+
+ for (size_t i (0); i != das.size (); ++i)
+ {
+ const dependency_alternative& da (das[i]);
+
+ if (!da.enable || ps.evaluate_enable (*da.enable, di))
+ edas.push_back (make_pair (ref (da), i));
+ }
+
+ if (edas.empty ())
+ continue;
+ }
+ else
+ {
+ // Must only contain the selected alternative.
+ //
+ assert (das.size () == 1);
+
+ edas.push_back (make_pair (ref (das.front ()), (*alts)[di]));
}
- if (edas.empty ())
- continue;
// Pick the first alternative with dependencies that can all be resolved
// to the configured packages, satisfying the respective constraints.
@@ -91,16 +116,19 @@ namespace bpkg
for (const vector<package_name>* pps (prev_prereqs);;)
{
bool satisfied (false);
- for (const dependency_alternative& da: edas)
+ for (const auto& eda: edas)
{
+ const dependency_alternative& da (eda.first);
+ size_t dai (eda.second);
+
// Cache the selected packages which correspond to the alternative
// dependencies, pairing them with the respective constraints. If
// the alternative turns out to be fully resolvable, we will add the
// cached packages into the dependent's prerequisites map.
//
small_vector<
- pair<lazy_shared_ptr<selected_package>,
- const optional<version_constraint>&>, 1> prerequisites;
+ pair<lazy_shared_ptr<selected_package>, prerequisite_info>,
+ 1> prerequisites;
dependency_alternative::const_iterator b (da.begin ());
dependency_alternative::const_iterator i (b);
@@ -132,9 +160,13 @@ namespace bpkg
// See the package_prerequisites definition for details on
// creating the map keys with the database passed.
//
+ bool conf (da.prefer || da.require);
+
prerequisites.emplace_back (
lazy_shared_ptr<selected_package> (*spd.second, dp),
- d.constraint);
+ prerequisite_info {d.constraint,
+ make_pair (conf ? di + 1 : 0,
+ conf ? dai + 1 : 0)});
}
// Try the next alternative if there are unresolved dependencies for
@@ -150,9 +182,9 @@ namespace bpkg
for (auto& pr: prerequisites)
{
const package_name& pn (pr.first.object_id ());
- const optional<version_constraint>& pc (pr.second);
+ const prerequisite_info& pi (pr.second);
- auto p (prereqs.emplace (pr.first, pc));
+ auto p (prereqs.emplace (pr.first, pi));
// Currently we can only capture a single constraint, so if we
// already have a dependency on this package and one constraint is
@@ -160,18 +192,28 @@ namespace bpkg
//
if (!p.second)
{
- auto& c (p.first->second);
+ auto& c1 (p.first->second.constraint);
+ auto& c2 (pi.constraint);
- bool s1 (satisfies (c, pc));
- bool s2 (satisfies (pc, c));
+ bool s1 (satisfies (c1, c2));
+ bool s2 (satisfies (c2, c1));
if (!s1 && !s2)
fail << "multiple dependencies on package " << pn <<
- info << pn << " " << *c <<
- info << pn << " " << *pc;
+ info << pn << " " << *c1 <<
+ info << pn << " " << *c2;
if (s2 && !s1)
- c = pc;
+ c1 = c2;
+
+ // Keep position of the first dependency alternative with a
+ // configuration clause.
+ //
+ pair<size_t, size_t>& p1 (p.first->second.config_position);
+ pair<size_t, size_t> p2 (pi.config_position);
+
+ if (p1.first == 0 && p2.first != 0)
+ p1 = p2;
}
// If the prerequisite is configured in the linked configuration,
@@ -287,6 +329,7 @@ namespace bpkg
transaction& t,
const shared_ptr<selected_package>& p,
const dependencies& deps,
+ const vector<size_t>* alts,
package_skeleton&& ps,
const vector<package_name>* pps,
bool simulate,
@@ -322,6 +365,7 @@ namespace bpkg
db,
t,
deps,
+ alts,
move (ps),
pps,
simulate,
@@ -559,6 +603,7 @@ namespace bpkg
t,
p,
ap->dependencies,
+ nullptr /* alternatives */,
package_skeleton (o,
db,
*ap,
diff --git a/bpkg/pkg-configure.hxx b/bpkg/pkg-configure.hxx
index 23dab83..cbfad7a 100644
--- a/bpkg/pkg-configure.hxx
+++ b/bpkg/pkg-configure.hxx
@@ -33,9 +33,16 @@ namespace bpkg
// Configure the package, update its state, and commit the transaction.
//
- // The package dependency constraints are expected to be complete. Empty
- // dependency alternatives lists are allowed and are ignored (see pkg-build
- // for the use-case).
+ // The package dependency constraints are expected to be complete.
+ //
+ // The dependencies argument may contain pre-selected dependency
+ // alternatives (with the potential empty entries for the toolchain
+ // build-time dependencies or for dependencies with all the alternatives
+ // disabled; see pkg-build for the use-case). In this case the number of
+ // dependency alternatives for each dependency must be 1 (or 0) and the
+ // alternatives argument must be specified. The alternatives argument must
+ // be parallel to the dependencies argument and specify indexes of the
+ // selected alternatives.
//
// If prerequisites corresponding to the previous configured state of the
// package are specified, then for each depends value try to select an
@@ -49,6 +56,7 @@ namespace bpkg
transaction&,
const shared_ptr<selected_package>&,
const dependencies&,
+ const vector<size_t>* alternatives,
package_skeleton&&,
const vector<package_name>* prerequisites,
bool simulate,
diff --git a/bpkg/pkg-status.cxx b/bpkg/pkg-status.cxx
index 45ea519..09a9424 100644
--- a/bpkg/pkg-status.cxx
+++ b/bpkg/pkg-status.cxx
@@ -144,7 +144,7 @@ namespace bpkg
{
shared_ptr<selected_package> d (pair.first.load ());
database& db (pair.first.database ());
- const optional<version_constraint>& c (pair.second);
+ const optional<version_constraint>& c (pair.second.constraint);
r.push_back (package {db, rdb, d->name, version (), move (d), c});
}
return r;