diff options
Diffstat (limited to 'load')
-rw-r--r-- | load/load.cxx | 224 |
1 files changed, 140 insertions, 84 deletions
diff --git a/load/load.cxx b/load/load.cxx index c786551..83cc9e6 100644 --- a/load/load.cxx +++ b/load/load.cxx @@ -391,11 +391,12 @@ load_packages (const shared_ptr<repository>& rp, // that we expect dependency constraints to be complete. // for (manifest_name_value nv (mp.next ()); !nv.empty (); nv = mp.next ()) - pms.emplace_back (mp, - move (nv), - ignore_unknown, - false /* complete_depends */, - package_manifest_flags::forbid_incomplete_depends); + pms.emplace_back ( + mp, + move (nv), + ignore_unknown, + false /* complete_depends */, + package_manifest_flags::forbid_incomplete_dependencies); } else pms = pkg_package_manifests (mp, ignore_unknown); @@ -406,6 +407,8 @@ load_packages (const shared_ptr<repository>& rp, throw failed (); } + using brep::dependency; + for (package_manifest& pm: pms) { shared_ptr<package> p ( @@ -501,11 +504,28 @@ load_packages (const shared_ptr<repository>& rp, // The package member will be assigned during dependency // resolution procedure. // - ds.back ().push_back ({move (pd.name), - move (pd.constraint), - nullptr /* package */}); + ds.back ().push_back (dependency {move (pd.name), + move (pd.constraint), + nullptr /* package */}); } + auto deps = [] (small_vector<bpkg::dependency, 1>&& ds) + { + small_vector<dependency, 1> r; + + if (!ds.empty ()) + { + r.reserve (ds.size ()); + + for (bpkg::dependency& d: ds) + r.push_back (dependency {move (d.name), + move (d.constraint), + nullptr /* package */}); + } + + return r; + }; + // Cache before the package name is moved. // package_name project (pm.effective_project ()); @@ -534,6 +554,9 @@ load_packages (const shared_ptr<repository>& rp, move (pm.build_error_email), move (ds), move (pm.requirements), + deps (move (pm.tests)), + deps (move (pm.examples)), + deps (move (pm.benchmarks)), move (pm.builds), move (pm.build_constraints), move (pm.location), @@ -827,110 +850,143 @@ find (const lazy_shared_ptr<repository>& r, return false; } -// Resolve package dependencies. Make sure that the best matching dependency -// belongs to the package repositories, their immediate prerequisite -// repositories, or their complements, recursively. Should be called once per -// internal package. +// Resolve package run-time dependencies, tests, examples, and benchmarks. +// Make sure that the best matching dependency belongs to the package +// repositories, their complements, recursively, or their immediate +// prerequisite repositories (only for run-time dependencies). Should be +// called once per internal package. // static void resolve_dependencies (package& p, database& db) { + using brep::dependency; + using brep::dependency_alternatives; + // Resolve dependencies for internal packages only. // assert (p.internal ()); - if (p.dependencies.empty ()) + if (p.dependencies.empty () && + p.tests.empty () && + p.examples.empty () && + p.benchmarks.empty ()) return; - for (auto& da: p.dependencies) + auto resolve = [&p, &db] (dependency& d, bool prereq) { - for (auto& d: da) - { - // Dependency should not be resolved yet. - // - assert (d.package == nullptr); + // Dependency should not be resolved yet. + // + assert (d.package == nullptr); - using query = query<package>; - query q (query::id.name == d.name); - const auto& vm (query::id.version); + using query = query<package>; + query q (query::id.name == d.name); + const auto& vm (query::id.version); - if (d.constraint) - { - auto c (*d.constraint); + if (d.constraint) + { + const version_constraint& c (*d.constraint); - assert (c.complete ()); + assert (c.complete ()); - query qs (compare_version_eq (vm, - canonical_version (wildcard_version), - false /* revision */)); + query qs (compare_version_eq (vm, + canonical_version (wildcard_version), + false /* revision */)); - if (c.min_version && c.max_version && - *c.min_version == *c.max_version) + if (c.min_version && c.max_version && *c.min_version == *c.max_version) + { + const version& v (*c.min_version); + q = q && (compare_version_eq (vm, + canonical_version (v), + v.revision.has_value ()) || + qs); + } + else + { + query qr (true); + + if (c.min_version) { const version& v (*c.min_version); - q = q && - (compare_version_eq (vm, - canonical_version (v), - v.revision.has_value ()) || - qs); - } - else - { - query qr (true); + canonical_version cv (v); + bool rv (v.revision); - if (c.min_version) - { - const version& v (*c.min_version); - canonical_version cv (v); - bool rv (v.revision); - - if (c.min_open) - qr = compare_version_gt (vm, cv, rv); - else - qr = compare_version_ge (vm, cv, rv); - } - - if (c.max_version) - { - const version& v (*c.max_version); - canonical_version cv (v); - bool rv (v.revision); - - if (c.max_open) - qr = qr && compare_version_lt (vm, cv, rv); - else - qr = qr && compare_version_le (vm, cv, rv); - } - - q = q && (qr || qs); + if (c.min_open) + qr = compare_version_gt (vm, cv, rv); + else + qr = compare_version_ge (vm, cv, rv); } - } - for (const auto& pp: db.query<package> (q + order_by_version_desc (vm))) - { - if (find (p.internal_repository, pp)) + if (c.max_version) { - d.package.reset (db, pp.id); - break; + const version& v (*c.max_version); + canonical_version cv (v); + bool rv (v.revision); + + if (c.max_open) + qr = qr && compare_version_lt (vm, cv, rv); + else + qr = qr && compare_version_le (vm, cv, rv); } + + q = q && (qr || qs); } + } - if (d.package == nullptr) + for (const auto& pp: db.query<package> (q + order_by_version_desc (vm))) + { + if (find (p.internal_repository, pp, prereq)) { - cerr << "error: can't resolve dependency " << d << " of the package " - << p.name << " " << p.version << endl - << " info: repository " - << p.internal_repository.load ()->location - << " appears to be broken" << endl; - - // Practically it is enough to resolve at least one dependency - // alternative to build a package. Meanwhile here we consider an error - // specifying in the manifest file an alternative which can't be - // resolved. - // - throw failed (); + d.package.reset (db, pp.id); + return true; } } + + return false; + }; + + auto bail = [&p] (const dependency& d, const char* what) + { + cerr << "error: can't resolve " << what << " " << d << " for the package " + << p.name << " " << p.version << endl + << " info: repository " << p.internal_repository.load ()->location + << " appears to be broken" << endl; + + throw failed (); + }; + + for (dependency_alternatives& da: p.dependencies) + { + for (dependency& d: da) + { + // Practically it is enough to resolve at least one dependency + // alternative to build a package. Meanwhile here we consider an error + // specifying in the manifest file an alternative which can't be + // resolved. + // + if (!resolve (d, true /* prereq */)) + bail (d, "dependency"); + } + } + + // Should we allow tests, examples, and benchmarks packages to be + // unresolvable? Let's forbid that until we see a use case for that. + // + for (dependency& d: p.tests) + { + if (!resolve (d, false /* prereq */)) + bail (d, "tests"); + } + + for (dependency& d: p.examples) + { + if (!resolve (d, false /* prereq */)) + bail (d, "examples"); + } + + for (dependency& d: p.benchmarks) + { + if (!resolve (d, false /* prereq */)) + bail (d, "benchmarks"); } db.update (p); // Update the package state. |