diff options
author | Karen Arutyunov <karen@codesynthesis.com> | 2023-08-08 15:28:25 +0300 |
---|---|---|
committer | Karen Arutyunov <karen@codesynthesis.com> | 2023-09-25 11:35:25 +0300 |
commit | bbf4d75525f54a41ebf38608c193f5787128c590 (patch) | |
tree | f66707abaaf18d15b339615fcfd24a56278b079a | |
parent | 6f40a051db7ef6c42c4856f0608ce1dad4fcf609 (diff) |
Fix configuration negotiation in pkg-build to re-evaluate being reconfigured existing dependents
-rw-r--r-- | bpkg/package.cxx | 12 | ||||
-rw-r--r-- | bpkg/package.hxx | 60 | ||||
-rw-r--r-- | bpkg/package.xml | 24 | ||||
-rw-r--r-- | bpkg/pkg-build-collect.cxx | 2105 | ||||
-rw-r--r-- | bpkg/pkg-build-collect.hxx | 314 | ||||
-rw-r--r-- | bpkg/pkg-build.cxx | 142 | ||||
-rw-r--r-- | bpkg/pkg-configure.cxx | 91 | ||||
-rw-r--r-- | bpkg/pkg-configure.hxx | 18 | ||||
-rw-r--r-- | bpkg/pkg-disfigure.cxx | 5 | ||||
-rw-r--r-- | tests/common/dependency-alternatives/t11a/biz-0.1.0.tar.gz | bin | 0 -> 416 bytes | |||
-rw-r--r-- | tests/common/dependency-alternatives/t11a/bus-0.1.0.tar.gz | bin | 0 -> 448 bytes | |||
-rw-r--r-- | tests/common/dependency-alternatives/t11a/libbiz-0.1.0.tar.gz | bin | 0 -> 401 bytes | |||
-rw-r--r-- | tests/common/dependency-alternatives/t11a/libbiz-1.0.0.tar.gz | bin | 0 -> 409 bytes | |||
-rw-r--r-- | tests/common/dependency-alternatives/t8a/tpx-1.0.0.tar.gz | bin | 0 -> 496 bytes | |||
-rw-r--r-- | tests/common/dependency-alternatives/t8a/twx-1.0.0.tar.gz | bin | 0 -> 431 bytes | |||
-rw-r--r-- | tests/pkg-build.testscript | 1396 |
16 files changed, 2321 insertions, 1846 deletions
diff --git a/bpkg/package.cxx b/bpkg/package.cxx index 56f4221..aca3550 100644 --- a/bpkg/package.cxx +++ b/bpkg/package.cxx @@ -296,12 +296,18 @@ namespace bpkg // The package is in at least fetched state, which means we should // be able to get its manifest. // - const optional<path>& a (sp->archive); - + // @@ PERF We should probably implement the available package caching not + // to parse the same manifests multiple times during all that build + // plan refinement iterations. What should be the cache key? Feels like + // it should be the archive/directory path. Note that the package + // manifests can potentially differ in different external package + // directories for the same version iteration. Testing showed 6% + // speedup on tests (debug/sanitized). + // package_manifest m ( sp->state == package_state::fetched ? pkg_verify (options, - a->absolute () ? *a : db.config_orig / *a, + sp->effective_archive (db.config_orig), true /* ignore_unknown */, false /* ignore_toolchain */, false /* expand_values */, diff --git a/bpkg/package.hxx b/bpkg/package.hxx index 947393b..06278cd 100644 --- a/bpkg/package.hxx +++ b/bpkg/package.hxx @@ -32,7 +32,7 @@ // #define DB_SCHEMA_VERSION_BASE 12 -#pragma db model version(DB_SCHEMA_VERSION_BASE, 24, closed) +#pragma db model version(DB_SCHEMA_VERSION_BASE, 25, closed) namespace bpkg { @@ -1086,37 +1086,9 @@ namespace bpkg // 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 @@ -1265,6 +1237,16 @@ namespace bpkg package_prerequisites prerequisites; + // 1-based indexes of the selected dependency alternatives which the + // prerequisite packages are resolved from. Parallel to the dependencies + // member of the respective available package. Entries which don't + // correspond to a selected alternative (toolchain build-time dependency, + // not enabled alternatives, etc) are set to 0. + // + using indexes_type = vector<size_t>; // Make sure ODB maps it portably. + indexes_type dependency_alternatives; + odb::section dependency_alternatives_section; + // Project configuration variable names and their sources. // vector<config_variable> config_variables; @@ -1363,6 +1345,11 @@ namespace bpkg #pragma db member(prerequisites) id_column("package") \ key_column("") value_column("") + #pragma db member(dependency_alternatives) id_column("package") \ + value_column("position") section(dependency_alternatives_section) + + #pragma db member(dependency_alternatives_section) load(lazy) update(always) + #pragma db member(config_variables) id_column("package") value_column("") // For the sake of simplicity let's not calculate the checksum during @@ -1595,21 +1582,6 @@ 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 343f27a..07595af 100644 --- a/bpkg/package.xml +++ b/bpkg/package.xml @@ -1,4 +1,28 @@ <changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="sqlite" version="1"> + <changeset version="25"> + <alter-table name="main.selected_package_prerequisites"> + <drop-column name="config_dependency_index"/> + <drop-column name="config_alternative_index"/> + </alter-table> + <add-table name="main.selected_package_dependency_alternatives" kind="container"> + <column name="package" type="TEXT" null="true" options="COLLATE NOCASE"/> + <column name="index" type="INTEGER" null="true"/> + <column name="position" type="INTEGER" null="true"/> + <foreign-key name="package_fk" on-delete="CASCADE"> + <column name="package"/> + <references table="main.selected_package"> + <column name="name"/> + </references> + </foreign-key> + <index name="selected_package_dependency_alternatives_package_i"> + <column name="package"/> + </index> + <index name="selected_package_dependency_alternatives_index_i"> + <column name="index"/> + </index> + </add-table> + </changeset> + <changeset version="24"> <alter-table name="main.selected_package"> <add-column name="config_checksum" type="TEXT" null="true" default="''"/> diff --git a/bpkg/pkg-build-collect.cxx b/bpkg/pkg-build-collect.cxx index d08f0f8..a52bba5 100644 --- a/bpkg/pkg-build-collect.cxx +++ b/bpkg/pkg-build-collect.cxx @@ -102,6 +102,7 @@ namespace bpkg return !system && (dependencies || selected->version != available_version () || + (flags & build_recollect) != 0 || ((!config_vars.empty () || skeleton) && has_buildfile_clause (available->dependencies)) || rpt_depts.find (package_key (db, name ())) != rpt_depts.end ()); @@ -119,6 +120,7 @@ namespace bpkg (selected->system () != system || selected->version != available_version () || replace () || + (flags & build_recollect) != 0 || (!system && (!config_vars.empty () || disfigure))))); } @@ -342,7 +344,9 @@ namespace bpkg package_skeleton& build_package:: init_skeleton (const common_options& options, - const shared_ptr<available_package>& override) + const shared_ptr<available_package>& override, + optional<dir_path> src_root, + optional<dir_path> out_root) { shared_ptr<available_package> ap (override != nullptr ? override @@ -365,9 +369,7 @@ namespace bpkg ap = nullptr; } - optional<dir_path> src_root, out_root; - - if (ap != nullptr) + if (!src_root && ap != nullptr) { src_root = external_dir (); out_root = (src_root && !disfigure @@ -613,26 +615,6 @@ namespace bpkg return false; } - const pair<size_t, size_t>* postponed_configuration:: - existing_dependent_position (const package_key& p) const - { - const pair<size_t, size_t>* r (nullptr); - - auto i (dependents.find (p)); - if (i != dependents.end () && i->second.existing) - { - for (const dependency& d: i->second.dependencies) - { - if (r == nullptr || d.position < *r) - r = &d.position; - } - - assert (r != nullptr); - } - - return r; - } - void postponed_configuration:: merge (postponed_configuration&& c) { @@ -653,10 +635,6 @@ namespace bpkg for (dependency& sd: sdi.dependencies) ddi.add (move (sd)); - - // As in add() above. - // - assert (ddi.existing || !sdi.existing); } else dependents.emplace (d.first, move (d.second)); @@ -1164,17 +1142,18 @@ namespace bpkg build_package* build_packages:: collect_build (const pkg_build_options& options, build_package pkg, - const function<find_database_function>& fdb, - const repointed_dependents& rpt_depts, - const function<add_priv_cfg_function>& apc, - bool initial_collection, replaced_versions& replaced_vers, postponed_configurations& postponed_cfgs, build_package_refs* dep_chain, + bool initial_collection, + const function<find_database_function>& fdb, + const function<add_priv_cfg_function>& apc, + const repointed_dependents* rpt_depts, postponed_packages* postponed_repo, postponed_packages* postponed_alts, + postponed_packages* postponed_recs, + postponed_existing_dependencies* postponed_edeps, postponed_dependencies* postponed_deps, - postponed_positions* postponed_poss, unacceptable_alternatives* unacceptable_alts, const function<verify_package_build_function>& vpb) { @@ -1188,10 +1167,13 @@ namespace bpkg // See the above notes. // bool recursive (dep_chain != nullptr); - assert ((postponed_repo != nullptr) == recursive && + assert ((fdb != nullptr) == recursive && + (rpt_depts != nullptr) == recursive && + (postponed_repo != nullptr) == recursive && (postponed_alts != nullptr) == recursive && + (postponed_recs != nullptr) == recursive && + (postponed_edeps != nullptr) == recursive && (postponed_deps != nullptr) == recursive && - (postponed_poss != nullptr) == recursive && (unacceptable_alts != nullptr) == recursive); // Only builds are allowed here. @@ -1391,7 +1373,7 @@ namespace bpkg // altogether if we are the only dependent (so that it doesn't // influence any subsequent dependent) or (2) making sure our // constraint is a sub-constraint of any other constraint and - // removing it from the dependency build_package. Maybe/later. + // removing it from the dependency build_package. Maybe/later. // // NOTE: remember to update collect_drop() if changing anything // here. @@ -1445,7 +1427,13 @@ namespace bpkg auto i (cfg.dependents.find (pk)); if (i != cfg.dependents.end () && i->second.existing) + { + l5 ([&]{trace << "existing dependent " << *pkg.selected << pkg.db + << " needs to be replaced with " + << pkg.available_name_version_db ();}); + replace_ver (pkg); + } } } @@ -1484,40 +1472,42 @@ namespace bpkg if (recursive) collect_build_prerequisites (options, p, + *dep_chain, + initial_collection, fdb, - rpt_depts, apc, - initial_collection, + *rpt_depts, replaced_vers, - *dep_chain, postponed_repo, postponed_alts, 0 /* max_alt_index */, + *postponed_recs, + *postponed_edeps, *postponed_deps, postponed_cfgs, - *postponed_poss, *unacceptable_alts); return &p; } - void build_packages:: + optional<vector<postponed_configuration::dependency>> build_packages:: collect_build_prerequisites (const pkg_build_options& options, build_package& pkg, + build_package_refs& dep_chain, + bool initial_collection, const function<find_database_function>& fdb, - const repointed_dependents& rpt_depts, const function<add_priv_cfg_function>& apc, - bool initial_collection, + const repointed_dependents& rpt_depts, replaced_versions& replaced_vers, - build_package_refs& dep_chain, postponed_packages* postponed_repo, postponed_packages* postponed_alts, size_t max_alt_index, + postponed_packages& postponed_recs, + postponed_existing_dependencies& postponed_edeps, postponed_dependencies& postponed_deps, postponed_configurations& postponed_cfgs, - postponed_positions& postponed_poss, unacceptable_alternatives& unacceptable_alts, - pair<size_t, size_t> reeval_pos) + optional<pair<size_t, size_t>> reeval_pos) { // NOTE: don't forget to update collect_build_postponed() if changing // anything in this function. @@ -1530,21 +1520,25 @@ namespace bpkg database& pdb (pkg.db); package_key pk (pdb, nm); - bool reeval (reeval_pos.first != 0); + bool pre_reeval (reeval_pos && reeval_pos->first == 0); + assert (!pre_reeval || reeval_pos->second == 0); + + bool reeval (reeval_pos && reeval_pos->first != 0); + assert (!reeval || reeval_pos->second != 0); - // The being re-evaluated dependent cannot be recursively collected yet. - // Also, we don't expect it being configured as system. + // The being (pre-)re-evaluated dependent cannot be recursively collected + // yet. Also, we don't expect it being configured as system. // // Note that the configured package can still be re-evaluated after // collect_build_prerequisites() has been called but didn't end up with // the recursive collection. // - assert (!reeval || + assert ((!pre_reeval && !reeval) || ((!pkg.recursive_collection || !pkg.recollect_recursively (rpt_depts)) && !pkg.skeleton && !pkg.system)); - // If this package is not being re-evaluated, is not yet collected + // If this package is not being (pre-)re-evaluated, is not yet collected // recursively, needs to be reconfigured, and is not yet postponed, then // check if it is a dependency of any dependent with configuration clause // and postpone the collection if that's the case. @@ -1554,200 +1548,142 @@ namespace bpkg // otherwise built (e.g., reconfigured) which means its externally- // imposed configuration (user, dependents) is not being changed. // - if (!reeval && - !pkg.recursive_collection && - pkg.reconfigure () && - postponed_cfgs.find_dependency (pk) == nullptr) + if (!pre_reeval && + !reeval && + !pkg.recursive_collection && + pkg.reconfigure () && + postponed_cfgs.find_dependency (pk) == nullptr && + postponed_edeps.find (pk) == postponed_edeps.end ()) { - // If the dependent is being built, then check if it was re-evaluated to - // the position greater than the dependency position. Return true if - // that's the case, so this package is added to the resulting list and - // we can handle this situation below. - // - // Note that we rely on "small function object" optimization here. - // - const function<verify_dependent_build_function> verify ( - [&postponed_cfgs] - (const package_key& pk, pair<size_t, size_t> pos) - { - for (const postponed_configuration& cfg: postponed_cfgs) - { - if (cfg.negotiated) - { - if (const pair<size_t, size_t>* p = - cfg.existing_dependent_position (pk)) - { - if (p->first > pos.first) - return true; - } - } - } - - return false; - }); - // Note that there can be multiple existing dependents for a dependency. - // Strictly speaking, we only need to add the first one with the - // assumption that the remaining dependents will also be considered - // comes the time for the negotiation. Let's, however, process all of - // them to detect the potential "re-evaluation on the greater dependency - // index" situation earlier. And, generally, have as much information as - // possible up front. // vector<existing_dependent> eds ( query_existing_dependents (trace, + options, pk.db, pk.name, - replaced_vers, + fdb, rpt_depts, - verify)); + replaced_vers)); if (!eds.empty ()) { + bool postpone (false); + for (existing_dependent& ed: eds) { - package_key dpt (ed.db, ed.selected->name); - package_key dep (pk); - - size_t& di (ed.dependency_position.first); - - const build_package* bp (&pkg); - - // Check if this dependent needs to be re-evaluated to an earlier - // dependency position and, if that's the case, create the - // configuration cluster with this dependency instead. - // - // Note that if the replace flag is false, we proceed normally with - // the assumption that the dependency referred by the entry will be - // collected later and its configuration cluster will be created - // normally and will be negotiated earlier than the cluster being - // created for the current dependency (see collect_build_postponed() - // for details). - // + if (ed.dependency) // Configuration clause is encountered. { - auto pi (postponed_poss.find (dpt)); + const build_package* bp (&pkg); - if (pi != postponed_poss.end () && pi->second.first < di) + package_key& dep (*ed.dependency); + package_key dpt (ed.db, ed.selected->name); + + // If the earliest configuration clause applies to a different + // dependency, then collect it (non-recursively). + // + if (dep != pk) + bp = collect_existing_dependent_dependency (options, + ed, + replaced_vers, + postponed_cfgs); + + // Indicate that the dependent with configuration clauses is + // present. + // { - // If requested, override the first encountered non-replace - // position to replace. See collect_build_postponed () for - // details. - // - if (!pi->second.replace && postponed_poss.replace) - { - pi->second.replace = true; - postponed_poss.replace = false; - } + auto i (postponed_deps.find (dep)); - if (pi->second.replace) + // Do not override postponements recorded during postponed + // collection phase with those recorded during initial + // phase. + // + if (i == postponed_deps.end ()) { - // Overwrite the existing dependent dependency information and - // fall through to proceed as for the normal case. - // - bp = replace_existing_dependent_dependency ( - trace, - options, - ed, // Note: modified. - pi->second, - fdb, - rpt_depts, - apc, - initial_collection, - replaced_vers, - postponed_cfgs); - - dep = package_key (bp->db, bp->name ()); - - // Note that here we side-step the bogus logic (by not setting - // the skipped flag) because in this case (replace=true) our - // choices are either (potentially) bogus or pathological - // (where we have evaluated too far). In other words, the - // postponed entry may cause the depends entry that triggered - // it to disappear (and thus, strictly speaking, to become - // bogus) but if we cancel it, we will be back to square one. + postponed_deps.emplace (dep, + postponed_dependency { + false /* without_config */, + true /* with_config */, + initial_collection}); } + else + i->second.with_config = true; } - } - // Make sure that this existing dependent doesn't belong to any - // (being) negotiated configuration cluster with a greater - // dependency index. That would mean that this dependent has already - // been re-evaluated to this index and so cannot participate in the - // configuration negotiation of this earlier dependency. - // - for (const postponed_configuration& cfg: postponed_cfgs) - { - if (const pair<size_t, size_t>* p = - cfg.existing_dependent_position (dpt)) + // Prematurely collected before we saw any config clauses. + // + if (bp->recursive_collection) { - size_t ei (p->first); - - if (di < ei && cfg.negotiated) - { - // Feels like there cannot be an earlier position. - // - postponed_position pp (ed.dependency_position, - false /* replace */); + l5 ([&]{trace << "cannot cfg-postpone dependency " + << bp->available_name_version_db () + << " of existing dependent " << dpt + << " (collected prematurely), " + << "throwing postpone_dependency";}); - auto p (postponed_poss.emplace (move (dpt), pp)); - if (!p.second) - { - assert (p.first->second > pp); - p.first->second = pp; - } - - l5 ([&]{trace << "cannot cfg-postpone dependency " - << bp->available_name_version_db () - << " of existing dependent " << *ed.selected - << ed.db << " (index " << di - << ") due to earlier dependency index " << ei - << " in " << cfg << ", throwing " - << "postpone_position";}); + // Don't print the "while satisfying..." chain. + // + dep_chain.clear (); - // Don't print the "while satisfying..." chain. - // - dep_chain.clear (); + throw postpone_dependency (move (dep)); + } - throw postpone_position (); - } + l5 ([&]{trace << "cfg-postpone dependency " + << bp->available_name_version_db () + << " of existing dependent " << *ed.selected + << ed.db << " due to dependency " + << pkg.available_name_version_db ();}); - if (di == ei) - { - // For the negotiated cluster all the dependency packages - // should have been added. For non-negotiated cluster we - // cannot add the missing dependencies at the moment and will - // do it as a part of the dependent re-evaluation. - // - assert (!cfg.negotiated); - } - } + // Only add this dependent/dependency to the newly created cluster + // if this dependency doesn't belong to any cluster yet, which may + // not be the case if there are multiple existing dependents with + // configuration clause for this dependency. + // + // To put it another way, if there are multiple such existing + // dependents for this dependency, here we will create the + // configuration cluster only for the first one. The remaining + // dependents will be added to this dependency's cluster when the + // existing dependents of dependencies in this cluster are all + // discovered and reevaluated (see collect_build_postponed() for + // details). + // + if (postponed_cfgs.find_dependency (dep) == nullptr) + postponed_cfgs.add (move (dpt), + ed.dependency_position, + move (dep)); + } + else // Existing dependent is deviated. + { + // Note that we could probably re-collect deviated dependents + // recursively right away but such a two-directional recursion + // would complicate implementation and troubleshooting. Thus, + // given that the deviated dependents are not very common, we just + // postpone their re-collection. + // + collect_deviated_dependent (options, + ed, + pk, + replaced_vers, + postponed_recs, + postponed_cfgs); } - l5 ([&]{trace << "cfg-postpone dependency " - << bp->available_name_version_db () - << " of existing dependent " << *ed.selected - << ed.db;}); - - // Only add this dependent/dependency to the newly created cluster - // if this dependency doesn't belong to any cluster yet, which may - // not be the case if there are multiple existing dependents with - // configuration clause for this dependency. + // Postpone the original dependency recursive collection if the + // existing dependent has deviated or the dependency belongs to the + // earliest depends clause with configuration clause or to some + // later depends clause. It is supposed that it will be collected + // during its existing dependent re-collection. // - // To put it another way, if there are multiple such an existing - // dependents for this dependency, here we will create the - // configuration cluster only for the first one. The remaining - // dependents will be added to this dependency's cluster when the - // existing dependents of dependencies in this cluster are all - // discovered and reevaluated (see collect_build_postponed() for - // details). - // - if (postponed_cfgs.find_dependency (dep) == nullptr) - postponed_cfgs.add (move (dpt), - ed.dependency_position, - move (dep)); + if (!ed.dependency || // Dependent has deviated. + !ed.orig_dependency_position || // Later depends clause. + *ed.orig_dependency_position == ed.dependency_position) + { + postpone = true; + postponed_edeps[pk].emplace_back (ed.db, ed.selected->name); + } } - return; + if (postpone) + return nullopt; } } @@ -1756,7 +1692,7 @@ namespace bpkg if (pkg.system) { l5 ([&]{trace << "skip system " << pkg.available_name_version_db ();}); - return; + return nullopt; } const shared_ptr<available_package>& ap (pkg.available); @@ -1764,6 +1700,8 @@ namespace bpkg const shared_ptr<selected_package>& sp (pkg.selected); + assert ((!pre_reeval && !reeval) || sp != nullptr); + // True if this is an up/down-grade. // bool ud (sp != nullptr && sp->version != pkg.available_version ()); @@ -1780,24 +1718,25 @@ namespace bpkg sp->state == package_state::configured && sp->substate != package_substate::system); - // The being re-evaluated dependent must be configured as a source package - // and should not be collected recursively (due to upgrade, etc). + // The being (pre-)re-evaluated dependent must be configured as a source + // package and should not be collected recursively (due to upgrade, etc). // - assert (!reeval || (src_conf && !pkg.recollect_recursively (rpt_depts))); + assert ((!pre_reeval && !reeval) || + (src_conf && !pkg.recollect_recursively (rpt_depts))); if (src_conf) { - repointed_dependents::const_iterator i (rpt_depts.find (pk)); - - if (i != rpt_depts.end ()) - rpt_prereq_flags = &i->second; - - if (!reeval && !pkg.recollect_recursively (rpt_depts)) + if (!pre_reeval && !reeval && !pkg.recollect_recursively (rpt_depts)) { l5 ([&]{trace << "skip configured " << pkg.available_name_version_db ();}); - return; + return nullopt; } + + repointed_dependents::const_iterator i (rpt_depts.find (pk)); + + if (i != rpt_depts.end ()) + rpt_prereq_flags = &i->second; } // Iterate over dependencies, trying to unambiguously select a @@ -1820,7 +1759,9 @@ namespace bpkg // if (!pkg.dependencies) { - l5 ([&]{trace << (reeval ? "reeval " : "begin ") + l5 ([&]{trace << (pre_reeval ? "pre-reeval " : + reeval ? "reeval " : + "begin " ) << pkg.available_name_version_db ();}); pkg.dependencies = dependencies (); @@ -1833,7 +1774,20 @@ namespace bpkg } if (!pkg.skeleton) - pkg.init_skeleton (options); + { + // In the pre-reevaluation mode make sure that the user-specified + // configuration is loaded by the skeleton. + // + if (pre_reeval) + { + pkg.init_skeleton (options, + nullptr /* override */, + sp->effective_src_root (pdb.config), + sp->effective_out_root (pdb.config)); + } + else + pkg.init_skeleton (options); + } } else l5 ([&]{trace << "resume " << pkg.available_name_version_db ();}); @@ -1848,7 +1802,7 @@ namespace bpkg if (sdeps.size () == deps.size ()) { l5 ([&]{trace << "end " << pkg.available_name_version_db ();}); - return; + return nullopt; } // Show how we got here if things go wrong. @@ -1872,28 +1826,59 @@ namespace bpkg } })); - dep_chain.push_back (pkg); + if (!pre_reeval) + dep_chain.push_back (pkg); assert (sdeps.size () < deps.size ()); package_skeleton& skel (*pkg.skeleton); + // We shouldn't be failing in the reevaluation mode, given that we only + // reevaluate a package if its pre-reevaluation succeeds. + // auto fail_reeval = [&pkg] () { fail << "unable to re-create dependency information of already " << "configured package " << pkg.available_name_version_db () << info << "likely cause is change in external environment" << - info << "consider resetting the build configuration"; + info << "if not, please report in https://github.com/build2/build2/issues/302"; }; bool postponed (false); bool reevaluated (false); + vector<postponed_configuration::dependency> r; + + if (pre_reeval) + { + if (!sp->dependency_alternatives_section.loaded ()) + pdb.load (*sp, sp->dependency_alternatives_section); + + // It doesn't feel like the number of depends clauses may differ for the + // available and selected packages in the pre-reevaluation mode since + // they must refer to the same package version. If it still happens, + // maybe due to some manual tampering, let's assume this as a deviation + // case. + // + size_t nn (deps.size ()); + size_t on (sp->dependency_alternatives.size ()); + + if (nn != on) + { + l5 ([&]{trace << "re-evaluation of dependent " + << pkg.available_name_version_db () + << " deviated: number of depends clauses changed to " + << nn << " from " << on;}); + + throw reeval_deviated (); + } + } + for (size_t di (sdeps.size ()); di != deps.size (); ++di) { // Fail if we missed the re-evaluation target position for any reason. // - if (reeval && di == reeval_pos.first) // Note: reeval_pos is 1-based. + if (reeval && di == reeval_pos->first) // Note: reeval_pos is 1-based. fail_reeval (); const dependency_alternatives_ex& das (deps[di]); @@ -1905,6 +1890,26 @@ namespace bpkg if (toolchain_buildtime_dependency (options, das, &nm)) { + if (pre_reeval) + { + size_t oi (sp->dependency_alternatives[di]); + + // It doesn't feel like it may happen in the pre-reevaluation + // mode. If it still happens, maybe due to some manual tampering, + // let's assume this as a deviation case. + // + if (oi != 0) + { + l5 ([&]{trace << "re-evaluation of dependent " + << pkg.available_name_version_db () + << " deviated at depends clause " << di + 1 + << ": toolchain buildtime dependency replaced the " + << " regular one with selected alternative " << oi;}); + + throw reeval_deviated (); + } + } + sdeps.push_back (move (sdas)); salts.push_back (0); // Keep parallel to sdeps. continue; @@ -1935,6 +1940,22 @@ namespace bpkg if (edas.empty ()) { + if (pre_reeval) + { + size_t oi (sp->dependency_alternatives[di]); + + if (oi != 0) + { + l5 ([&]{trace << "re-evaluation of dependent " + << pkg.available_name_version_db () + << " deviated at depends clause " << di + 1 + << ": dependency with previously selected " + << "alternative " << oi << " is now disabled";}); + + throw reeval_deviated (); + } + } + sdeps.push_back (move (sdas)); salts.push_back (0); // Keep parallel to sdeps. continue; @@ -2026,6 +2047,7 @@ namespace bpkg &apc, postponed_repo, &dep_chain, + pre_reeval, &trace, this] (const dependency_alternative& da, @@ -2046,6 +2068,21 @@ namespace bpkg if (buildtime && pdb.type == build2_config_type) { + // It doesn't feel like it may happen in the pre-reevaluation + // mode. If it still happens, maybe due to some manual + // tampering, let's assume this as a deviation case. + // + if (pre_reeval) + { + l5 ([&]{trace << "re-evaluation of dependent " + << pkg.available_name_version_db () + << " deviated: build-time dependency " << dn + << " is now in build system module " + << "configuration";}); + + throw reeval_deviated (); + } + assert (dr == nullptr); // Should fail on the "silent" run. // Note that the dependent is not necessarily a build system @@ -2110,6 +2147,11 @@ namespace bpkg if (!wildcard (*dep_constr) && !satisfies (*dep_constr, dp.constraint)) { + // We should end up throwing reeval_deviated exception + // before the diagnostics run in the pre-reevaluation mode. + // + assert (!pre_reeval || dr == nullptr); + if (dr != nullptr) *dr << error << "unable to satisfy constraints on package " << dn << @@ -2199,6 +2241,21 @@ namespace bpkg if (dsp->state == package_state::broken) { + // If it happens in the pre-reevaluation mode, that may mean + // that the package has become broken since the time the + // dependent was built. Let's assume this as a deviation case + // and fail on the re-collection. + // + if (pre_reeval) + { + l5 ([&]{trace << "re-evaluation of dependent " + << pkg.available_name_version_db () + << " deviated: package " << dn << *ddb + << " is broken";}); + + throw reeval_deviated (); + } + assert (dr == nullptr); // Should fail on the "silent" run. fail << "unable to build broken package " << dn << *ddb << @@ -2316,6 +2373,24 @@ namespace bpkg db = &ldb; else { + // If it happens in the pre-reevaluation mode, that may + // mean that some new configuration has been linked since + // the time the dependent was built. Let's assume this as + // a deviation case. + // + if (pre_reeval) + { + l5 ([&]{trace << "re-evaluation of dependent " + << pkg.available_name_version_db () + << " deviated: now multiple possible " + << type << " configurations for " + << "build-time dependency (" << dp << "): " + << db->config_orig << ", " + << ldb.config_orig;}); + + throw reeval_deviated (); + } + assert (dr == nullptr); // Should fail on the "silent" run. fail << "multiple possible " << type << " configurations " @@ -2334,6 +2409,22 @@ namespace bpkg // if (db == nullptr) { + // If it happens in the pre-reevaluation mode, that may mean + // that some configuration has been unlinked since the time + // the dependent was built. Let's assume this as a deviation + // case. + // + if (pre_reeval) + { + l5 ([&]{trace << "re-evaluation of dependent " + << pkg.available_name_version_db () + << " deviated: now no suitable configuration " + << "is found for build-time dependency (" + << dp << ')';}); + + throw reeval_deviated (); + } + // The private config should be created on the "silent" run // and so there always should be a suitable configuration on // the diagnostics run. @@ -2431,6 +2522,21 @@ namespace bpkg build2_module (dn) && pdb == *ddb) { + // It doesn't feel like it may happen in the pre-reevaluation + // mode. If it still happens, maybe due to some manual + // tampering, let's assume this as a deviation case. + // + if (pre_reeval) + { + l5 ([&]{trace << "re-evaluation of dependent " + << pkg.available_name_version_db () + << " deviated: now unable to build build system " + << "module " << dn << " in its dependent " + << "package configuration " << pdb.config_orig;}); + + throw reeval_deviated (); + } + assert (dr == nullptr); // Should fail on the "silent" run. // Note that the dependent package information is printed by the @@ -2454,6 +2560,19 @@ namespace bpkg // if (af == nullptr) { + // If it happens in the pre-reevaluation mode, that may mean + // that the dependent has become an orphan since the time it + // was built. Let's assume this as a deviation case. + // + if (pre_reeval) + { + l5 ([&]{trace << "re-evaluation of dependent " + << pkg.available_name_version_db () + << " deviated: is now orphaned";}); + + throw reeval_deviated (); + } + assert (dr == nullptr); // Should fail on the "silent" run. fail << "package " << pkg.available_name_version_db () @@ -2517,6 +2636,22 @@ namespace bpkg if (dap == nullptr) { + // If it happens in the pre-reevaluation mode, that may mean + // that the repositories has been refetched since the time the + // dependent was built and don't contain a satisfactory + // package anymore. Let's assume this as a deviation case. + // + if (pre_reeval) + { + l5 ([&]{trace << "re-evaluation of dependent " + << pkg.available_name_version_db () + << " deviated: unable to satisfy " + << (!dep_constr ? "" : "user-specified ") + << "dependency constraint (" << d << ')';}); + + throw reeval_deviated (); + } + if (dep_constr && !system && postponed_repo != nullptr) { // We shouldn't be called in the diag mode for the postponed @@ -2613,6 +2748,11 @@ namespace bpkg // if (dap->system_version (*ddb) == nullptr) { + // We should end up throwing reeval_deviated exception + // before the diagnostics run in the pre-reevaluation mode. + // + assert (!pre_reeval || dr == nullptr); + if (dr != nullptr) *dr << error << "dependency " << d << " of package " << nm << " is not available in source" << @@ -2624,6 +2764,11 @@ namespace bpkg if (!satisfies (*dap->system_version (*ddb), d.constraint)) { + // We should end up throwing reeval_deviated exception + // before the diagnostics run in the pre-reevaluation mode. + // + assert (!pre_reeval || dr == nullptr); + if (dr != nullptr) *dr << error << "dependency " << d << " of package " << nm << " is not available in source" << @@ -2679,7 +2824,7 @@ namespace bpkg { const shared_ptr<available_package>& dap (b.available); - assert (dap != nullptr); // Otherwise we would fail earlier. + assert (dap != nullptr); // Otherwise we would have failed earlier. const dependency& d (b.dependency); @@ -2709,6 +2854,12 @@ namespace bpkg { if (!satisfies (v1, c2.value)) { + // We should end up throwing reeval_deviated exception + // before the diagnostics run in the pre-reevaluation + // mode. + // + assert (!pre_reeval || dr == nullptr); + if (dr != nullptr) { const package_name& n (d.name); @@ -2759,9 +2910,10 @@ namespace bpkg &dep_chain, postponed_repo, postponed_alts, + &postponed_recs, + &postponed_edeps, &postponed_deps, &postponed_cfgs, - &postponed_poss, &unacceptable_alts, &di, reeval, @@ -2782,39 +2934,39 @@ namespace bpkg // pair<size_t, size_t> dp (di + 1, dai + 1); - if (reeval && - dp.first == reeval_pos.first && - dp.second != reeval_pos.second) + if (reeval && + dp.first == reeval_pos->first && + dp.second != reeval_pos->second) fail_reeval (); postponed_configuration::packages cfg_deps; for (prebuild& b: bs) { - build_package bp { + build_package bpk { build_package::build, - b.db, - b.selected, - b.available, - move (b.repository_fragment), - nullopt, // Dependencies. - nullopt, // Dependencies alternatives. - nullopt, // Package skeleton. - nullopt, // Postponed dependency alternatives. - false, // Recursive collection. - nullopt, // Hold package. - nullopt, // Hold version. - {}, // Constraints. - b.system, - false, // Keep output directory. - false, // Disfigure (from-scratch reconf). - false, // Configure-only. - nullopt, // Checkout root. - false, // Checkout purge. - strings (), // Configuration variables. - {pk}, // Required by (dependent). - true, // Required by dependents. - 0}; // State flags. + b.db, + b.selected, + b.available, + move (b.repository_fragment), + nullopt, // Dependencies. + nullopt, // Dependencies alternatives. + nullopt, // Package skeleton. + nullopt, // Postponed dependency alternatives. + false, // Recursive collection. + nullopt, // Hold package. + nullopt, // Hold version. + {}, // Constraints. + b.system, + false, // Keep output directory. + false, // Disfigure (from-scratch reconf). + false, // Configure-only. + nullopt, // Checkout root. + false, // Checkout purge. + strings (), // Configuration variables. + {pk}, // Required by (dependent). + true, // Required by dependents. + 0}; // State flags. const optional<version_constraint>& constraint ( b.dependency.constraint); @@ -2822,12 +2974,12 @@ namespace bpkg // Add our constraint, if we have one. // // Note that we always add the constraint implied by the - // dependent. The user-implied constraint, if present, will be + // dependent. The user-implied constraint, if present, will be // added when merging from the pre-entered entry. So we will have // both constraints for completeness. // if (constraint) - bp.constraints.emplace_back (pdb, nm.string (), *constraint); + bpk.constraints.emplace_back (pdb, nm.string (), *constraint); // Now collect this prerequisite. If it was actually collected // (i.e., it wasn't already there) and we are forcing a downgrade @@ -2933,18 +3085,19 @@ namespace bpkg // build_package* p ( collect_build (options, - move (bp), - fdb, - rpt_depts, - apc, - initial_collection, + move (bpk), replaced_vers, postponed_cfgs, nullptr /* dep_chain */, + false /* initial_collection */, + nullptr /* fdb */, + nullptr /* apc */, + nullptr /* rpt_depts */, nullptr /* postponed_repo */, nullptr /* postponed_alts */, + nullptr /* postponed_recs */, + nullptr /* postponed_edeps */, nullptr /* postponed_deps */, - nullptr /* postponed_poss */, nullptr /* unacceptable_alts */, verify)); @@ -2952,17 +3105,30 @@ namespace bpkg // Do not collect prerequisites recursively for dependent // re-evaluation. Instead, if the re-evaluation position is - // reached, collect the dependency packages to add them to the + // reached, stash the dependency packages to add them to the // existing dependent's cluster. // - if (reeval) - { - if (dp == reeval_pos) - cfg_deps.push_back (move (dpk)); - + if (reeval && dp != *reeval_pos) continue; + + // Note that while collect_build() may prefer an existing entry in + // the map and return NULL, the recursive collection of this + // preferred entry may have been postponed due to the existing + // dependent (see collect_build_prerequisites() for details). Now, + // we can potentially be recursively collecting such a dependent + // after its re-evaluation to some earlier than this dependency + // position. If that's the case, it is the time to collect this + // dependency (unless it has a config clause which will be handled + // below). + // + if (p == nullptr) + { + p = entered_build (dpk); + assert (p != nullptr); } + bool collect_prereqs (!p->recursive_collection); + // Do not recursively collect a dependency of a dependent with // configuration clauses, which could be this or some other // (indicated by the presence in postponed_deps) dependent. In the @@ -2973,12 +3139,7 @@ namespace bpkg // directly right after the configuration negotiation (rather than // via the dependent). // - bool collect_prereqs (p != nullptr); - { - build_package* bp (entered_build (dpk)); - assert (bp != nullptr); - if (da.prefer || da.require) { // Indicate that the dependent with configuration clauses is @@ -2996,8 +3157,8 @@ namespace bpkg postponed_deps.emplace (dpk, postponed_dependency { false /* without_config */, - true /* with_config */, - initial_collection}); + true /* with_config */, + initial_collection}); } else i->second.with_config = true; @@ -3005,15 +3166,27 @@ namespace bpkg // Prematurely collected before we saw any config clauses. // - if (bp->recursive_collection && + if (p->recursive_collection && postponed_cfgs.find_dependency (dpk) == nullptr) { - l5 ([&]{trace << "cannot cfg-postpone dependency " - << bp->available_name_version_db () - << " of dependent " - << pkg.available_name_version_db () - << " (collected prematurely), " - << "throwing postpone_dependency";}); + if (reeval) + { + l5 ([&]{trace << "cannot re-evaluate existing dependent " + << pkg.available_name_version_db () + << " due to dependencys " + << p->available_name_version_db () + << " (collected prematurely), " + << "throwing postpone_dependency";}); + } + else + { + l5 ([&]{trace << "cannot cfg-postpone dependency " + << p->available_name_version_db () + << " of dependent " + << pkg.available_name_version_db () + << " (collected prematurely), " + << "throwing postpone_dependency";}); + } // Don't print the "while satisfying..." chain. // @@ -3022,12 +3195,15 @@ namespace bpkg throw postpone_dependency (move (dpk)); } - // Postpone until (re-)negotiation. - // - l5 ([&]{trace << "cfg-postpone dependency " - << bp->available_name_version_db () - << " of dependent " - << pkg.available_name_version_db ();}); + if (!reeval) + { + // Postpone until (re-)negotiation. + // + l5 ([&]{trace << "cfg-postpone dependency " + << p->available_name_version_db () + << " of dependent " + << pkg.available_name_version_db ();}); + } cfg_deps.push_back (move (dpk)); @@ -3042,7 +3218,7 @@ namespace bpkg if (i != postponed_deps.end ()) { l5 ([&]{trace << "dep-postpone dependency " - << bp->available_name_version_db () + << p->available_name_version_db () << " of dependent " << pkg.available_name_version_db ();}); @@ -3053,7 +3229,7 @@ namespace bpkg else { l5 ([&]{trace << "no cfg-clause for dependency " - << bp->available_name_version_db () + << p->available_name_version_db () << " of dependent " << pkg.available_name_version_db ();}); } @@ -3063,18 +3239,19 @@ namespace bpkg if (collect_prereqs) collect_build_prerequisites (options, *p, + dep_chain, + initial_collection, fdb, - rpt_depts, apc, - initial_collection, + rpt_depts, replaced_vers, - dep_chain, postponed_repo, postponed_alts, 0 /* max_alt_index */, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs, - postponed_poss, unacceptable_alts); } @@ -3190,8 +3367,31 @@ namespace bpkg { reevaluated = true; - // Note: the dependent may already exist in the cluster with a - // subset of dependencies. + // As a first step add this dependent/dependencies to one of the + // new/existing postponed_configuration clusters, which could + // potentially cause some of them to be merged. Note that when + // we re-evaluate existing dependents of dependencies in a + // cluster, these dependents can potentially be added to + // different clusters (see collect_build_postponed() for + // details). Here are the possibilities and what we should do in + // each case. + // + // 1. Got added to a new cluster -- this dependent got postponed + // and we return false. + // + // 2. Got added to an existing non-yet-negotiated cluster (which + // could potentially involve merging a bunch of them) -- + // ditto. Note this also covers adding into a cluster which + // contain dependencies whose existing dependents we are + // currently re-evaluating (the negotiated member is absent + // but the depth is non-zero). + // + // 3. Got added to an existing already-[being]-negotiated + // cluster (which could potentially involve merging a bunch + // of them, some negotiated, some being negotiated, and some + // not yet negotiated). Perhaps just making the resulting + // cluster shadow and rolling back, just like in the other + // case (non-existing dependent), will do. // postponed_configuration& cfg ( postponed_cfgs.add (pk, @@ -3200,29 +3400,7 @@ namespace bpkg cfg_deps, has_alt).first); - // Can we merge clusters as a result? Seems so. - // - // - Simple case is if the cluster(s) being merged are not - // negotiated. Then perhaps we could handle this via the same - // logic that handles the addition of extra dependencies. - // - // - For the complex case, perhaps just making the resulting - // cluster shadow and rolling back, just like in the other - // case (non-existing dependent). - // - // Note: this is a special case of the below more general logic. - // - // Also note that we can distinguish the simple case by the fact - // that the resulting cluster is not negotiated. Note however, - // that in this case it is guaranteed that all the involved - // clusters will be merged into the cluster which the being - // re-evaluated dependent belongs to since this cluster (while - // not being negotiated) already has non-zero depth (see - // collect_build_postponed() for details). - // - assert (cfg.depth != 0); - - if (cfg.negotiated) + if (cfg.negotiated) // Case (3). { l5 ([&]{trace << "re-evaluating dependent " << pkg.available_name_version_db () @@ -3515,18 +3693,19 @@ namespace bpkg collect_build_prerequisites (options, *b, + dep_chain, + initial_collection, fdb, - rpt_depts, apc, - initial_collection, + rpt_depts, replaced_vers, - dep_chain, postponed_repo, postponed_alts, 0 /* max_alt_index */, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs, - postponed_poss, unacceptable_alts); // Unless the dependency is already being reconfigured, @@ -3591,15 +3770,14 @@ namespace bpkg // package to the postponements set (can potentially already be there) // and saving the enabled alternatives. // - auto postpone = [&pkg, &edas, &postponed] - (postponed_packages* postpones) - { - if (postpones != nullptr) - postpones->insert (&pkg); + auto postpone = [&pkg, &edas, &postponed] (postponed_packages* postpones) + { + if (postpones != nullptr) + postpones->insert (&pkg); - pkg.postponed_dependency_alternatives = move (edas); - postponed = true; - }; + pkg.postponed_dependency_alternatives = move (edas); + postponed = true; + }; // Iterate over the enabled dependencies and try to select a // satisfactory alternative. @@ -3621,10 +3799,10 @@ namespace bpkg ? &sp->prerequisites : nullptr); - // During the dependent re-evaluation we always try to reproduce the - // existing setup. + // During the dependent (pre-)re-evaluation we always try to reproduce + // the existing setup. // - assert (!reeval || prereqs != nullptr); + assert ((!reeval && !pre_reeval) || prereqs != nullptr); for (bool unacceptable (false);;) { @@ -3657,6 +3835,18 @@ namespace bpkg // bool reused_only (false); + auto pre_reeval_append_result = [&r] (pair<size_t, size_t> pos, + prebuilds&& builds) + { + postponed_configuration::packages deps; + deps.reserve (builds.size ()); + + for (prebuild& b: builds) + deps.emplace_back (b.db, move (b.dependency.name)); + + r.emplace_back (pos, move (deps), nullopt /* has_alternative */); + }; + for (size_t i (0); i != edas.size (); ++i) { // Skip the unacceptable alternatives. @@ -3683,7 +3873,7 @@ namespace bpkg const dependency_alternative& da (edas[i].first); - precollect_result r (precollect (da, das.buildtime, prereqs)); + precollect_result pcr (precollect (da, das.buildtime, prereqs)); // If we didn't come up with satisfactory dependency builds, then // skip this alternative and try the next one, unless the collecting @@ -3699,9 +3889,9 @@ namespace bpkg // // depends: libfoo >= 2.0.0 | {libfoo >= 1.0.0 libbar} // - if (!r.builds) + if (!pcr.builds) { - if (r.repo_postpone) + if (pcr.repo_postpone) { if (reeval) fail_reeval (); @@ -3713,7 +3903,7 @@ namespace bpkg // If this alternative is reused but is not satisfactory, then // switch to the reused-only mode. // - if (r.reused && r.unsatisfactory) + if (pcr.reused && pcr.unsatisfactory) reused_only = true; continue; @@ -3730,7 +3920,7 @@ namespace bpkg // if (!first_alt) { - first_alt = make_pair (i, move (r)); + first_alt = make_pair (i, move (pcr)); continue; } @@ -3741,11 +3931,16 @@ namespace bpkg // auto try_select = [postponed_alts, &max_alt_index, &edas, &pkg, + di, prereqs, + pre_reeval, reeval, &trace, - &postpone, &collect, &select] - (size_t index, precollect_result&& r) + &postpone, + &collect, + &select, + &pre_reeval_append_result] + (size_t index, precollect_result&& pcr) { const auto& eda (edas[index]); const dependency_alternative& da (eda.first); @@ -3773,14 +3968,39 @@ namespace bpkg // Select this alternative if all its dependencies are reused and // do nothing about it otherwise. // - if (r.reused) + if (pcr.reused) { // On the diagnostics run there shouldn't be any alternatives // that we could potentially select. // assert (postponed_alts != nullptr); - if (!collect (da, dai, move (*r.builds), prereqs)) + if (pre_reeval) + { + size_t ni (dai + 1); + size_t oi (pkg.selected->dependency_alternatives[di]); + + if (ni != oi) + { + l5 ([&]{trace << "re-evaluation of dependent " + << pkg.available_name_version_db () + << " deviated at depends clause " << di + 1 + << ": selected alternative changed to " << ni + << " from " << oi;}); + + throw reeval_deviated (); + } + + pre_reeval_append_result (make_pair (di + 1, ni), + move (*pcr.builds)); + + if (da.prefer || da.require) + { + postpone (nullptr); + return true; + } + } + else if (!collect (da, dai, move (*pcr.builds), prereqs)) { postpone (nullptr); // Already inserted into postponed_cfgs. return true; @@ -3789,9 +4009,9 @@ namespace bpkg select (da, dai); // Make sure no more true alternatives are selected during this - // function call unless we are re-evaluating a dependent. + // function call unless we are (pre-)reevaluating a dependent. // - if (!reeval) + if (!reeval && !pre_reeval) max_alt_index = 0; return true; @@ -3813,7 +4033,7 @@ namespace bpkg break; } - if (try_select (i, move (r))) + if (try_select (i, move (pcr))) break; // Not all of the alternative dependencies are reused, so go to @@ -3832,22 +4052,47 @@ namespace bpkg { assert (first_alt); - precollect_result& r (first_alt->second); + precollect_result& pcr (first_alt->second); - assert (r.builds); + assert (pcr.builds); - if (r.reused || !reused_only) + if (pcr.reused || !reused_only) { // If there are any unacceptable alternatives, then the remaining // one should be reused. // - assert (!unacceptable || r.reused); + assert (!unacceptable || pcr.reused); const auto& eda (edas[first_alt->first]); const dependency_alternative& da (eda.first); size_t dai (eda.second); - if (!collect (da, dai, move (*r.builds), prereqs)) + if (pre_reeval) + { + size_t ni (dai + 1); + size_t oi (sp->dependency_alternatives[di]); + + if (ni != oi) + { + l5 ([&]{trace << "re-evaluation of dependent " + << pkg.available_name_version_db () + << " deviated for depends clause " << di + 1 + << ": selected alternative (single) changed to " + << ni << " from " << oi;}); + + throw reeval_deviated (); + } + + pre_reeval_append_result (make_pair (di + 1, ni), + move (*pcr.builds)); + + if (da.prefer || da.require) + { + postpone (nullptr); + break; + } + } + else if (!collect (da, dai, move (*pcr.builds), prereqs)) { postpone (nullptr); // Already inserted into postponed_cfgs. break; @@ -3870,6 +4115,19 @@ namespace bpkg // if (prereqs != nullptr) { + if (pre_reeval) + { + size_t oi (sp->dependency_alternatives[di]); + + l5 ([&]{trace << "re-evaluation of dependent " + << pkg.available_name_version_db () + << " deviated for depends clause " << di + 1 + << ": now can't select alternative, previously " + << oi << " was selected";}); + + throw reeval_deviated (); + } + if (reeval) fail_reeval (); @@ -3877,6 +4135,10 @@ namespace bpkg continue; } + // Otherwise we would have thrown/failed earlier. + // + assert (!pre_reeval && !reeval); + // We shouldn't end up with the "no alternative to select" case if any // alternatives are unacceptable. // @@ -3973,10 +4235,7 @@ namespace bpkg // Print the reason. // - precollect (da.first, - das.buildtime, - nullptr /* prereqs */, - &dr); + precollect (da.first, das.buildtime, nullptr /* prereqs */, &dr); } } } @@ -3994,29 +4253,56 @@ namespace bpkg assert (postponed); } - dep_chain.pop_back (); + if (pre_reeval) + { + l5 ([&] + { + diag_record dr (trace); + dr << "pre-reevaluated " << pkg.available_name_version_db () + << ": "; + + if (postponed) + { + assert (!r.empty ()); + + dr << r.back ().position.first << ',' + << r.back ().position.second; + } + else + dr << "end reached"; + }); + } + else + { + dep_chain.pop_back (); + + l5 ([&]{trace << (!postponed ? "end " : + reeval ? "re-evaluated " : + "postpone ") + << pkg.available_name_version_db ();}); + } - l5 ([&]{trace << (!postponed ? "end " : - reeval ? "re-evaluated " : - "postpone ") - << pkg.available_name_version_db ();}); + return pre_reeval && postponed + ? optional<vector<postponed_configuration::dependency>> (move (r)) + : nullopt; } void build_packages:: collect_build_prerequisites (const pkg_build_options& o, database& db, const package_name& name, + bool initial_collection, const function<find_database_function>& fdb, - const repointed_dependents& rpt_depts, const function<add_priv_cfg_function>& apc, - bool initial_collection, + const repointed_dependents& rpt_depts, replaced_versions& replaced_vers, postponed_packages& postponed_repo, postponed_packages& postponed_alts, size_t max_alt_index, + postponed_packages& postponed_recs, + postponed_existing_dependencies& postponed_edeps, postponed_dependencies& postponed_deps, postponed_configurations& postponed_cfgs, - postponed_positions& postponed_poss, unacceptable_alternatives& unacceptable_alts) { auto mi (map_.find (db, name)); @@ -4026,33 +4312,36 @@ namespace bpkg collect_build_prerequisites (o, mi->second.package, + dep_chain, + initial_collection, fdb, - rpt_depts, apc, - initial_collection, + rpt_depts, replaced_vers, - dep_chain, &postponed_repo, &postponed_alts, max_alt_index, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs, - postponed_poss, unacceptable_alts); } void build_packages:: - collect_repointed_dependents (const pkg_build_options& o, - const repointed_dependents& rpt_depts, - replaced_versions& replaced_vers, - postponed_packages& postponed_repo, - postponed_packages& postponed_alts, - postponed_dependencies& postponed_deps, - postponed_configurations& postponed_cfgs, - postponed_positions& postponed_poss, - unacceptable_alternatives& unacceptable_alts, - const function<find_database_function>& fdb, - const function<add_priv_cfg_function>& apc) + collect_repointed_dependents ( + const pkg_build_options& o, + const repointed_dependents& rpt_depts, + replaced_versions& replaced_vers, + postponed_packages& postponed_repo, + postponed_packages& postponed_alts, + postponed_packages& postponed_recs, + postponed_existing_dependencies& postponed_edeps, + postponed_dependencies& postponed_deps, + postponed_configurations& postponed_cfgs, + unacceptable_alternatives& unacceptable_alts, + const function<find_database_function>& fdb, + const function<add_priv_cfg_function>& apc) { for (const auto& rd: rpt_depts) { @@ -4124,17 +4413,18 @@ namespace bpkg // collect_build (o, move (p), - fdb, - rpt_depts, - apc, - true /* initial_collection */, replaced_vers, postponed_cfgs, &dep_chain, + true /* initial_collection */, + fdb, + apc, + &rpt_depts, &postponed_repo, &postponed_alts, + &postponed_recs, + &postponed_edeps, &postponed_deps, - &postponed_poss, &unacceptable_alts); } } @@ -4305,10 +4595,11 @@ namespace bpkg replaced_versions& replaced_vers, postponed_packages& postponed_repo, postponed_packages& postponed_alts, + postponed_packages& postponed_recs, + postponed_existing_dependencies& postponed_edeps, postponed_dependencies& postponed_deps, postponed_configurations& postponed_cfgs, strings& postponed_cfgs_history, - postponed_positions& postponed_poss, unacceptable_alternatives& unacceptable_alts, const function<find_database_function>& fdb, const repointed_dependents& rpt_depts, @@ -4325,9 +4616,12 @@ namespace bpkg snapshot (const build_packages& pkgs, const postponed_packages& postponed_repo, const postponed_packages& postponed_alts, + const postponed_packages& postponed_recs, + const postponed_existing_dependencies& postponed_edeps, const postponed_dependencies& postponed_deps, const postponed_configurations& postponed_cfgs) : pkgs_ (pkgs), + postponed_edeps_ (postponed_edeps), postponed_deps_ (postponed_deps), postponed_cfgs_ (postponed_cfgs) { @@ -4341,18 +4635,22 @@ namespace bpkg save (postponed_repo_, postponed_repo); save (postponed_alts_, postponed_alts); + save (postponed_recs_, postponed_recs); } void restore (build_packages& pkgs, postponed_packages& postponed_repo, postponed_packages& postponed_alts, + postponed_packages& postponed_recs, + postponed_existing_dependencies& postponed_edeps, postponed_dependencies& postponed_deps, postponed_configurations& postponed_cfgs) { - pkgs = move (pkgs_); - postponed_cfgs = move (postponed_cfgs_); - postponed_deps = move (postponed_deps_); + pkgs = move (pkgs_); + postponed_cfgs = move (postponed_cfgs_); + postponed_deps = move (postponed_deps_); + postponed_edeps = move (postponed_edeps_); auto restore = [&pkgs] (postponed_packages& d, const vector<package_key>& s) @@ -4369,6 +4667,7 @@ namespace bpkg restore (postponed_repo, postponed_repo_); restore (postponed_alts, postponed_alts_); + restore (postponed_recs, postponed_recs_); } private: @@ -4376,31 +4675,13 @@ namespace bpkg // memory. We could probably optimize this some more if necessary // (there are still sets/maps inside). // - build_packages pkgs_; - vector<package_key> postponed_repo_; - vector<package_key> postponed_alts_; - postponed_dependencies postponed_deps_; - postponed_configurations postponed_cfgs_; - }; - - // This exception is thrown if negotiation of the current cluster needs to - // be skipped until later. This is normally required if this cluster - // contains some existing dependent which needs to be re-evaluated to a - // dependency position greater than some other not yet negotiated cluster - // will re-evaluate this dependent to. Sometimes this another cluster yet - // needs to be created in which case the exception carries the information - // required for that (see the postponed_position's replace flag for - // details). - // - struct skip_configuration - { - optional<existing_dependent> dependent; - pair<size_t, size_t> new_position; - - skip_configuration () = default; - - skip_configuration (existing_dependent&& d, pair<size_t, size_t> n) - : dependent (move (d)), new_position (n) {} + build_packages pkgs_; + vector<package_key> postponed_repo_; + vector<package_key> postponed_alts_; + vector<package_key> postponed_recs_; + postponed_existing_dependencies postponed_edeps_; + postponed_dependencies postponed_deps_; + postponed_configurations postponed_cfgs_; }; size_t depth (pcfg != nullptr ? pcfg->depth : 0); @@ -4428,29 +4709,36 @@ namespace bpkg assert (!pcfg->negotiated); - // Re-evaluate existing dependents with configuration clause for - // dependencies in this configuration cluster up to these - // dependencies. Omit dependents which are already being built or - // dropped. Note that these dependents, potentially with additional - // dependencies, will be added to this cluster with the `existing` flag - // as a part of the dependents' re-evaluation (see the collect lambda in - // collect_build_prerequisites() for details). + // Re-evaluate existing dependents for dependencies in this + // configuration cluster. Omit dependents which are already being built + // or dropped. + // + // Note that the existing dependent can be re-evaluated to an earlier + // position than the position of the dependency which has introduced + // this existing dependent. Thus, re-evaluating such a dependent does + // not necessarily add this dependent together with the dependencies at + // the re-evaluation target position specifically to this cluster. We, + // however, re-evaluate all the discovered existing dependents. Also + // note that these dependents will be added to their respective clusters + // with the `existing` flag as a part of the dependents' re-evaluation + // (see the collect lambda in collect_build_prerequisites() for + // details). // // After being re-evaluated the existing dependents are recursively - // collected in the same way as the new dependents. + // collected in the same way and at the same time as the new dependents + // of the clusters they belong to. // { // Map existing dependents to the dependencies they apply a // configuration to. Also, collect the information which is required - // for a dependent re-evaluation and its subsequent recursive - // collection (selected package, etc). + // for a dependent re-evaluation (selected package, etc). // - // As mentioned earlier, we may end up adding additional dependencies - // to pcfg->dependencies which in turn may have additional existing + // Note that we may end up adding additional dependencies to + // pcfg->dependencies which in turn may have additional existing // dependents which we need to process. Feels like doing this // iteratively is the best option. // - // Note that we need to make sure we don't re-process the same + // Also note that we need to make sure we don't re-process the same // existing dependents. // struct existing_dependent_ex: existing_dependent @@ -4481,136 +4769,79 @@ namespace bpkg // const package_key& p (deps[i]); - // If the dependent is being built, then check if it was - // re-evaluated to the position greater than the dependency - // position. Return true if that's the case, so this package is - // added to the resulting list and we can handle this situation. - // - // Note that we rely on "small function object" optimization - // here. - // - const function<verify_dependent_build_function> verify ( - [&postponed_cfgs, pcfg] - (const package_key& pk, pair<size_t, size_t> pos) - { - for (const postponed_configuration& cfg: postponed_cfgs) - { - if (&cfg == pcfg || cfg.negotiated) - { - if (const pair<size_t, size_t>* p = - cfg.existing_dependent_position (pk)) - { - if (p->first > pos.first) - return true; - } - } - } - - return false; - }); - for (existing_dependent& ed: query_existing_dependents (trace, + o, p.db, p.name, - replaced_vers, + fdb, rpt_depts, - verify)) + replaced_vers)) { - package_key pk (ed.db, ed.selected->name); - - // If this dependent is present in postponed_deps, then it means - // someone depends on it with configuration and it's no longer - // considered an existing dependent (it will be reconfigured). - // However, this fact may not be reflected yet. And it can - // actually turn out bogus. - // - auto pi (postponed_deps.find (pk)); - if (pi != postponed_deps.end ()) + if (ed.dependency) { - l5 ([&]{trace << "skip dep-postponed existing dependent " - << pk << " of dependency " << p;}); + package_key pk (ed.db, ed.selected->name); - // Note that here we would re-evaluate the existing dependent - // without specifying any configuration for it. + // If this dependent is present in postponed_deps, then it + // means someone depends on it with configuration and it's no + // longer considered an existing dependent (it will be + // reconfigured). However, this fact may not be reflected + // yet. And it can actually turn out bogus. // - pi->second.wout_config = true; - - continue; - } - - auto i (dependents.find (pk)); - size_t di (ed.dependency_position.first); + auto pi (postponed_deps.find (pk)); + if (pi != postponed_deps.end ()) + { + l5 ([&]{trace << "skip dep-postponed existing dependent " + << pk << " of dependency " << p;}); - // Skip re-evaluated dependent if the dependency index is - // greater than the one we have already re-evaluated to. If it - // is earlier, then add the entry to postponed_poss and throw - // postpone_position to recollect from scratch. Note that this - // entry in postponed_poss is with replacement. - // - if (i != dependents.end () && i->second.reevaluated) - { - size_t ci (i->second.dependency_position.first); + // Note that here we would re-evaluate the existing + // dependent without specifying any configuration for it. + // + pi->second.wout_config = true; - if (di > ci) continue; + } - // The newly-introduced dependency must belong to the depends - // value other then the one we have re-evaluated to. - // - assert (di < ci); - - postponed_position pp (ed.dependency_position, - true /* replace */); - - auto p (postponed_poss.emplace (pk, pp)); + auto i (dependents.find (pk)); - if (!p.second) + // If the existing dependent is not in the map yet, then add + // it. + // + if (i == dependents.end ()) { - assert (p.first->second > pp); - p.first->second = pp; + if (*ed.dependency != p) + collect_existing_dependent_dependency (o, + ed, + replaced_vers, + postponed_cfgs); + + i = dependents.emplace ( + move (pk), existing_dependent_ex (move (ed))).first; + } + else + { + // We always re-evaluate to the earliest position. + // + assert (i->second.dependency_position == + ed.dependency_position); } - l5 ([&]{trace << "cannot re-evaluate dependent " - << pk << " to dependency index " << di - << " since it is already re-evaluated to " - << "greater index " << ci << " in " << *pcfg - << ", throwing postpone_position";}); - - throw postpone_position (); - } - - // If the existing dependent is not in the map yet, then add - // it. Otherwise, if the dependency position is greater than - // that one in the existing map entry then skip it (this - // position will be up-negotiated, if it's still present). - // Otherwise, if the position is less then overwrite the - // existing entry. Otherwise (the position is equal), just add - // the dependency to the existing entry. - // - // Note that we want to re-evaluate the dependent up to the - // earliest dependency position and continue with the regular - // prerequisites collection (as we do for new dependents) - // afterwards. - // - if (i == dependents.end ()) - { - i = dependents.emplace ( - move (pk), existing_dependent_ex (move (ed))).first; + // Note that we add here the dependency which introduced this + // existing dependent, rather than the dependency which + // position we re-evaluate to, and which we want to be + // mentioned in the plan, if printed. + // + i->second.dependencies.push_back (p); } else { - size_t ci (i->second.dependency_position.first); - - if (ci < di) - continue; - else if (ci > di) - i->second = existing_dependent_ex (move (ed)); - //else if (ci == di) - // ; + collect_deviated_dependent (o, + ed, + p, + replaced_vers, + postponed_recs, + postponed_cfgs); } - - i->second.dependencies.push_back (p); } } @@ -4629,108 +4860,7 @@ namespace bpkg if (ed.reevaluated) continue; - size_t di (ed.dependency_position.first); const package_key& pk (d.first); - - // Check if there is an earlier dependency position for this - // dependent that will be participating in a configuration - // negotiation and skip this cluster if that's the case. There - // are two places to check: postponed_poss and other clusters. - // - auto pi (postponed_poss.find (pk)); - if (pi != postponed_poss.end () && pi->second.first < di) - { - l5 ([&]{trace << "pos-postpone existing dependent " - << pk << " re-evaluation to dependency " - << "index " << di << " due to recorded index " - << pi->second.first << ", skipping " << *pcfg;}); - - pi->second.skipped = true; - - // If requested, override the first encountered non-replace - // position to replace (see below for details). - // - if (!pi->second.replace && postponed_poss.replace) - { - pi->second.replace = true; - postponed_poss.replace = false; - } - - if (pi->second.replace) - throw skip_configuration (move (ed), pi->second); - else - throw skip_configuration (); - } - - // The other clusters check is a bit more complicated: if the - // other cluster (with the earlier position) is not yet - // negotiated, then we skip. Otherwise, we have to add an entry - // to postponed_poss and backtrack. - // - bool skip (false); - for (const postponed_configuration& cfg: postponed_cfgs) - { - // Skip the current cluster. - // - if (&cfg == pcfg) - continue; - - if (const pair<size_t, size_t>* p = - cfg.existing_dependent_position (pk)) - { - size_t ei (p->first); // Other position. - - if (!cfg.negotiated) - { - if (ei < di) - { - l5 ([&]{trace << "cannot re-evaluate dependent " - << pk << " to dependency index " << di - << " due to earlier dependency index " - << ei << " in " << cfg << ", skipping " - << *pcfg;}); - - skip = true; - } - } - else - { - // If this were not the case, then this dependent wouldn't - // have been considered as an existing by - // query_existing_dependents() since as it is (being) - // negotiated then it is already re-evaluated and so is - // being built (see the verify lambda above). - // - assert (ei > di); - - // Feels like there cannot be an earlier position. - // - postponed_position pp (ed.dependency_position, - false /* replace */); - - auto p (postponed_poss.emplace (pk, pp)); - if (!p.second) - { - assert (p.first->second > pp); - p.first->second = pp; - } - - l5 ([&]{trace << "cannot re-evaluate dependent " - << pk << " to dependency index " << di - << " due to greater dependency " - << "index " << ei << " in " << cfg - << ", throwing postpone_position";}); - - throw postpone_position (); - } - } - } - - if (skip) - throw skip_configuration (); - - // Finally, re-evaluate the dependent. - // packages& ds (ed.dependencies); pair<shared_ptr<available_package>, @@ -4749,40 +4879,34 @@ namespace bpkg // build_package p { build_package::build, - pk.db, - move (ed.selected), - move (rp.first), - move (rp.second), - nullopt, // Dependencies. - nullopt, // Dependencies alternatives. - nullopt, // Package skeleton. - nullopt, // Postponed dependency alternatives. - false, // Recursive collection. - nullopt, // Hold package. - nullopt, // Hold version. - {}, // Constraints. - false, // System. - false, // Keep output directory. - false, // Disfigure (from-scratch reconf). - false, // Configure-only. - nullopt, // Checkout root. - false, // Checkout purge. - strings (), // Configuration variables. - set<package_key> ( // Required by (dependency). - ds.begin (), ds.end ()), - false, // Required by dependents. - build_package::build_reevaluate}; + pk.db, + move (ed.selected), + move (rp.first), + move (rp.second), + nullopt, // Dependencies. + nullopt, // Dependencies alternatives. + nullopt, // Package skeleton. + nullopt, // Postponed dependency alternatives. + false, // Recursive collection. + nullopt, // Hold package. + nullopt, // Hold version. + {}, // Constraints. + false, // System. + false, // Keep output directory. + false, // Disfigure (from-scratch reconf). + false, // Configure-only. + 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 ())), + false, // Required by dependents. + build_package::build_reevaluate}; // Note: not recursive. // - collect_build (o, - move (p), - fdb, - rpt_depts, - apc, - false /* initial_collection */, - replaced_vers, - postponed_cfgs); + collect_build (o, move (p), replaced_vers, postponed_cfgs); build_package* b (entered_build (pk)); assert (b != nullptr); @@ -4794,31 +4918,23 @@ namespace bpkg build_package_refs dep_chain; collect_build_prerequisites (o, *b, + dep_chain, + false /* initial_collection */, fdb, - rpt_depts, apc, - false /* initial_collection */, + rpt_depts, replaced_vers, - dep_chain, &postponed_repo, &postponed_alts, numeric_limits<size_t>::max (), + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs, - postponed_poss, unacceptable_alts, ed.dependency_position); ed.reevaluated = true; - - if (pi != postponed_poss.end ()) - { - // Otherwise we should have thrown skip_configuration above. - // - assert (di <= pi->second.first); - - pi->second.reevaluated = true; - } } } } @@ -5018,18 +5134,19 @@ namespace bpkg build_package_refs dep_chain; collect_build_prerequisites (o, *b, + dep_chain, + false /* initial_collection */, fdb, - rpt_depts, apc, - false /* initial_collection */, + rpt_depts, replaced_vers, - dep_chain, &postponed_repo, &postponed_alts, 0 /* max_alt_index */, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs, - postponed_poss, unacceptable_alts); // Unless the dependency is already being reconfigured, reconfigure @@ -5154,18 +5271,19 @@ namespace bpkg collect_build_prerequisites (o, *b, + dep_chain, + false /* initial_collection */, fdb, - rpt_depts, apc, - false /* initial_collection */, + rpt_depts, replaced_vers, - dep_chain, &postponed_repo, &postponed_alts, 0 /* max_alt_index */, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs, - postponed_poss, unacceptable_alts); } @@ -5183,16 +5301,70 @@ namespace bpkg // vector<build_package*> spas; // Reuse. - for (bool prog (!postponed_repo.empty () || - !postponed_cfgs.negotiated () || - !postponed_alts.empty () || + for (bool prog (find_if (postponed_recs.begin (), postponed_recs.end (), + [] (const build_package* p) + { + return !p->recursive_collection; + }) != postponed_recs.end () || + !postponed_repo.empty () || + !postponed_cfgs.negotiated () || + !postponed_alts.empty () || postponed_deps.has_bogus ()); prog; ) { + // First, recursively recollect the not yet collected packages (deviated + // existing dependents, etc). + // + prog = false; + + postponed_packages pcs; + for (build_package* p: postponed_recs) + { + if (!p->recursive_collection) + { + build_package_refs dep_chain; + collect_build_prerequisites (o, + *p, + dep_chain, + false /* initial_collection */, + fdb, + apc, + rpt_depts, + replaced_vers, + &postponed_repo, + &postponed_alts, + 0 /* max_alt_index */, + pcs, + postponed_edeps, + postponed_deps, + postponed_cfgs, + unacceptable_alts); + + // Note that the existing dependent collection can be postponed + // due to it's own existing dependents. + // + if (p->recursive_collection) + prog = true; + } + } + + // Scheduling new packages for re-collection is also a progress. + // + if (!prog) + prog = !pcs.empty (); + + if (prog) + { + postponed_recs.insert (pcs.begin (), pcs.end ()); + continue; + } + postponed_packages prs; postponed_packages pas; - // Try to collect the repository-related postponments first. + // Now, as there is no more progress made in recollecting of the not yet + // collected packages, try to collect the repository-related + // postponments. // for (build_package* p: postponed_repo) { @@ -5203,18 +5375,19 @@ namespace bpkg collect_build_prerequisites (o, *p, + dep_chain, + false /* initial_collection */, fdb, - rpt_depts, apc, - false /* initial_collection */, + rpt_depts, replaced_vers, - dep_chain, &prs, &pas, 0 /* max_alt_index */, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs, - postponed_poss, unacceptable_alts); } @@ -5265,6 +5438,8 @@ namespace bpkg snapshot s (*this, postponed_repo, postponed_alts, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs); @@ -5274,10 +5449,11 @@ namespace bpkg replaced_vers, postponed_repo, postponed_alts, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs, postponed_cfgs_history, - postponed_poss, unacceptable_alts, fdb, rpt_depts, @@ -5296,72 +5472,6 @@ namespace bpkg return; } - catch (skip_configuration& e) - { - // Restore the state from snapshot. - // - // Note: postponed_cfgs is re-assigned. - // - s.restore (*this, - postponed_repo, - postponed_alts, - postponed_deps, - postponed_cfgs); - - pc = &postponed_cfgs[ci]; - - // Note that in this case we keep the accumulated configuration, - // if any. - - pc->depth = 0; // Mark as non-negotiated. - - // If requested, "replace" the "later" dependent-dependency - // cluster with an earlier. - // - if (e.dependent) - { - existing_dependent& ed (*e.dependent); - pair<size_t, size_t> pos (e.new_position); - - const build_package* bp ( - replace_existing_dependent_dependency ( - trace, - o, - ed, // Note: modified. - pos, - fdb, - rpt_depts, - apc, - false /* initial_collection */, - replaced_vers, - postponed_cfgs)); - - // Can this dependency already belong to some configuration - // cluster? It feels like potentially it can. However, if it - // does then this cluster cannot be current (we would throw - // postpone_position) nor (being) negotiated (the dependent - // would have already been re-evaluated). Thus, if the - // dependency already belongs to some cluster we assume that - // this existing dependent will naturally be reevaluated up to - // this dependency later when their cluster is negotiated. - // Otherwise, we just create such a cluster. - // - package_key dep (bp->db, bp->selected->name); - - const postponed_configuration* cfg ( - postponed_cfgs.find_dependency (dep)); - - if (cfg == nullptr) - postponed_cfgs.add ( - package_key (ed.db, ed.selected->name), pos, move (dep)); - else - assert (cfg != pc && !cfg->negotiated); - } - - l5 ([&]{trace << "postpone cfg-negotiation of " << *pc;}); - - break; - } catch (const retry_configuration& e) { // If this is not "our problem", then keep looking. @@ -5379,6 +5489,8 @@ namespace bpkg s.restore (*this, postponed_repo, postponed_alts, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs); @@ -5425,6 +5537,8 @@ namespace bpkg s.restore (*this, postponed_repo, postponed_alts, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs); @@ -5568,18 +5682,19 @@ namespace bpkg collect_build_prerequisites (o, *p, + dep_chain, + false /* initial_collection */, fdb, - rpt_depts, apc, - false /* initial_collection */, + rpt_depts, replaced_vers, - dep_chain, &prs, &pas, i, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs, - postponed_poss, unacceptable_alts); prog = (pas.find (p) == pas.end () || @@ -5600,7 +5715,7 @@ namespace bpkg // but producing new repository-related postponements is progress // nevertheless. // - // Note that we don't need to check for new configuration- related + // Note that we don't need to check for new configuration-related // postponements here since if they are present, then this package // wouldn't be in pas and so prog would be true (see above for // details). @@ -5619,40 +5734,6 @@ namespace bpkg assert (!prog); - // If we still have any non-negotiated clusters and non-replace - // postponed positions, then it's possible one of them is the cross- - // dependent pathological case where we will never hit it unless we - // force the re-evaluation to earlier position (similar to the - // single-dependent case, which we handle accurately). For example: - // - // tex: depends: libbar(c) - // depends: libfoo(c) - // - // tix: depends: libbar(c) - // depends: tex(c) - // - // Here tex and tix are existing dependent and we are upgrading tex. - // - // While it would be ideal to handle such cases accurately, it's not - // trivial. So for now we resort to the following heuristics: when left - // with no other option, we treat the first encountered non- replace - // position as replace and see if that helps move things forward. - // - if (!postponed_cfgs.negotiated () && - find_if (postponed_poss.begin (), postponed_poss.end (), - [] (const auto& v) {return !v.second.replace;}) != - postponed_poss.end () && - !postponed_poss.replace) - { - l5 ([&]{trace << "non-negotiated clusters left and non-replace " - << "postponed positions are present, overriding first " - << "encountered non-replace position to replace";}); - - postponed_poss.replace = true; - prog = true; - continue; // Go back to negotiating skipped cluster. - } - // Finally, erase the bogus postponements and re-collect from scratch, // if any (see postponed_dependencies for details). // @@ -5805,18 +5886,19 @@ namespace bpkg collect_build_prerequisites (o, **postponed_repo.begin (), + dep_chain, + false /* initial_collection */, fdb, - rpt_depts, apc, - false /* initial_collection */, + rpt_depts, replaced_vers, - dep_chain, nullptr, nullptr, 0, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs, - postponed_poss, unacceptable_alts); assert (false); // Can't be here. @@ -5828,18 +5910,19 @@ namespace bpkg collect_build_prerequisites (o, **postponed_alts.begin (), + dep_chain, + false /* initial_collection */, fdb, - rpt_depts, apc, - false /* initial_collection */, + rpt_depts, replaced_vers, - dep_chain, nullptr, nullptr, 0, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs, - postponed_poss, unacceptable_alts); assert (false); // Can't be here. @@ -6193,16 +6276,15 @@ namespace bpkg vector<build_packages::existing_dependent> build_packages:: query_existing_dependents ( tracer& trace, + const pkg_build_options& o, database& db, const package_name& name, - const replaced_versions& replaced_vers, + const function<find_database_function>& fdb, const repointed_dependents& rpt_depts, - const function<verify_dependent_build_function>& vdb) + const replaced_versions& replaced_vers) { vector<existing_dependent> r; - lazy_shared_ptr<selected_package> sp (db, name); - // Lazily search for the dependency build and detect if it is being // up/downgraded. Note that we will only do that if the dependency has an // existing dependent which imposes a version constraint on this @@ -6215,106 +6297,214 @@ namespace bpkg { for (auto& pd: query_dependents (ddb, name, db)) { - shared_ptr<selected_package> dsp ( - ddb.load<selected_package> (pd.name)); - - auto i (dsp->prerequisites.find (sp)); - assert (i != dsp->prerequisites.end ()); + package_key pk (ddb, pd.name); - const auto& pos (i->second.config_position); + // Ignore repointed dependents. + // + if (rpt_depts.find (pk) != rpt_depts.end ()) + { + l5 ([&]{trace << "skip repointed existing dependent " << pk + << " of dependency " << name << db;}); + continue; + } - if (pos.first != 0) // Has config clause? + // Ignore dependent which is expected to be built or dropped. + // + auto vi (replaced_vers.find (pk)); + if (vi != replaced_vers.end () && !vi->second.replaced) { - package_key pk (ddb, pd.name); + bool build (vi->second.available != nullptr); + + l5 ([&]{trace << "skip expected to be " + << (build ? "built" : "dropped") + << " existing dependent " << pk + << " of dependency " << name << db;}); + + continue; + } + + // Ignore dependent which is already being built or dropped. + // + const build_package* p (entered_build (pk)); - if (rpt_depts.find (pk) != rpt_depts.end ()) + if (p != nullptr && p->action) + { + bool build; + if (((build = *p->action == build_package::build) && + (p->system || p->recollect_recursively (rpt_depts))) || + *p->action == build_package::drop) { - l5 ([&]{trace << "skip repointed existing dependent " << pk + l5 ([&]{trace << "skip being " + << (build ? "built" : "dropped") + << " existing dependent " << pk << " of dependency " << name << db;}); continue; } + } - // Ignore dependent which is already being built or dropped. + // Ignore dependent if this dependency up/downgrade won't satisfy the + // dependent's constraint. The thinking here is that we will either + // fail for this reason later or the problem will be resolved + // naturally due to the execution plan refinement (see + // unsatisfied_dependents for details). + // + if (pd.constraint) + { + // Search for the dependency build and detect if it is being + // up/downgraded, if not done yet. In particular, the available + // package could be NULL meaning we are just adjusting. // - const build_package* p (entered_build (pk)); - - if (p != nullptr && p->action) + if (dep == nullptr) { - bool build; - if (((build = *p->action == build_package::build) && - (p->system || p->recollect_recursively (rpt_depts))) || - *p->action == build_package::drop) + dep = entered_build (db, name); + + assert (dep != nullptr); // Expected to be being built. + + if (dep->available != nullptr) { - if (!build || !vdb || !vdb (pk, pos)) - { - l5 ([&]{trace << "skip being " - << (build ? "built" : "dropped") - << " existing dependent " << pk - << " of dependency " << name << db;}); - continue; - } + const shared_ptr<selected_package>& sp (dep->selected); + + // Expected to be selected since it has an existing dependent. + // + assert (sp != nullptr); + + ud = sp->version.compare (dep->available_version ()); } } - // Ignore dependent which is expected to be built or dropped. - // - auto vi (replaced_vers.find (pk)); - if (vi != replaced_vers.end () && !vi->second.replaced) + if (ud != 0 && + !satisfies (dep->available_version (), *pd.constraint)) { - bool build (vi->second.available != nullptr); - - l5 ([&]{trace << "skip expected to be " - << (build ? "built" : "dropped") - << " existing dependent " << pk - << " of dependency " << name << db;}); + l5 ([&]{trace << "skip unsatisfied existing dependent " << pk + << " of dependency " + << dep->available_name_version_db () << " due to " + << "constraint (" << name << ' ' << *pd.constraint + << ')';}); continue; } + } + + // Pre-reevaluate the dependent to calculate the position which the + // dependent should be re-evaluated to. + // + shared_ptr<selected_package> dsp ( + ddb.load<selected_package> (pd.name)); + + pair<shared_ptr<available_package>, + lazy_shared_ptr<repository_fragment>> rp ( + find_available_fragment (o, ddb, dsp)); + + try + { + build_package p { + build_package::build, + ddb, + dsp, // Don't move from since will be used later. + move (rp.first), + move (rp.second), + nullopt, // Dependencies. + nullopt, // Dependencies alternatives. + nullopt, // Package skeleton. + nullopt, // Postponed dependency alternatives. + false, // Recursive collection. + nullopt, // Hold package. + nullopt, // Hold version. + {}, // Constraints. + false, // System. + false, // Keep output directory. + false, // Disfigure (from-scratch reconf). + false, // Configure-only. + nullopt, // Checkout root. + false, // Checkout purge. + strings (), // Configuration variables. + {}, // Required by (dependency). + false, // Required by dependents. + 0}; // State flags. - // Ignore dependent if this dependency up/downgrade won't satisfy - // the dependent's constraint. The thinking here is that we will - // either fail for this reason later or the problem will be resolved - // naturally due to the execution plan refinement (see - // unsatisfied_dependents for details). + build_package_refs dep_chain; + postponed_packages postponed_repo; + postponed_packages postponed_alts; + postponed_packages postponed_recs; + postponed_existing_dependencies postponed_edeps; + postponed_dependencies postponed_deps; + postponed_configurations postponed_cfgs; + unacceptable_alternatives unacceptable_alts; + replaced_versions replaced_vers; + + // Note: the initial_collection value is meaningless since we don't + // perform the actual prerequisites collection in the + // pre-reevaluation mode. // - if (pd.constraint) - { - // Search for the dependency build and detect if it is being - // up/downgraded, if not done yet. In particular, the available - // package could be NULL meaning we are just adjusting. - // - if (dep == nullptr) - { - dep = entered_build (db, name); + optional<vector<postponed_configuration::dependency>> deps ( + collect_build_prerequisites (o, + p, + dep_chain, + false /* initial_collection */, + fdb, + nullptr /* add_priv_cfg_function */, + rpt_depts, + replaced_vers, + &postponed_repo, + &postponed_alts, + numeric_limits<size_t>::max (), + postponed_recs, + postponed_edeps, + postponed_deps, + postponed_cfgs, + unacceptable_alts, + pair<size_t, size_t> (0, 0))); - assert (dep != nullptr); // Expected to be being built. + // Must be read-only. + // + assert (postponed_repo.empty () && + postponed_alts.empty () && + postponed_recs.empty () && + postponed_edeps.empty () && + postponed_deps.empty () && + postponed_cfgs.empty () && + unacceptable_alts.empty () && + replaced_vers.empty ()); + + if (deps) + { + package_key pk {db, name}; - if (dep->available != nullptr) - { - const shared_ptr<selected_package>& sp (dep->selected); + assert (!deps->empty ()); - // Expected to be selected since it has an existing dependent. - // - assert (sp != nullptr); + // Try to retrieve the original dependency position. If we fail, + // then this dependency belongs to the depends clause which comes + // after the re-evaluation target position. + // + optional<pair<size_t, size_t>> odp; - ud = sp->version.compare (dep->available_version ()); + for (const postponed_configuration::dependency& d: *deps) + { + if (find (d.begin (), d.end (), pk) != d.end ()) + { + odp = d.position; + break; } } - if (ud != 0 && - !satisfies (dep->available_version (), *pd.constraint)) - { - l5 ([&]{trace << "skip unsatisfied existing dependent " << pk - << " of dependency " - << dep->available_name_version_db () << " due to " - << "constraint (" << name << ' ' << *pd.constraint - << ')';}); + // Try to preserve the name of the original dependency as the one + // which brings the existing dependent to the config cluster. + // Failed that, use the first dependency in the alternative which + // we will be re-evaluating to. + // + postponed_configuration::dependency& d (deps->back ()); - continue; - } - } + if (find (d.begin (), d.end (), pk) == d.end ()) + pk = move (d.front ()); - r.push_back (existing_dependent {ddb, move (dsp), pos}); + r.push_back ( + existing_dependent {ddb, move (dsp), move (pk), d.position, odp}); + } + } + catch (const reeval_deviated&) + { + r.push_back ( + existing_dependent {ddb, move (dsp), nullopt, {}, nullopt}); } } } @@ -6323,73 +6513,32 @@ namespace bpkg } const build_package* build_packages:: - replace_existing_dependent_dependency ( - tracer& trace, + collect_existing_dependent_dependency ( const pkg_build_options& o, - existing_dependent& ed, - pair<size_t, size_t> pos, - const function<find_database_function>& fdb, - const repointed_dependents& rpt_depts, - const function<add_priv_cfg_function>& apc, - bool initial_collection, + const existing_dependent& ed, replaced_versions& replaced_vers, postponed_configurations& postponed_cfgs) { - // The repointed dependent cannot be returned by - // query_existing_dependents(). Note that the repointed dependent - // references both old and new prerequisites. - // - assert (rpt_depts.find (package_key (ed.db, ed.selected->name)) == - rpt_depts.end ()); - - shared_ptr<selected_package> dsp; - database* pdb (nullptr); - const version_constraint* vc (nullptr); - - // Find the dependency for this earlier dependency position. We know it - // must be there since it's with configuration. - // - for (const auto& p: ed.selected->prerequisites) - { - if (p.second.config_position == pos) - { - pdb = &p.first.database (); - - dsp = p.first.load (); - - l5 ([&]{trace << "replace dependency at index " - << ed.dependency_position.first - << " of existing dependent " << *ed.selected - << ed.db << " with dependency " << *dsp - << *pdb << " at index " << pos.first;}); + assert (ed.dependency); // Shouldn't be called for deviated dependents. - if (p.second.constraint) - vc = &*p.second.constraint; - } - } + const shared_ptr<selected_package>& dsp (ed.selected); - assert (dsp != nullptr); + package_key dpt (ed.db, dsp->name); + const package_key& dep (*ed.dependency); - package_key pk (*pdb, dsp->name); + lazy_shared_ptr<selected_package> lsp (dep.db.get (), dep.name); + shared_ptr<selected_package> sp (lsp.load ()); - // Adjust the existing dependent entry. - // - ed.dependency_position = pos; - - // Collect the package build for this dependency. - // pair<shared_ptr<available_package>, lazy_shared_ptr<repository_fragment>> rp ( - find_available_fragment (o, pk.db, dsp)); + find_available_fragment (o, dep.db, sp)); - bool system (dsp->system ()); - - package_key dpk (ed.db, ed.selected->name); + bool system (sp->system ()); build_package p { build_package::build, - pk.db, - move (dsp), + dep.db, + move (sp), move (rp.first), move (rp.second), nullopt, // Dependencies. @@ -6407,25 +6556,71 @@ namespace bpkg nullopt, // Checkout root. false, // Checkout purge. strings (), // Configuration variables. - {dpk}, // Required by (dependent). + {dpt}, // Required by (dependent). true, // Required by dependents. - build_package::adjust_reconfigure}; + 0}; + + // Add constraints, if present. + // + { + auto i (dsp->prerequisites.find (lsp)); + assert (i != dsp->prerequisites.end ()); + + if (i->second.constraint) + p.constraints.emplace_back (dpt.db, + dpt.name.string (), + *i->second.constraint); + } + + // Note: not recursive. + // + collect_build (o, move (p), replaced_vers, postponed_cfgs); - if (vc != nullptr) - p.constraints.emplace_back (dpk.db, dpk.name.string (), *vc); + return entered_build (dep); + } + + void build_packages:: + collect_deviated_dependent (const pkg_build_options& o, + const existing_dependent& ed, + package_key orig_dep, + replaced_versions& replaced_vers, + postponed_packages& postponed_recs, + postponed_configurations& postponed_cfgs) + { + pair<shared_ptr<available_package>, + lazy_shared_ptr<repository_fragment>> rp ( + find_available_fragment (o, ed.db, ed.selected)); + + build_package p { + build_package::build, + ed.db, + ed.selected, + move (rp.first), + move (rp.second), + nullopt, // Dependencies. + nullopt, // Dependencies alternatives. + nullopt, // Package skeleton. + nullopt, // Postponed dependency alternatives. + false, // Recursive collection. + nullopt, // Hold package. + nullopt, // Hold version. + {}, // Constraints. + false, // System. + false, // Keep output directory. + false, // Disfigure (from-scratch reconf). + false, // Configure-only. + nullopt, // Checkout root. + false, // Checkout purge. + strings (), // Configuration variables. + {move (orig_dep)}, // Required by (dependency). + false, // Required by dependents. + build_package::build_recollect}; // Note: not recursive. // - collect_build (o, - move (p), - fdb, - rpt_depts, - apc, - initial_collection, - replaced_vers, - postponed_cfgs); - - return entered_build (pk); + collect_build (o, move (p), replaced_vers, postponed_cfgs); + + postponed_recs.insert (entered_build (ed.db, ed.selected->name)); } build_packages::iterator build_packages:: diff --git a/bpkg/pkg-build-collect.hxx b/bpkg/pkg-build-collect.hxx index 1764b3a..a91d2df 100644 --- a/bpkg/pkg-build-collect.hxx +++ b/bpkg/pkg-build-collect.hxx @@ -297,7 +297,9 @@ namespace bpkg // This is required if it is being built as a source package and needs to // be up/down-graded and/or reconfigured and has some buildfile clauses, // it is a repointed dependent, or it is already in the process of being - // collected. + // collected. Also configured dependents can be scheduled for recollection + // explicitly (see postponed_packages and build_recollect flag for + // details). // bool recollect_recursively (const repointed_dependents&) const; @@ -345,6 +347,11 @@ namespace bpkg // static const uint16_t build_reevaluate = 0x0008; + // Set if this build action is for recursive re-collecting of a deviated + // existing dependent. + // + static const uint16_t build_recollect = 0x0010; + // Set if this build action is for replacing of an existing package due to // deorphaning or rebuilding as an archive or directory. // @@ -352,7 +359,7 @@ namespace bpkg // repository fragment, archive, or directory (even if its version doesn't // change). // - static const uint16_t build_replace = 0x0010; + static const uint16_t build_replace = 0x0020; bool replace () const @@ -404,7 +411,9 @@ namespace bpkg // package_skeleton& init_skeleton (const common_options&, - const shared_ptr<available_package>& override = nullptr); + const shared_ptr<available_package>& override = nullptr, + optional<dir_path> src_root = nullopt, + optional<dir_path> out_root = nullopt); }; using build_package_list = std::list<reference_wrapper<build_package>>; @@ -415,11 +424,11 @@ namespace bpkg // Packages with postponed prerequisites collection, for one of the // following reasons: // - // - Postponed due to the inability to find a version satisfying the pre- - // entered constraint from repositories available to this package. The - // idea is that this constraint could still be satisfied from a repository - // fragment of some other package (that we haven't processed yet) that - // also depends on this prerequisite. + // - Postponed due to the inability to find a dependency version satisfying + // the pre-entered constraint from repositories available to this + // package. The idea is that this constraint could still be satisfied from + // a repository fragment of some other package (that we haven't processed + // yet) that also depends on this prerequisite. // // - Postponed due to the inability to choose between two dependency // alternatives, both having dependency packages which are not yet @@ -427,6 +436,11 @@ namespace bpkg // ambiguity could still be resolved after some of those dependency // packages get built via some other dependents. // + // - Postponed recollection of configured dependents whose dependencies + // up/downgrade causes selection of different dependency alternatives. + // This, in particular, may end up in resolving different dependency + // packages and affect the dependent and dependency configurations. + // using postponed_packages = std::set<build_package*>; // Base for exception types that indicate an inability to collect a package @@ -529,101 +543,13 @@ namespace bpkg } }; - // Map of existing dependents which may not be re-evaluated to a position - // with the dependency index greater than the specified one. - // - // This mechanism applies when we re-evaluate an existing dependent to a - // certain position but later realize we've gone too far. In this case we - // note the earlier position information and re-collect from scratch. On the - // re-collection any re-evaluation of the dependent to a greater position - // will be either skipped or performed but to this earlier position (see the - // replace member for details). + // Map of the dependencies whose recursive collection is postponed until + // their existing dependents re-collection/re-evaluation to the lists of the + // respective existing dependents (see collect_build_prerequisites() for + // details). // - // We consider the postponement bogus if some dependent re-evaluation was - // skipped due to its presence but no re-evaluation to this (or earlier) - // dependency index was performed. Thus, if after the collection of packages - // some bogus entries are present in the map, then it means that we have - // skipped the respective re-evaluations erroneously and so need to erase - // these entries and re-collect. - // - // Note that if no re-evaluation is skipped due to a postponement then it - // is harmless and we don't consider it bogus. - // - struct postponed_position: pair<size_t, size_t> - { - // True if the "later" position should be replaced rather than merely - // skipped. The replacement deals with the case where the "earlier" - // position is encountered while processing the same cluster as what - // contains the later position. In this case, if we merely skip, then we - // will never naturally encounter the earlier position. So we have to - // force the issue (even if things change enough for us to never see the - // later position again). - // - bool replace; - - // Re-evaluation was skipped due to this postponement. - // - bool skipped = false; - - // The dependent was re-evaluated. Note that it can be only re-evaluated - // to this or earlier dependency index. - // - bool reevaluated = false; - - postponed_position (pair<size_t, size_t> p, bool r) - : pair<size_t, size_t> (p), replace (r) {} - }; - - class postponed_positions: public std::map<package_key, postponed_position> - { - public: - // If true, override the first encountered non-replace position to replace - // and clear this flag. See collect_build_postponed() for details. - // - bool replace = false; - - // Erase the bogus postponements and throw cancel_postponement, if any. - // - struct cancel_postponement: scratch_collection - { - cancel_postponement () - : scratch_collection ("bogus existing dependent re-evaluation " - "postponement cancellation") {} - }; - - void - cancel_bogus (tracer& trace) - { - bool bogus (false); - for (auto i (begin ()); i != end (); ) - { - const postponed_position& p (i->second); - - if (p.skipped && !p.reevaluated) - { - bogus = true; - - l5 ([&]{trace << "erase bogus existing dependent " << i->first - << " re-evaluation postponement with dependency index " - << i->second.first;}); - - // It seems that the replacement may never be bogus. - // - assert (!p.replace); - - i = erase (i); - } - else - ++i; - } - - if (bogus) - { - l5 ([&]{trace << "bogus re-evaluation postponement erased, throwing";}); - throw cancel_postponement (); - } - } - }; + using postponed_existing_dependencies = std::map<package_key, + vector<package_key>>; // Set of dependency alternatives which were found unacceptable by the // configuration negotiation machinery and need to be ignored on re- @@ -922,6 +848,10 @@ namespace bpkg // The depth of the negotiating recursion (see collect_build_postponed() // for details). // + // Note that non-zero depth for an absent negotiated member indicates that + // the cluster is in the existing dependents re-evaluation or + // configuration refinment phases. + // size_t depth = 0; // Add dependencies of a new dependent. @@ -990,12 +920,6 @@ namespace bpkg bool contains_dependency (const postponed_configuration&) const; - // If the configuration contains the specified existing dependent, then - // return the earliest dependency position. Otherwise return NULL. - // - const pair<size_t, size_t>* - existing_dependent_position (const package_key&) const; - // Notes: // // - Adds dependencies of the being merged from configuration to the end @@ -1206,21 +1130,23 @@ namespace bpkg build_package* collect_build (const pkg_build_options&, build_package, - const function<find_database_function>&, - const repointed_dependents&, - const function<add_priv_cfg_function>&, - bool initial_collection, replaced_versions&, postponed_configurations&, build_package_refs* dep_chain = nullptr, + bool initial_collection = false, + const function<find_database_function>& = nullptr, + const function<add_priv_cfg_function>& = nullptr, + const repointed_dependents* = nullptr, postponed_packages* postponed_repo = nullptr, postponed_packages* postponed_alts = nullptr, + postponed_packages* postponed_recs = nullptr, + postponed_existing_dependencies* = nullptr, postponed_dependencies* = nullptr, - postponed_positions* = nullptr, unacceptable_alternatives* = nullptr, const function<verify_package_build_function>& = nullptr); - // Collect prerequisites of the package being built recursively. + // Collect prerequisites of the package being built recursively. Return + // nullopt, unless in the pre-reevaluation mode (see below). // // But first "prune" this process if the package we build is a system one // or is already configured, since that would mean all its prerequisites @@ -1244,7 +1170,16 @@ namespace bpkg // recursively. // // - For an existing dependent being re-evaluated to the specific - // dependency position. + // dependency position (reeval_pos argument is specified and is not + // {0,0}). + // + // - For an existing dependent being pre-reevaluated (reeval_pos argument + // is {0,0}). + // + // - For an existing dependent being re-collected due to the selected + // dependency alternatives deviation, which may be caused by its + // dependency up/downgrade (see postponed prerequisites collection for + // details). // // Note that for these cases, as it was said above, we can potentially // fail if the dependent is an orphan, but this is exactly what we need to @@ -1279,16 +1214,44 @@ namespace bpkg // be performed. See the collect lambda implementation for details on the // configuration refinement machinery. // - // If the package is a dependency of a configured dependent with - // configuration clause and needs to be reconfigured (being upgraded, has - // configuration specified, etc), then postpone its recursive collection - // by recording it in postponed_cfgs as a single-dependency cluster with - // an existing dependent (see postponed_configurations for details). If - // this dependent already belongs to some (being) negotiated configuration - // cluster with a greater dependency position then record this dependency - // position in postponed_poss and throw postpone_position. This exception - // is handled by re-collecting packages from scratch, but now with the - // knowledge about position this dependent needs to be re-evaluated to. + // If {0,0} is specified as the reeval_pos argument, then perform the + // pre-reevaluation. In this read-only mode perform the regular dependency + // alternative selection but not the actual dependency collection and stop + // when all the depends clauses are processed or an alternative with the + // configuration clause is encountered. In the latter case return the list + // of the selected alternative dependencies/positions, where the last + // entry corresponds to the alternative with the encountered configuration + // clause. Return nullopt otherwise. Also lock for any deviation in the + // dependency alternatives selection and throw reeval_deviated exception + // if such a deviation is detected. + // + // If the package is a dependency of configured dependents and needs to be + // reconfigured (being upgraded, has configuration specified, etc), then + // do the following for each such dependent prior to collecting its own + // prerequisites: + // + // - If the dependent is not already being built/dropped, expected to be + // built/dropped, and doesn't apply constraints which the dependency + // doesn't satisfy anymore, then pre-reevaluate the dependent. + // + // - If the dependency alternative with configuration clause has been + // encountered during the pre-reevaluation, then record it in + // postponed_cfgs as a single-dependency cluster with an existing + // dependent (see postponed_configurations for details). If the index of + // the encountered depends clause is equal/less than the index of the + // depends clause the dependency belongs to, then postpone the recursive + // collection of this dependency assuming that it will be collected + // later, during/after its existing dependent re-evaluation. + // + // - If the dependency alternatives selection has deviated, then record + // the dependent in postponed_recs (so that it can be re-collected + // later) and postpone recursive collection of this dependency assuming + // that it will be collected later, during its existing dependent + // re-collection. Also record this dependency in the postponed existing + // dependencies map (postponed_existing_dependencies argument). This way + // the caller can track if the postponed dependencies have never been + // collected recursively (deviations are too large, etc) and handle this + // situation (currently just fail). // // If a dependency alternative configuration cannot be negotiated between // all the dependents, then unaccept_alternative can be thrown (see @@ -1307,12 +1270,6 @@ namespace bpkg } }; - struct postpone_position: scratch_collection - { - postpone_position () - : scratch_collection ("earlier dependency position") {} - }; - struct retry_configuration { size_t depth; @@ -1324,40 +1281,43 @@ namespace bpkg size_t depth; }; - void + struct reeval_deviated {}; + + optional<vector<postponed_configuration::dependency>> collect_build_prerequisites (const pkg_build_options&, build_package&, + build_package_refs& dep_chain, + bool initial_collection, const function<find_database_function>&, - const repointed_dependents&, const function<add_priv_cfg_function>&, - bool initial_collection, + const repointed_dependents&, replaced_versions&, - build_package_refs& dep_chain, postponed_packages* postponed_repo, postponed_packages* postponed_alts, size_t max_alt_index, + postponed_packages& postponed_recs, + postponed_existing_dependencies&, postponed_dependencies&, postponed_configurations&, - postponed_positions&, unacceptable_alternatives&, - pair<size_t, size_t> reeval_pos = - make_pair(0, 0)); + optional<pair<size_t, size_t>> reeval_pos = nullopt); void collect_build_prerequisites (const pkg_build_options&, database&, const package_name&, + bool initial_collection, const function<find_database_function>&, - const repointed_dependents&, const function<add_priv_cfg_function>&, - bool initial_collection, + const repointed_dependents&, replaced_versions&, postponed_packages& postponed_repo, postponed_packages& postponed_alts, size_t max_alt_index, + postponed_packages& postponed_recs, + postponed_existing_dependencies&, postponed_dependencies&, postponed_configurations&, - postponed_positions&, unacceptable_alternatives&); // Collect the repointed dependents and their replaced prerequisites, @@ -1374,9 +1334,10 @@ namespace bpkg replaced_versions&, postponed_packages& postponed_repo, postponed_packages& postponed_alts, + postponed_packages& postponed_recs, + postponed_existing_dependencies&, postponed_dependencies&, postponed_configurations&, - postponed_positions&, unacceptable_alternatives&, const function<find_database_function>&, const function<add_priv_cfg_function>&); @@ -1403,10 +1364,11 @@ namespace bpkg replaced_versions&, postponed_packages& postponed_repo, postponed_packages& postponed_alts, + postponed_packages& postponed_recs, + postponed_existing_dependencies&, postponed_dependencies&, postponed_configurations&, strings& postponed_cfgs_history, - postponed_positions&, unacceptable_alternatives&, const function<find_database_function>&, const repointed_dependents&, @@ -1469,54 +1431,64 @@ namespace bpkg private: // Return the list of existing dependents that has a configuration clause - // for the specified dependency. Skip dependents which are being built and - // require recursive recollection or dropped (present in the map) or - // expected to be built or dropped (present in rpt_depts or + // for any of the selected alternatives together with the dependencies for + // the earliest such an alternative and the original dependency (for which + // the function is called for) position. Return absent dependency for + // those dependents which dependency alternatives selection has deviated + // (normally due to the dependency up/downgrade). Skip dependents which + // are being built and require recursive recollection or dropped (present + // in the map) or expected to be built or dropped (present in rpt_depts or // replaced_vers). Also skip dependents which impose the version // constraint on this dependency and the dependency doesn't satisfy this // constraint. // - // Optionally, specify the function which can verify the dependent build - // and decide whether to override the default behavior and still add the - // dependent package to the resulting list, returning true in this case. - // struct existing_dependent { - reference_wrapper<database> db; - shared_ptr<selected_package> selected; - pair<size_t, size_t> dependency_position; - }; + // Dependent. + // + reference_wrapper<database> db; + shared_ptr<selected_package> selected; - using verify_dependent_build_function = bool (const package_key&, - pair<size_t, size_t>); + // Dependency. + // + optional<package_key> dependency; + pair<size_t, size_t> dependency_position; + optional<pair<size_t, size_t>> orig_dependency_position; + }; vector<existing_dependent> query_existing_dependents ( tracer&, + const pkg_build_options&, database&, const package_name&, - const replaced_versions&, + const function<find_database_function>&, const repointed_dependents&, - const function<verify_dependent_build_function>& = nullptr); + const replaced_versions&); - // Update the existing dependent object (previously obtained with the - // query_existing_dependents() call) with the new dependency position and - // collect the dependency referred by this position. Return the pointer to - // the collected build package object. + // Non-recursively collect the dependency of an existing dependent + // previously returned by the query_existing_dependents() function call + // with the build_package::build_reevaluate flag. // const build_package* - replace_existing_dependent_dependency ( - tracer&, + collect_existing_dependent_dependency ( const pkg_build_options&, - existing_dependent&, - pair<size_t, size_t>, - const function<find_database_function>&, - const repointed_dependents&, - const function<add_priv_cfg_function>&, - bool initial_collection, + const existing_dependent&, replaced_versions&, postponed_configurations&); + // Non-recursively collect the deviated existing dependent previously + // returned by the query_existing_dependents() function call and add it to + // the postponed package recollections list. + // + void + collect_deviated_dependent (const pkg_build_options&, + const existing_dependent&, + package_key orig_dependency, + replaced_versions&, + postponed_packages& postponed_recs, + postponed_configurations&); + struct package_ref { database& db; @@ -1536,7 +1508,7 @@ namespace bpkg bool reorder); // Skip the dependents collection/ordering for the specified dependency if - // that has already be done. + // that has already been done. // // Note that if this function has already been called for this dependency, // then all its dependents are already in the map and the dependency diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx index 243d713..fa3d762 100644 --- a/bpkg/pkg-build.cxx +++ b/bpkg/pkg-build.cxx @@ -1697,7 +1697,7 @@ namespace bpkg // will modify the cached instance, which means our list will always "see" // their updated state. // - // Also note that rep_fetch() must be called in session. + // Also note that rep_fetch() and pkg_fetch() must be called in session. // session ses; @@ -3891,7 +3891,6 @@ namespace bpkg replaced_versions replaced_vers; postponed_dependencies postponed_deps; - postponed_positions postponed_poss; unacceptable_alternatives unacceptable_alts; // Map the repointed dependents to the replacement flags (see @@ -3959,12 +3958,12 @@ namespace bpkg // during the package collection) because we want to enter them before // collect_build_postponed() and they could be the dependents that have // the config clauses. In a sense, change to replaced_vers, - // postponed_deps, or postponed_poss maps should not affect the deps + // postponed_deps, or unacceptable_alts maps should not affect the deps // list. But not the other way around: a dependency erased from the deps // list could have caused an entry in the replaced_vers, postponed_deps, - // and/or postponed_poss maps. And so we clean replaced_vers, - // postponed_deps, and postponed_poss on scratch_exe (scratch during the - // plan execution). + // and/or unacceptable_alts maps. And so we clean replaced_vers, + // postponed_deps, and unacceptable_alts on scratch_exe (scratch during + // the plan execution). // for (bool refine (true), scratch_exe (true), scratch_col (false); refine; ) @@ -4172,11 +4171,13 @@ namespace bpkg } }); - postponed_packages postponed_repo; - postponed_packages postponed_alts; - postponed_configurations postponed_cfgs; - strings postponed_cfgs_history; - unsatisfied_dependents unsatisfied_depts; + postponed_packages postponed_repo; + postponed_packages postponed_alts; + postponed_packages postponed_recs; + postponed_existing_dependencies postponed_edeps; + postponed_configurations postponed_cfgs; + strings postponed_cfgs_history; + unsatisfied_dependents unsatisfied_depts; try { @@ -4188,7 +4189,6 @@ namespace bpkg { replaced_vers.clear (); postponed_deps.clear (); - postponed_poss.clear (); unacceptable_alts.clear (); scratch_exe = false; @@ -4206,12 +4206,6 @@ namespace bpkg pd.second.with_config = false; } - for (auto& pd: postponed_poss) - { - pd.second.skipped = false; - pd.second.reevaluated = false; - } - scratch_col = false; } @@ -4244,14 +4238,7 @@ namespace bpkg // specify packages on the command line does not matter). // for (const build_package& p: hold_pkgs) - pkgs.collect_build (o, - p, - find_prereq_database, - rpt_depts, - add_priv_cfg, - true /* initial_collection */, - replaced_vers, - postponed_cfgs); + pkgs.collect_build (o, p, replaced_vers, postponed_cfgs); // Collect all the prerequisites of the user selection. // @@ -4270,17 +4257,18 @@ namespace bpkg o, p.db, p.name (), + true /* initial_collection */, find_prereq_database, - rpt_depts, add_priv_cfg, - true /* initial_collection */, + rpt_depts, replaced_vers, postponed_repo, postponed_alts, 0 /* max_alt_index */, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs, - postponed_poss, unacceptable_alts); } else @@ -4332,9 +4320,10 @@ namespace bpkg replaced_vers, postponed_repo, postponed_alts, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs, - postponed_poss, unacceptable_alts, find_prereq_database, add_priv_cfg); @@ -4361,6 +4350,11 @@ namespace bpkg } else { + // Wouldn't be here otherwise. + // + assert (postponed_deps.find (package_key {ddb, d.name}) == + postponed_deps.end ()); + shared_ptr<selected_package> sp ( ddb.find<selected_package> (d.name)); @@ -4408,17 +4402,18 @@ namespace bpkg // pkgs.collect_build (o, move (p), - find_prereq_database, - rpt_depts, - add_priv_cfg, - true /* initial_collection */, replaced_vers, postponed_cfgs, &dep_chain, + true /* initial_collection */, + find_prereq_database, + add_priv_cfg, + &rpt_depts, &postponed_repo, &postponed_alts, + &postponed_recs, + &postponed_edeps, &postponed_deps, - &postponed_poss, &unacceptable_alts); } } @@ -4446,18 +4441,24 @@ namespace bpkg // Handle the (combined) postponed collection. // - if (!postponed_repo.empty () || - !postponed_alts.empty () || - postponed_deps.has_bogus () || + if (find_if (postponed_recs.begin (), postponed_recs.end (), + [] (const build_package* p) + { + return !p->recursive_collection; + }) != postponed_recs.end () || + !postponed_repo.empty () || + !postponed_alts.empty () || + postponed_deps.has_bogus () || !postponed_cfgs.empty ()) pkgs.collect_build_postponed (o, replaced_vers, postponed_repo, postponed_alts, + postponed_recs, + postponed_edeps, postponed_deps, postponed_cfgs, postponed_cfgs_history, - postponed_poss, unacceptable_alts, find_prereq_database, rpt_depts, @@ -4467,12 +4468,6 @@ namespace bpkg // (see replaced_versions for details). // replaced_vers.cancel_bogus (trace, true /* scratch */); - - // Erase the bogus existing dependent re-evaluation postponements - // and re-collect from scratch, if any (see postponed_positions for - // details). - // - postponed_poss.cancel_bogus (trace); } catch (const scratch_collection& e) { @@ -4552,6 +4547,16 @@ namespace bpkg } } + for (build_package* p: postponed_recs) + { + assert (p->recursive_collection); + + pkgs.order (p->db, + p->name (), + nullopt /* buildtime */, + find_prereq_database); + } + // Collect and order all the dependents that we will need to // reconfigure because of the up/down-grades of packages that are now // on the list. @@ -4589,6 +4594,32 @@ namespace bpkg } } + // Make sure all the postponed dependencies of existing dependents + // have been collected and fail if that's not the case. + // + for (const auto& pd: postponed_edeps) + { + const build_package* p (pkgs.entered_build (pd.first)); + assert (p != nullptr && p->available != nullptr); + + if (!p->recursive_collection) + { + // Feels like this shouldn't happen but who knows. + // + diag_record dr (fail); + dr << "package " << p->available_name_version_db () << " is not " + << "built due to its configured dependents deviation in " + << "dependency resolution" << + info << "deviated dependents:"; + + for (const package_key& d: pd.second) + dr << ' ' << d; + + dr << info << "please report in " + << "https://github.com/build2/build2/issues/302"; + } + } + #ifndef NDEBUG pkgs.verify_ordering (); #endif @@ -4959,10 +4990,10 @@ namespace bpkg // that the build-time dependency configuration type (host or // build2) differs from the dependent configuration type (target // is a common case) and doesn't work well, for example, for the - // self-hosted configurations. For them it can fail - // erroneously. We can potentially fix that by additionally - // storing the build-time flag for a prerequisite. However, let's - // first see if it ever becomes a problem. + // self-hosted configurations. For them it can fail erroneously. + // We can potentially fix that by additionally storing the + // build-time flag for a prerequisite. However, let's first see if + // it ever becomes a problem. // prerequisites r; const package_prerequisites& prereqs (sp->prerequisites); @@ -5630,8 +5661,8 @@ namespace bpkg // 1. sys-install not installed system/distribution // 2. disfigure up/down-graded, reconfigured [left to right] // 3. purge up/down-graded [right to left] - // 4.a fetch/unpack new, up/down-graded - // 4.b checkout new, up/down-graded + // 4.a fetch/unpack new, up/down-graded, replaced + // 4.b checkout new, up/down-graded, replaced // 5. configure all // 6. unhold unheld // 7. build user selection [right to left] @@ -5699,13 +5730,14 @@ namespace bpkg database& db (p.db); - // Note: don't update the re-evaluated dependent unless it is - // reconfigured. + // Note: don't update the re-evaluated and re-collected dependents + // unless they are reconfigured. // if ((*p.action == build_package::adjust && p.reconfigure ()) || (*p.action == build_package::build && - ((p.flags & build_package::build_repoint) != 0 || - ((p.flags & build_package::build_reevaluate) != 0 && + ((p.flags & build_package::build_repoint) != 0 || + ((p.flags & (build_package::build_reevaluate | + build_package::build_recollect)) != 0 && p.reconfigure ())))) upkgs.push_back (pkg_command_vars {db.config_orig, !multi_config () && db.main (), diff --git a/bpkg/pkg-configure.cxx b/bpkg/pkg-configure.cxx index 57ac5ac..53c104e 100644 --- a/bpkg/pkg-configure.cxx +++ b/bpkg/pkg-configure.cxx @@ -58,6 +58,7 @@ namespace bpkg tracer_guard tg (db, trace); package_prerequisites prereqs; + vector<size_t> dep_alts; strings vars; // Notes on the buildfile clauses evaluation: @@ -88,46 +89,9 @@ namespace bpkg // on some previous pkg-build run when this package and its dependencies // have been configured. But because of this we may not evaluate the // enable and reflect clauses which refer to dependency configuration - // variables. Thus, for now we fail if such an enable or reflect clause - // is encountered and evaluate all the enable and reflect clauses - // otherwise. In the future it feels like such cases should somehow - // be handled at the pkg-build level (e.g., detect such situations and - // cause the dependent re-evaluation instead of re-configuration). Note - // that if/when this is implemented, the current logic could still be - // used as an optimization (reflection of dependency configuration is - // not very common). - // - // @@ It seems there is a hole in the reconfiguration mode: - // - // foo -> libfoo {prefer {config.libfoo.proto=1} accept(true) - // reflect {config.foo.reflect=1}} | - // libfoo {prefer {config.libfoo.proto=2} accept(true) - // reflect {config.foo.reflect=2}} - // -> libbar {prefer {config.libbar.proto=$config.libfoo.proto} - // accept (config.libbar.proto=2)} - // -> libbaz - // - // foo is configured with config.foo.reflect=2 initially. - // - // If afterwords libbaz is upgraded, the foo is reconfigured with - // config.foo.reflect=1 just because we erroneously pick the first - // libfoo alternative (which has been banned by libbar accept clause - // on the previous pkg-build run during negotiation). - // - // It feels more and more that the proper solution here is to go - // "nuclear" and to always "upgrade" re-configuration for a package - // with any prefer/require into a complete re-evaluation. The most - // likely drawback of this approach would be unnecessary - // re-evaluations if we use the "any prefer/require in any - // alternative" condition. So we may need to exclude some common - // simple cases where such an upgrade is not needed. For example: - // - // foo -> libfoo require {config.libfoo.proto=1} - // foo -> libbar require {config.libbar.proto=1} - // foo -> libbaz - // - // Feels like the condition will have to be based on the presence - // of clauses plus their textual analysis. + // variables. If such clauses are present, then this is considered an + // implementation error since such packages should be handled in the + // above pre-selected alternatives mode. // bool manual (alts == nullptr && prev_prereqs == nullptr); @@ -152,7 +116,8 @@ namespace bpkg { fail << "unable to reconfigure dependent " << ps.package.name << " with " << what << " clause that refers to dependency " - << "configuration variables"; + << "configuration variables" << + info << "please report in https://github.com/build2/build2/issues/302"; } } }; @@ -162,6 +127,8 @@ namespace bpkg // assert (alts == nullptr || alts->size () == deps.size ()); + dep_alts.reserve (deps.size ()); + for (size_t di (0); di != deps.size (); ++di) { // Skip the toolchain build-time dependencies and dependencies without @@ -170,7 +137,10 @@ namespace bpkg const dependency_alternatives_ex& das (deps[di]); if (das.empty ()) + { + dep_alts.push_back (0); continue; + } small_vector<pair<reference_wrapper<const dependency_alternative>, size_t>, @@ -179,7 +149,10 @@ namespace bpkg if (alts == nullptr) { if (toolchain_buildtime_dependency (o, das, &ps.package.name)) + { + dep_alts.push_back (0); continue; + } for (size_t i (0); i != das.size (); ++i) { @@ -205,7 +178,10 @@ namespace bpkg } if (edas.empty ()) + { + dep_alts.push_back (0); continue; + } } else { @@ -226,6 +202,8 @@ namespace bpkg // the "make dependency decisions" mode and select the alternative // regardless of the former prerequisites. // + assert (!edas.empty ()); + for (const vector<package_name>* pps (prev_prereqs);;) { const pair<reference_wrapper<const dependency_alternative>, @@ -234,7 +212,6 @@ namespace bpkg 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 @@ -297,13 +274,9 @@ 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> (pdb, dp), - prerequisite_info {*dc, - make_pair (conf ? di + 1 : 0, - conf ? dai + 1 : 0)}); + prerequisite_info {*dc}); } // Try the next alternative if there are unresolved dependencies for @@ -342,15 +315,6 @@ namespace bpkg if (s2 && !s1) 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, @@ -480,6 +444,8 @@ namespace bpkg make_pair (di, selected_alt->second)); } + dep_alts.push_back (selected_alt->second + 1); + // The dependency alternative is selected and its dependencies are // resolved to the selected packages. So proceed to the next depends // value. @@ -488,6 +454,10 @@ namespace bpkg } } + // Make sure we didn't miss any selected dependency alternative. + // + assert (dep_alts.size () == deps.size ()); + // Add the rest of the configuration variables (user overrides, reflects, // etc) as well as their sources. // @@ -518,6 +488,7 @@ namespace bpkg } return configure_prerequisites_result {move (prereqs), + move (dep_alts), move (vars), move (srcs), move (checksum)}; @@ -633,8 +604,14 @@ namespace bpkg l4 ([&]{trace << "src_root: " << src_root << ", " << "out_root: " << out_root;}); - assert (p->prerequisites.empty ()); + assert (p->prerequisites.empty () && p->dependency_alternatives.empty ()); + p->prerequisites = move (cpr.prerequisites); + p->dependency_alternatives = move (cpr.dependency_alternatives); + + // Mark the section as loaded, so dependency alternatives are updated. + // + p->dependency_alternatives_section.load (); // Configure. // diff --git a/bpkg/pkg-configure.hxx b/bpkg/pkg-configure.hxx index 876d11a..cd74786 100644 --- a/bpkg/pkg-configure.hxx +++ b/bpkg/pkg-configure.hxx @@ -43,12 +43,13 @@ namespace bpkg bool buildtime); // Given dependencies of a package, return its prerequisite packages, - // configuration variables that resulted from selection of these - // prerequisites (import, reflection, etc), and sources of the configuration - // variables resulted from evaluating the reflect clauses. Fail if for some - // of the dependency alternative lists there is no satisfactory alternative - // (all its dependencies are configured, satisfy the respective constraints, - // etc). + // 1-based indexes of the selected dependency alternatives (0 for toolchain + // build-time dependencies, etc), configuration variables that resulted from + // selection of these prerequisites (import, reflection, etc), and sources + // of the configuration variables resulted from evaluating the reflect + // clauses. Fail if for some of the dependency alternative lists there is no + // satisfactory alternative (all its dependencies are configured, satisfy + // the respective constraints, etc). // // The package dependency constraints are expected to be complete. // @@ -101,8 +102,9 @@ namespace bpkg // struct configure_prerequisites_result { - package_prerequisites prerequisites; - strings config_variables; // Note: name and value. + package_prerequisites prerequisites; + vector<size_t> dependency_alternatives; + strings config_variables; // Note: name and value. // Only contains sources of configuration variables collected using the // package skeleton, excluding those user-specified variables which are diff --git a/bpkg/pkg-disfigure.cxx b/bpkg/pkg-disfigure.cxx index af2c4f1..2239314 100644 --- a/bpkg/pkg-disfigure.cxx +++ b/bpkg/pkg-disfigure.cxx @@ -72,6 +72,11 @@ namespace bpkg // Since we are no longer configured, clear the prerequisites list. // p->prerequisites.clear (); + p->dependency_alternatives.clear (); + + // Mark the section as loaded, so dependency alternatives are updated. + // + p->dependency_alternatives_section.load (); assert (p->src_root); // Must be set since unpacked. assert (p->out_root); // Must be set since configured. diff --git a/tests/common/dependency-alternatives/t11a/biz-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/biz-0.1.0.tar.gz Binary files differnew file mode 100644 index 0000000..b42dff0 --- /dev/null +++ b/tests/common/dependency-alternatives/t11a/biz-0.1.0.tar.gz diff --git a/tests/common/dependency-alternatives/t11a/bus-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/bus-0.1.0.tar.gz Binary files differnew file mode 100644 index 0000000..e486d37 --- /dev/null +++ b/tests/common/dependency-alternatives/t11a/bus-0.1.0.tar.gz diff --git a/tests/common/dependency-alternatives/t11a/libbiz-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/libbiz-0.1.0.tar.gz Binary files differnew file mode 100644 index 0000000..429dc0d --- /dev/null +++ b/tests/common/dependency-alternatives/t11a/libbiz-0.1.0.tar.gz diff --git a/tests/common/dependency-alternatives/t11a/libbiz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/libbiz-1.0.0.tar.gz Binary files differnew file mode 100644 index 0000000..250f110 --- /dev/null +++ b/tests/common/dependency-alternatives/t11a/libbiz-1.0.0.tar.gz diff --git a/tests/common/dependency-alternatives/t8a/tpx-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/tpx-1.0.0.tar.gz Binary files differnew file mode 100644 index 0000000..aa8db1d --- /dev/null +++ b/tests/common/dependency-alternatives/t8a/tpx-1.0.0.tar.gz diff --git a/tests/common/dependency-alternatives/t8a/twx-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/twx-1.0.0.tar.gz Binary files differnew file mode 100644 index 0000000..03e8fbb --- /dev/null +++ b/tests/common/dependency-alternatives/t8a/twx-1.0.0.tar.gz diff --git a/tests/pkg-build.testscript b/tests/pkg-build.testscript index be5a9f8..ee4ea99 100644 --- a/tests/pkg-build.testscript +++ b/tests/pkg-build.testscript @@ -148,9 +148,9 @@ # | |-- libbox-1.0.0.tar.gz # | |-- libfoo-1.0.0.tar.gz # | |-- libfoo-2.0.0.tar.gz -# | |-- bar -> libbar -# | |-- baz -> libbaz -# | |-- box -> libbiz ^1.0.0 config.box.backend=libbiz | +# | |-- bar-1.0.0.tar.gz -> libbar +# | |-- baz-1.0.0.tar.gz -> libbaz +# | |-- box-1.0.0.tar.gz -> libbiz ^1.0.0 config.box.backend=libbiz | # | | libbox >= 0.1.1 config.box.backend=libbox, # | | libbaz # | |-- fax-1.0.0.tar.gz -> libbar ^1.0.0 ? ($cxx.target.class == 'windows') config.fax.backend=libbar | @@ -160,13 +160,19 @@ # | |-- fix-1.0.0.tar.gz -> libbaz ^1.0.0 | libbar ^1.0.0 # | |-- foo-1.0.0.tar.gz -> {libbar libbaz} ^1.0.0 # | |-- fox-1.0.0.tar.gz -> libbar ^1.0.0 | libbaz ^1.0.0 -# | |-- fux -> libbiz ? (!$config.fux.libbiz_old) | libbiz ^0.1.0 ? ($config.fux.libbiz_old) -# | |-- tax -> libfoo == 1.0.0 | libfoo == 2.0.0 -# | |-- tex -> libfoo {prefer{} accept(false) reflect {...}} -# | |-- tix -> libfoo >= 2.0.0 reflect {...} | libfoo >= 1.0.0 reflect {...} -# | |-- tox -> libfoo >= 2.0.0 {prefer{} accept(false) reflect {...}} | libfoo >= 1.0.0 reflect {...} -# | |-- tux -> libfoo {prefer{config.libfoo.protocol = "1"} accept(false) -# | | -> libbox ? (config.libfoo.protocol == "1") +# | |-- fux-1.0.0.tar.gz -> libbiz ? (!$config.fux.libbiz_old) | libbiz ^0.1.0 ? ($config.fux.libbiz_old) +# | |-- tax-1.0.0.tar.gz -> libfoo == 1.0.0 | libfoo == 2.0.0 +# | |-- tex-1.0.0.tar.gz -> libfoo prefer{} accept(true) reflect {...} +# | |-- tix-1.0.0.tar.gz -> libfoo >= 2.0.0 reflect {...} | libfoo >= 1.0.0 reflect {...} +# | |-- tox-1.0.0.tar.gz -> libfoo >= 2.0.0 prefer{} accept(true) reflect {...} | libfoo >= 1.0.0 reflect {...} +# | |-- tpx-1.0.0.tar.gz -> libfoo >= 2.0.0 prefer{...} accept(true) reflect {...} | libfoo >= 1.0.0 prefer{...} accept(true) reflect {...} +# | |-- tux-1.0.0.tar.gz -> libfoo prefer{config.libfoo.protocol = "1"} accept(true), +# | | libbox ? (config.libfoo.protocol == "1") +# | |-- twx-1.0.0.tar.gz -> libbiz, +# | | libfoo prefer{config.libfoo.protocol = "1"} accept(true), +# | | libbox ? (config.libfoo.protocol == "1") +# | |-- tvx-1.0.0.tar.gz -> libfoo >= 2.0.0 reflect {...} | libfoo >= 1.0.0 reflect {...}, +# | | libfox prefer{config.libfox.level = $config.tvx.reflect} accept(true) # | `-- repositories.manifest # | # |-- t9 @@ -191,6 +197,8 @@ # | |-- libbaz-1.0.0.tar.gz # | |-- libbox-0.1.0.tar.gz # | |-- libbox-1.0.0.tar.gz +# | |-- libbiz-0.1.0.tar.gz +# | |-- libbiz-1.0.0.tar.gz -> libbar # | |-- foo-0.1.0.tar.gz -> libfoo {require {config.libfoo.extras=true}} # | |-- foo-0.2.0.tar.gz -> libfoo {require {config.libfoo.extras=true}} | libbar # | |-- foo-1.0.0.tar.gz -> libfoo {require {config.libfoo.extras=true}} @@ -201,6 +209,7 @@ # | | libbar {require {config.libbar.extras=true}} # | |-- fox-1.0.0.tar.gz -> libfoo {require {config.libfoo.extras=true}} # | |-- fux-1.0.0.tar.gz -> libfoo +# | |-- fix-0.1.0.tar.gz -> foo == 0.1.0 # | |-- fix-1.0.0.tar.gz -> foo {require {config.foo.extras=true}} # | |-- fex-1.0.0.tar.gz -> foo, libfoo {require {config.libfoo.extras=true}} # | |-- bar-0.1.0.tar.gz -> libbar == 0.1.0 {require {config.libbar.extras=true}} @@ -213,6 +222,7 @@ # | |-- bat-1.0.0.tar.gz -> libbaz {require {config.libbaz.extras=true}} # | |-- bas-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}}, # | | bus {require {config.bus.extras=true}} +# | |-- bus-0.1.0.tar.gz -> foo {require {config.foo.extras=true}} # | |-- bus-1.0.0.tar.gz -> libaz {require {config.libbox.extras=true}}, # | | foo {require {config.foo.extras=true}} # | |-- box-0.1.0.tar.gz -> libbox {require {config.libbox.extras=true}} @@ -225,6 +235,7 @@ # | | bux # | |-- bex-1.0.0.tar.gz -> libbar # | |-- boo-1.0.0.tar.gz -> libbar | libfoo {require {config.libfoo.extras=true}} | libbox +# | |-- biz-0.1.0.tar.gz -> libbiz == 0.1.0 # | |-- biz-1.0.0.tar.gz -> boo {require {config.boo.extras=true}} # | |-- buz-1.0.0.tar.gz -> bux {require {config.bux.extras=true}} # | |-- buc-1.0.0.tar.gz -> libfoo {require {config.libfoo.extras=true}}, @@ -5191,7 +5202,7 @@ test.arguments += --sys-no-query $pkg_drop tix } - : fail-select-alt-with-reflect + : select-alt-with-reflect : { $clone_cfg; @@ -5209,103 +5220,217 @@ test.arguments += --sys-no-query %.* EOO - # @@ Note that the current behavior should actually be considered as a - # bug which we will fix eventually. The proper behaviour would be - # to re-evaluate this dependent rather than just to re-configure. - # - $* ?libfoo 2>>~%EOE% != 0; - error: unable to reconfigure dependent tox with reflect clause that refers to dependency configuration variables - info: while configuring tox + $* ?libfoo 2>>~%EOE%; + disfigured tox/1.0.0 + disfigured libfoo/1.0.0 + fetched libfoo/2.0.0 + unpacked libfoo/2.0.0 + configured libfoo/2.0.0 + configured tox/1.0.0 + %info: .+tox-1.0.0.+ is up to date% + updated tox/1.0.0 EOE $pkg_status -r >>EOO; !tox configured 1.0.0 - libfoo configured !1.0.0 available 2.0.0 + libfoo configured 2.0.0 EOO cat cfg/tox-1.0.0/build/config.build >>~%EOO%; %.* - config.tox.libfoo_protocol = '1 or 2' + config.tox.libfoo_protocol = 2 %.* EOO $pkg_drop tox } - : fail-enable-banned-var + : re-evaluate-from : { - $clone_cfg; + +$clone_cfg - $* tux ?libbox/0.1.0 2>!; + : earlier-depends + : + { + $clone_cfg; - $pkg_status -r >>EOO; - !tux configured 1.0.0 - libbox configured !0.1.0 available 1.0.0 0.1.1 - libfoo configured 2.0.0 - EOO + $* tux ?libbox/0.1.0 2>!; - $* ?libbox 2>>EOE != 0; - error: unable to reconfigure dependent tux with enable clause that refers to dependency configuration variables - info: while configuring tux - EOE + $pkg_status -r >>EOO; + !tux configured 1.0.0 + libbox configured !0.1.0 available 1.0.0 0.1.1 + libfoo configured 2.0.0 + EOO - $pkg_status -r >>EOO; - !tux configured 1.0.0 - libbox configured !0.1.0 available 1.0.0 0.1.1 - libfoo configured 2.0.0 - EOO + cat cfg/libfoo-2.0.0/build/config.build >>~%EOO%; + %.* + config.libfoo.protocol = 1 + %.* + EOO + + $* ?libbox 2>>~%EOE%; + disfigured tux/1.0.0 + disfigured libbox/0.1.0 + fetched libbox/1.0.0 + unpacked libbox/1.0.0 + configured libbox/1.0.0 + configured tux/1.0.0 + %info: .+tux-1.0.0.+ is up to date% + updated tux/1.0.0 + EOE + + $pkg_status -r >>EOO; + !tux configured 1.0.0 + libbox configured 1.0.0 + libfoo configured 2.0.0 + EOO + + cat cfg/libfoo-2.0.0/build/config.build >>~%EOO%; + %.* + config.libfoo.protocol = 1 + %.* + EOO + + $pkg_drop tux + } + + : later-depends + : + { + $clone_cfg; + + $* twx ?libbiz/0.1.0 2>!; + + $pkg_status -r >>EOO; + !twx configured 1.0.0 + libbiz configured !0.1.0 available 1.0.0 + libbox configured 1.0.0 + libfoo configured 2.0.0 + EOO + + cat cfg/libfoo-2.0.0/build/config.build >>~%EOO%; + %.* + config.libfoo.protocol = 1 + %.* + EOO + + $* ?libbiz 2>>~%EOE%; + disfigured twx/1.0.0 + disfigured libbiz/0.1.0 + fetched libbiz/1.0.0 + unpacked libbiz/1.0.0 + configured libbiz/1.0.0 + configured twx/1.0.0 + %info: .+twx-1.0.0.+ is up to date% + updated twx/1.0.0 + EOE + + $pkg_status -r >>EOO; + !twx configured 1.0.0 + libbiz configured 1.0.0 + libbox configured 1.0.0 + libfoo configured 2.0.0 + EOO + + cat cfg/libfoo-2.0.0/build/config.build >>~%EOO%; + %.* + config.libfoo.protocol = 1 + %.* + EOO + + $pkg_drop twx + } + + : same-depends + : + { + $clone_cfg; + + $* tvx ?libfoo/1.0.0 2>!; + + $pkg_status -r >>EOO; + !tvx configured 1.0.0 + libfoo configured !1.0.0 available 2.0.0 + libfox configured 1.0.0 + EOO + + cat cfg/libfox-1.0.0/build/config.build >>~%EOO%; + %.* + config.libfox.level = 1 + %.* + EOO + + $* ?libfoo 2>>~%EOE%; + disfigured tvx/1.0.0 + disfigured libfoo/1.0.0 + disfigured libfox/1.0.0 + fetched libfoo/2.0.0 + unpacked libfoo/2.0.0 + configured libfox/1.0.0 + configured libfoo/2.0.0 + configured tvx/1.0.0 + %info: .+tvx-1.0.0.+ is up to date% + updated tvx/1.0.0 + EOE - $pkg_drop tux + $pkg_status -r >>EOO; + !tvx configured 1.0.0 + libfoo configured 2.0.0 + libfox configured 1.0.0 + EOO + + cat cfg/libfox-1.0.0/build/config.build >>~%EOO%; + %.* + config.libfox.level = 2 + %.* + EOO + + $pkg_drop tvx + } } - : dont-re-evaluate-dependent + : change-alternative : { $clone_cfg; - $* tvx ?libfoo/1.0.0 2>!; + $* tpx ?libfoo/1.0.0 2>!; $pkg_status -r >>EOO; - !tvx configured 1.0.0 + !tpx configured 1.0.0 libfoo configured !1.0.0 available 2.0.0 - libfox configured 1.0.0 EOO - cat cfg/libfox-1.0.0/build/config.build >>~%EOO%; + cat cfg/tpx-1.0.0/build/config.build >>~%EOO%; %.* - config.libfox.level = 1 + config.tpx.libfoo_protocol = 1 %.* EOO - # @@ Note that the current behavior should actually be considered as a - # bug which we will fix eventually. The proper behaviour would be - # to re-evaluate this dependent rather than just to re-configure. - # $* ?libfoo 2>>~%EOE%; - disfigured tvx/1.0.0 + disfigured tpx/1.0.0 disfigured libfoo/1.0.0 fetched libfoo/2.0.0 unpacked libfoo/2.0.0 configured libfoo/2.0.0 - configured tvx/1.0.0 - %info: .+tvx-1.0.0.+ is up to date% - updated tvx/1.0.0 + configured tpx/1.0.0 + %info: .+tpx-1.0.0.+ is up to date% + updated tpx/1.0.0 EOE $pkg_status -r >>EOO; - !tvx configured 1.0.0 + !tpx configured 1.0.0 libfoo configured 2.0.0 - libfox configured 1.0.0 EOO - cat cfg/libfox-1.0.0/build/config.build >>~%EOO%; + cat cfg/tpx-1.0.0/build/config.build >>~%EOO%; %.* - config.libfox.level = 1 + config.tpx.libfoo_protocol = 2 %.* EOO - $pkg_drop tvx + $pkg_drop tpx } } } @@ -6109,6 +6234,10 @@ test.arguments += --sys-no-query { $clone_cfg; + # Dependencies: + # + # foo/1.0.0: depends: libfoo(c) + # $* foo 2>>~%EOE%; %.* trace: pkg_build: refine package collection/plan execution from scratch @@ -6151,11 +6280,17 @@ test.arguments += --sys-no-query %.* trace: pkg_build: refine package collection/plan execution %.* - trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0 + trace: collect_build_prerequisites: pre-reeval foo/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1 + trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0 due to dependency libfoo/0.1.0 trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}} trace: collect_build_postponed (0): begin trace: collect_build_postponed (1): begin {foo^ | libfoo->{foo/1,1}} %.* + trace: collect_build_prerequisites: pre-reeval foo/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1 trace: collect_build_postponed (1): re-evaluate existing dependents for {foo^ | libfoo->{foo/1,1}} trace: collect_build: add foo/1.0.0 trace: collect_build_prerequisites: reeval foo/1.0.0 @@ -6213,13 +6348,18 @@ test.arguments += --sys-no-query %.* trace: collect_build: add libfoo/0.1.0 %.* - trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0 + trace: collect_build_prerequisites: pre-reeval foo/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1 + trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0 due to dependency libfoo/0.1.0 trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}} trace: collect_build_postponed (0): begin trace: collect_build_postponed (1): begin {foo^ | libfoo->{foo/1,1}} %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {foo^ | libfoo->{foo/1,1}} + trace: collect_build_prerequisites: pre-reeval foo/1.0.0 %.* + trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1 + trace: collect_build_postponed (1): re-evaluate existing dependents for {foo^ | libfoo->{foo/1,1}} trace: collect_build: add foo/1.0.0 trace: collect_build_prerequisites: reeval foo/1.0.0 %.* @@ -6273,11 +6413,17 @@ test.arguments += --sys-no-query %.* trace: collect_build: add libfoo/1.0.0 %.* - trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent foo/1.0.0 + trace: collect_build_prerequisites: pre-reeval foo/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1 + trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent foo/1.0.0 due to dependency libfoo/1.0.0 trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}} trace: collect_build_postponed (0): begin trace: collect_build_postponed (1): begin {foo^ | libfoo->{foo/1,1}} %.* + trace: collect_build_prerequisites: pre-reeval foo/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1 trace: collect_build_postponed (1): re-evaluate existing dependents for {foo^ | libfoo->{foo/1,1}} trace: collect_build_prerequisites: reeval foo/1.0.0 %.* @@ -6310,6 +6456,16 @@ test.arguments += --sys-no-query trace: pkg_build: refine package collection/plan execution from scratch %.* trace: collect_build: add libfoo/1.0.0 + trace: pkg_build: dep-postpone user-specified libfoo + trace: collect_drop: overwrite foo + trace: collect_build_postponed (0): begin + trace: collect_build_postponed (0): erase bogus postponement libfoo + trace: collect_build_postponed (0): bogus postponements erased, throwing + trace: pkg_build: collection failed due to bogus dependency collection postponement cancellation, retry from scratch + %.* + trace: pkg_build: refine package collection/plan execution from scratch + %.* + trace: collect_build: add libfoo/1.0.0 %.* trace: collect_build_prerequisites: skip expected to be dropped existing dependent foo of dependency libfoo trace: collect_build_prerequisites: begin libfoo/1.0.0 @@ -6350,6 +6506,11 @@ test.arguments += --sys-no-query { $clone_cfg; + # Dependencies: + # + # foo/1.0.0: depends: libfoo(c) + # fox/1.0.0: depends: libfoo(c) + # $* libfoo/0.1.0 foo/1.0.0 fox/1.0.0 2>!; $pkg_status -r >>EOO; @@ -6366,14 +6527,26 @@ test.arguments += --sys-no-query %.* trace: collect_build: add libfoo/1.0.0 %.* - trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent foo/1.0.0 + trace: collect_build_prerequisites: pre-reeval foo/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1 + %.* + trace: collect_build_prerequisites: pre-reeval fox/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated fox/1.0.0: 1,1 + trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent foo/1.0.0 due to dependency libfoo/1.0.0 trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}} - trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent fox/1.0.0 + trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent fox/1.0.0 due to dependency libfoo/1.0.0 trace: collect_build_postponed (0): begin trace: collect_build_postponed (1): begin {foo^ | libfoo->{foo/1,1}} %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {foo^ | libfoo->{foo/1,1}} + trace: collect_build_prerequisites: pre-reeval foo/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1 + trace: collect_build_prerequisites: pre-reeval fox/1.0.0 %.* + trace: collect_build_prerequisites: pre-reevaluated fox/1.0.0: 1,1 + trace: collect_build_postponed (1): re-evaluate existing dependents for {foo^ | libfoo->{foo/1,1}} trace: collect_build: add foo/1.0.0 trace: collect_build_prerequisites: reeval foo/1.0.0 %.* @@ -6381,7 +6554,6 @@ test.arguments += --sys-no-query trace: postponed_configurations::add: add {foo^ 1,1: libfoo} to {foo^ | libfoo->{foo/1,1}} trace: collect_build_prerequisites: re-evaluating dependent foo/1.0.0 results in {foo^ | libfoo->{foo/1,1}} trace: collect_build_prerequisites: re-evaluated foo/1.0.0 - %.* trace: collect_build: add fox/1.0.0 trace: collect_build_prerequisites: reeval fox/1.0.0 %.* @@ -6446,56 +6618,214 @@ test.arguments += --sys-no-query $pkg_drop libfoo foo fox } - : postpone-existing + : postpone-existing-dependency : { $clone_cfg; # Dependencies: # - # fix/1.0.0: depends: foo(c) - # foo/1.0.0: depends: libfoo(c) + # bus: depends: foo(c) # - # fix/0.1.0: depends: foo == 0.1.0 - # foo/0.1.0: depends: libfoo(c) + # fix: depends: foo == 0.1.0 # - $* fix 2>!; + # libbiz/1.0.0: depends: libbar + # libbiz/0.1.0: + # + # foo: depends: libfoo(c) + # + $* bus/0.1.0 2>!; - $* libfoo/0.1.0 fix/0.1.0 2>>~%EOE%; + $pkg_status -r >>EOO; + !bus configured !0.1.0 available 1.0.0 + foo configured 1.0.0 + libfoo configured 1.0.0 + EOO + + $* fix/0.1.0 libbiz biz/0.1.0 2>>~%EOE%; %.* trace: pkg_build: refine package collection/plan execution from scratch %.* - trace: collect_build: add libfoo/0.1.0 trace: collect_build: add fix/0.1.0 + trace: collect_build: add libbiz/1.0.0 + trace: collect_build: add biz/0.1.0 + trace: collect_build_prerequisites: begin fix/0.1.0 %.* - trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0 - trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}} + trace: collect_build: add foo/0.1.0 + info: package fix dependency on (foo == 0.1.0) is forcing downgrade of foo/1.0.0 to 0.1.0 + trace: collect_build_prerequisites: no cfg-clause for dependency foo/0.1.0 of dependent fix/0.1.0 %.* - trace: collect_build_prerequisites: begin fix/0.1.0 + trace: collect_build_prerequisites: pre-reeval bus/0.1.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated bus/0.1.0: 1,1 + trace: collect_build_prerequisites: cfg-postpone dependency foo/0.1.0 of existing dependent bus/0.1.0 due to dependency foo/0.1.0 + trace: postponed_configurations::add: create {bus^ | foo->{bus/1,1}} + trace: collect_build_prerequisites: end fix/0.1.0 + trace: collect_build_prerequisites: begin libbiz/1.0.0 + %.* + trace: collect_build: add libbar/1.0.0 + trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent libbiz/1.0.0 + trace: collect_build_prerequisites: begin libbar/1.0.0 + trace: collect_build_prerequisites: end libbar/1.0.0 + trace: collect_build_prerequisites: end libbiz/1.0.0 + trace: collect_build_prerequisites: begin biz/0.1.0 + %.* + trace: collect_build: pick libbiz/0.1.0 over libbiz/1.0.0 + trace: collect_build: libbiz/1.0.0 package version needs to be replaced with libbiz/0.1.0 + trace: pkg_build: collection failed due to package version replacement, retry from scratch %.* trace: pkg_build: refine package collection/plan execution from scratch %.* - trace: collect_build: add libfoo/0.1.0 trace: collect_build: add fix/0.1.0 + trace: collect_build: apply version replacement for libbiz/1.0.0 + trace: collect_build: replacement: libbiz/0.1.0 + trace: collect_build: add libbiz/0.1.0 + trace: collect_build: add biz/0.1.0 + trace: collect_build_prerequisites: begin fix/0.1.0 %.* - trace: collect_build_prerequisites: skip expected to be built existing dependent foo of dependency libfoo - trace: collect_build_prerequisites: begin libfoo/0.1.0 - trace: collect_build_prerequisites: end libfoo/0.1.0 + trace: collect_build: add foo/0.1.0 + info: package fix dependency on (foo == 0.1.0) is forcing downgrade of foo/1.0.0 to 0.1.0 + trace: collect_build_prerequisites: dep-postpone dependency foo/0.1.0 of dependent fix/0.1.0 + trace: collect_build_prerequisites: end fix/0.1.0 + trace: collect_build_prerequisites: begin libbiz/0.1.0 + trace: collect_build_prerequisites: end libbiz/0.1.0 + trace: collect_build_prerequisites: begin biz/0.1.0 + %.* + trace: collect_build_prerequisites: no cfg-clause for dependency libbiz/0.1.0 of dependent biz/0.1.0 + trace: collect_build_prerequisites: end biz/0.1.0 + trace: pkg_build: erase bogus postponement foo + trace: pkg_build: bogus postponements erased, throwing + trace: pkg_build: collection failed due to bogus dependency collection postponement cancellation, retry from scratch %.* + trace: pkg_build: refine package collection/plan execution from scratch + %.* + trace: collect_build: add fix/0.1.0 + trace: collect_build: apply version replacement for libbiz/1.0.0 + trace: collect_build: replacement: libbiz/0.1.0 + trace: collect_build: add libbiz/0.1.0 + trace: collect_build: add biz/0.1.0 trace: collect_build_prerequisites: begin fix/0.1.0 %.* - trace: collect_build: apply version replacement for foo/0.1.0 - trace: collect_build: replacement: foo/0.1.0 trace: collect_build: add foo/0.1.0 info: package fix dependency on (foo == 0.1.0) is forcing downgrade of foo/1.0.0 to 0.1.0 trace: collect_build_prerequisites: no cfg-clause for dependency foo/0.1.0 of dependent fix/0.1.0 %.* - trace: collect_build_prerequisites: skip being built existing dependent fix of dependency foo + trace: collect_build_prerequisites: pre-reeval bus/0.1.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated bus/0.1.0: 1,1 + trace: collect_build_prerequisites: cfg-postpone dependency foo/0.1.0 of existing dependent bus/0.1.0 due to dependency foo/0.1.0 + trace: postponed_configurations::add: create {bus^ | foo->{bus/1,1}} + trace: collect_build_prerequisites: end fix/0.1.0 + trace: collect_build_prerequisites: begin libbiz/0.1.0 + trace: collect_build_prerequisites: end libbiz/0.1.0 + trace: collect_build_prerequisites: begin biz/0.1.0 + %.* + trace: collect_build_prerequisites: no cfg-clause for dependency libbiz/0.1.0 of dependent biz/0.1.0 + trace: collect_build_prerequisites: end biz/0.1.0 + trace: collect_build_postponed (0): begin + trace: collect_build_postponed (1): begin {bus^ | foo->{bus/1,1}} + %.* + trace: collect_build_prerequisites: pre-reeval bus/0.1.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated bus/0.1.0: 1,1 + trace: collect_build_postponed (1): re-evaluate existing dependents for {bus^ | foo->{bus/1,1}} + trace: collect_build: add bus/0.1.0 + trace: collect_build_prerequisites: reeval bus/0.1.0 + %.* + trace: collect_build: pick foo/0.1.0 over foo/1.0.0 + trace: postponed_configurations::add: add {bus^ 1,1: foo} to {bus^ | foo->{bus/1,1}} + trace: collect_build_prerequisites: re-evaluating dependent bus/0.1.0 results in {bus^ | foo->{bus/1,1}} + trace: collect_build_prerequisites: re-evaluated bus/0.1.0 + trace: collect_build_postponed (1): cfg-negotiate begin {bus^ | foo->{bus/1,1}} + %.* + trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: begin foo/0.1.0 %.* - trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0 - trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/0.1.0 of dependent foo/0.1.0 (collected prematurely), throwing postpone_dependency - trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch + trace: collect_build: add libfoo/1.0.0 + trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/0.1.0 + trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}} + trace: collect_build_prerequisites: postpone foo/0.1.0 + trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents + trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bus/0.1.0 + trace: collect_build_prerequisites: resume bus/0.1.0 + trace: collect_build_prerequisites: end bus/0.1.0 + trace: collect_build_postponed (1): cfg-negotiate end {bus^ | foo->{bus/1,1}}! + trace: collect_build_postponed (2): begin {foo | libfoo->{foo/1,1}} + %.* + trace: collect_build_postponed (2): skip being built existing dependent foo of dependency libfoo + trace: collect_build_postponed (2): cfg-negotiate begin {foo | libfoo->{foo/1,1}} + %.* + trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies + trace: collect_build_prerequisites: skip configured libfoo/1.0.0 + trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents + trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent foo/0.1.0 + trace: collect_build_prerequisites: resume foo/0.1.0 + trace: collect_build_prerequisites: end foo/0.1.0 + trace: collect_build_postponed (2): cfg-negotiate end {foo | libfoo->{foo/1,1}}! + trace: collect_build_postponed (2): end {foo | libfoo->{foo/1,1}} + trace: collect_build_postponed (1): end {bus^ | foo->{bus/1,1}} + trace: collect_build_postponed (0): end + %.* + trace: execute_plan: simulate: yes + %.* + build plan: + downgrade foo/0.1.0 (required by bus, fix) + config.foo.extras=true (set by bus) + reconfigure bus/0.1.0 (dependent of foo) + new fix/0.1.0 + new libbiz/0.1.0 + new biz/0.1.0 + trace: execute_plan: simulate: no + %.* + EOE + + $pkg_status -r >>EOO; + !bus configured !0.1.0 available 1.0.0 + foo configured 0.1.0 available 1.0.0 0.2.0 + libfoo configured 1.0.0 + !fix configured !0.1.0 available 1.0.0 + foo configured 0.1.0 available 1.0.0 0.2.0 + libfoo configured 1.0.0 + !libbiz configured 0.1.0 available 1.0.0 + !biz configured !0.1.0 available 1.0.0 + !libbiz configured 0.1.0 available 1.0.0 + EOO + + $pkg_drop bus fix libbiz biz + } + + : postpone-existing + : + { + $clone_cfg; + + # Dependencies: + # + # fix/1.0.0: depends: foo(c) + # foo/1.0.0: depends: libfoo(c) + # + # fix/0.1.0: depends: foo == 0.1.0 + # foo/0.1.0: depends: libfoo(c) + # + $* fix 2>!; + + $* libfoo/0.1.0 fix/0.1.0 2>>~%EOE%; + %.* + trace: pkg_build: refine package collection/plan execution from scratch + %.* + trace: collect_build: add libfoo/0.1.0 + trace: collect_build: add fix/0.1.0 + %.* + trace: collect_build_prerequisites: pre-reeval foo/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1 + trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0 due to dependency libfoo/0.1.0 + trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}} + %.* + trace: collect_build_prerequisites: begin fix/0.1.0 + %.* + trace: collect_build: existing dependent foo/1.0.0 needs to be replaced with foo/0.1.0 + trace: pkg_build: collection failed due to package version replacement, retry from scratch %.* trace: pkg_build: refine package collection/plan execution from scratch %.* @@ -6538,6 +6868,13 @@ test.arguments += --sys-no-query %.* trace: execute_plan: simulate: yes %.* + build plan: + downgrade libfoo/0.1.0 + config.libfoo.extras=true (set by foo) + downgrade foo/0.1.0 (required by fix) + downgrade fix/0.1.0 + trace: execute_plan: simulate: no + %.* EOE $pkg_status -r >>EOO; @@ -6575,21 +6912,20 @@ test.arguments += --sys-no-query trace: collect_build: add libfoo/0.1.0 trace: collect_build: add libbar/0.1.0 %.* - trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent tex/1.0.0 - trace: postponed_configurations::add: create {tex^ | libfoo->{tex/2,1}} + trace: collect_build_prerequisites: pre-reeval tex/1.0.0 %.* - trace: collect_build_prerequisites: cfg-postpone dependency libbar/0.1.0 of existing dependent tex/1.0.0 + trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1 + trace: collect_build: pick libbar/0.1.0 over libbar/1.0.0 + trace: collect_build_prerequisites: cfg-postpone dependency libbar/0.1.0 of existing dependent tex/1.0.0 due to dependency libfoo/0.1.0 trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}} + trace: pkg_build: dep-postpone user-specified libbar trace: collect_build_postponed (0): begin - trace: collect_build_postponed (1): begin {tex^ | libfoo->{tex/2,1}} - %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libfoo->{tex/2,1}} - trace: collect_build_postponed (1): cannot re-evaluate dependent tex to dependency index 2 due to earlier dependency index 1 in {tex^ | libbar->{tex/1,1}}, skipping {tex^ | libfoo->{tex/2,1}} - trace: collect_build_postponed (0): postpone cfg-negotiation of {tex^ | libfoo->{tex/2,1}} trace: collect_build_postponed (1): begin {tex^ | libbar->{tex/1,1}} %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libbar->{tex/1,1}} + trace: collect_build_prerequisites: pre-reeval tex/1.0.0 %.* + trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1 + trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libbar->{tex/1,1}} trace: collect_build: add tex/1.0.0 trace: collect_build_prerequisites: reeval tex/1.0.0 %.* @@ -6608,13 +6944,13 @@ test.arguments += --sys-no-query %.* trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0 trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of dependent tex/1.0.0 - trace: postponed_configurations::add: add {tex 2,1: libfoo} to {tex^ | libfoo->{tex/2,1}} + trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}} trace: collect_build_prerequisites: postpone tex/1.0.0 trace: collect_build_postponed (1): cfg-negotiate end {tex^ | libbar->{tex/1,1}}! - trace: collect_build_postponed (2): begin {tex^ | libfoo->{tex/2,1}} + trace: collect_build_postponed (2): begin {tex | libfoo->{tex/2,1}} %.* trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo - trace: collect_build_postponed (2): cfg-negotiate begin {tex^ | libfoo->{tex/2,1}} + trace: collect_build_postponed (2): cfg-negotiate begin {tex | libfoo->{tex/2,1}} %.* trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: begin libfoo/0.1.0 @@ -6623,8 +6959,8 @@ test.arguments += --sys-no-query trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/1.0.0 trace: collect_build_prerequisites: resume tex/1.0.0 trace: collect_build_prerequisites: end tex/1.0.0 - trace: collect_build_postponed (2): cfg-negotiate end {tex^ | libfoo->{tex/2,1}}! - trace: collect_build_postponed (2): end {tex^ | libfoo->{tex/2,1}} + trace: collect_build_postponed (2): cfg-negotiate end {tex | libfoo->{tex/2,1}}! + trace: collect_build_postponed (2): end {tex | libfoo->{tex/2,1}} trace: collect_build_postponed (1): end {tex^ | libbar->{tex/1,1}} trace: collect_build_postponed (0): end %.* @@ -6636,32 +6972,7 @@ test.arguments += --sys-no-query downgrade libbar/0.1.0 config.libbar.extras=true (set by tex) reconfigure tex/1.0.0 (dependent of libbar) - %.* - disfigured tex/1.0.0 - %.* - disfigured libbar/1.0.0 - %.* - disfigured libfoo/1.0.0 - %.* - fetched libfoo/0.1.0 - %.* - unpacked libfoo/0.1.0 - %.* - fetched libbar/0.1.0 - %.* - unpacked libbar/0.1.0 - %.* - configured libfoo/0.1.0 - %.* - configured libbar/0.1.0 - %.* - configured tex/1.0.0 - %.* - updated libfoo/0.1.0 - %.* - updated libbar/0.1.0 - %.* - updated tex/1.0.0 + trace: execute_plan: simulate: no %.* EOE @@ -6697,73 +7008,32 @@ test.arguments += --sys-no-query trace: collect_build: add libfoo/0.1.0 trace: collect_build: add bar/0.1.0 %.* - trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent tex/1.0.0 - trace: postponed_configurations::add: create {tex^ | libfoo->{tex/2,1}} - trace: collect_build_prerequisites: begin bar/0.1.0 + trace: collect_build_prerequisites: pre-reeval tex/1.0.0 %.* - trace: collect_build: add libbar/0.1.0 - info: package bar dependency on (libbar == 0.1.0) is forcing downgrade of libbar/1.0.0 to 0.1.0 - trace: collect_build_prerequisites: cfg-postpone dependency libbar/0.1.0 of dependent bar/0.1.0 - trace: postponed_configurations::add: create {bar | libbar->{bar/1,1}} - trace: collect_build_prerequisites: postpone bar/0.1.0 - trace: collect_build_postponed (0): begin - trace: collect_build_postponed (1): begin {tex^ | libfoo->{tex/2,1}} - %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libfoo->{tex/2,1}} - %.* - trace: collect_build: add tex/1.0.0 - trace: collect_build_prerequisites: reeval tex/1.0.0 - %.* - trace: collect_build: pick libbar/0.1.0 over libbar/1.0.0 - %.* - trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0 - trace: postponed_configurations::add: add {tex^ 2,1: libfoo} to {tex^ | libfoo->{tex/2,1}} - trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ | libfoo->{tex/2,1}} - trace: collect_build_prerequisites: re-evaluated tex/1.0.0 - trace: collect_build_postponed (1): cfg-negotiate begin {tex^ | libfoo->{tex/2,1}} - %.* - trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies - trace: collect_build_prerequisites: begin libfoo/0.1.0 - trace: collect_build_prerequisites: end libfoo/0.1.0 - trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents - trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0 - trace: collect_build_prerequisites: resume tex/1.0.0 - trace: collect_build_prerequisites: end tex/1.0.0 - trace: collect_build_postponed (1): cfg-negotiate end {tex^ | libfoo->{tex/2,1}}! - trace: collect_build_postponed (2): begin {bar | libbar->{bar/1,1}} - %.* - trace: collect_build_postponed (2): re-evaluate existing dependents for {bar | libbar->{bar/1,1}} - trace: collect_build_postponed (2): cannot re-evaluate dependent tex to dependency index 1 due to greater dependency index 2 in {tex^ | libfoo->{tex/2,1}}!, throwing postpone_position - trace: pkg_build: collection failed due to earlier dependency position, retry from scratch - %.* - trace: pkg_build: refine package collection/plan execution from scratch - %.* - trace: collect_build: add libfoo/0.1.0 - trace: collect_build: add bar/0.1.0 - %.* - trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent tex/1.0.0 - trace: postponed_configurations::add: create {tex^ | libfoo->{tex/2,1}} + trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1 + trace: collect_build: add libbar/1.0.0 + trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tex/1.0.0 due to dependency libfoo/0.1.0 + trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}} trace: collect_build_prerequisites: begin bar/0.1.0 %.* - trace: collect_build: add libbar/0.1.0 + trace: collect_build: pick libbar/0.1.0 over libbar/1.0.0 + trace: collect_build: libbar/1.0.0 package version needs to be replaced in-place with libbar/0.1.0 info: package bar dependency on (libbar == 0.1.0) is forcing downgrade of libbar/1.0.0 to 0.1.0 trace: collect_build_prerequisites: cfg-postpone dependency libbar/0.1.0 of dependent bar/0.1.0 - trace: postponed_configurations::add: create {bar | libbar->{bar/1,1}} + trace: postponed_configurations::add: add {bar 1,1: libbar} to {tex^ | libbar->{tex/1,1}} trace: collect_build_prerequisites: postpone bar/0.1.0 trace: collect_build_postponed (0): begin - trace: collect_build_postponed (1): begin {tex^ | libfoo->{tex/2,1}} + trace: collect_build_postponed (1): begin {bar tex^ | libbar->{bar/1,1 tex/1,1}} %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libfoo->{tex/2,1}} - trace: collect_build_postponed (1): pos-postpone existing dependent tex re-evaluation to dependency index 2 due to recorded index 1, skipping {tex^ | libfoo->{tex/2,1}} - trace: collect_build_postponed (0): postpone cfg-negotiation of {tex^ | libfoo->{tex/2,1}} - trace: collect_build_postponed (1): begin {bar | libbar->{bar/1,1}} + trace: collect_build_prerequisites: pre-reeval tex/1.0.0 %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {bar | libbar->{bar/1,1}} + trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1 + trace: collect_build_postponed (1): re-evaluate existing dependents for {bar tex^ | libbar->{bar/1,1 tex/1,1}} trace: collect_build: add tex/1.0.0 trace: collect_build_prerequisites: reeval tex/1.0.0 %.* trace: collect_build: pick libbar/0.1.0 over libbar/1.0.0 - trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {bar | libbar->{bar/1,1}} + trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {bar tex^ | libbar->{bar/1,1 tex/1,1}} trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {bar tex^ | libbar->{bar/1,1 tex/1,1}} trace: collect_build_prerequisites: re-evaluated tex/1.0.0 trace: collect_build_postponed (1): cfg-negotiate begin {bar tex^ | libbar->{bar/1,1 tex/1,1}} @@ -6780,13 +7050,13 @@ test.arguments += --sys-no-query %.* trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0 trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of dependent tex/1.0.0 - trace: postponed_configurations::add: add {tex 2,1: libfoo} to {tex^ | libfoo->{tex/2,1}} + trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}} trace: collect_build_prerequisites: postpone tex/1.0.0 trace: collect_build_postponed (1): cfg-negotiate end {bar tex^ | libbar->{bar/1,1 tex/1,1}}! - trace: collect_build_postponed (2): begin {tex^ | libfoo->{tex/2,1}} + trace: collect_build_postponed (2): begin {tex | libfoo->{tex/2,1}} %.* trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo - trace: collect_build_postponed (2): cfg-negotiate begin {tex^ | libfoo->{tex/2,1}} + trace: collect_build_postponed (2): cfg-negotiate begin {tex | libfoo->{tex/2,1}} %.* trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: begin libfoo/0.1.0 @@ -6795,13 +7065,22 @@ test.arguments += --sys-no-query trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/1.0.0 trace: collect_build_prerequisites: resume tex/1.0.0 trace: collect_build_prerequisites: end tex/1.0.0 - trace: collect_build_postponed (2): cfg-negotiate end {tex^ | libfoo->{tex/2,1}}! - trace: collect_build_postponed (2): end {tex^ | libfoo->{tex/2,1}} - trace: collect_build_postponed (1): end {bar | libbar->{bar/1,1}} + trace: collect_build_postponed (2): cfg-negotiate end {tex | libfoo->{tex/2,1}}! + trace: collect_build_postponed (2): end {tex | libfoo->{tex/2,1}} + trace: collect_build_postponed (1): end {bar tex^ | libbar->{bar/1,1 tex/1,1}} trace: collect_build_postponed (0): end %.* trace: execute_plan: simulate: yes %.* + build plan: + downgrade libfoo/0.1.0 + config.libfoo.extras=true (set by tex) + downgrade libbar/0.1.0 (required by bar, tex) + config.libbar.extras=true (set by bar) + reconfigure tex/1.0.0 (dependent of libbar) + new bar/0.1.0 + trace: execute_plan: simulate: no + %.* EOE $pkg_status -r >>EOO; @@ -6922,49 +7201,22 @@ test.arguments += --sys-no-query %.* trace: collect_build: add libbox/0.1.0 %.* - trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of existing dependent bax/1.0.0 - trace: postponed_configurations::add: create {bax^ | libbox->{bax/2,1}} - trace: collect_build_postponed (0): begin - trace: collect_build_postponed (1): begin {bax^ | libbox->{bax/2,1}} - %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libbox->{bax/2,1}} - %.* - trace: collect_build: add bax/1.0.0 - trace: collect_build_prerequisites: reeval bax/1.0.0 - %.* - trace: collect_build: add libfoo/1.0.0 - %.* - trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0 - trace: collect_build: add libbar/1.0.0 - trace: postponed_configurations::add: add {bax^ 2,1: libbox libbar} to {bax^ | libbox->{bax/2,1}} - trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}} - trace: collect_build_prerequisites: re-evaluated bax/1.0.0 - %.* - trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar - trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}} - %.* - trace: collect_build: add baz/1.0.0 - trace: collect_build_prerequisites: reeval baz/1.0.0 - %.* - trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}} - trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libbox->{bax/2,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}} - trace: collect_build_prerequisites: re-evaluated baz/1.0.0 - %.* - trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libfoo - trace: collect_build_postponed (1): cannot re-evaluate dependent bax to dependency index 1 since it is already re-evaluated to greater index 2 in {bax^ baz^ | libbox->{bax/2,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}, throwing postpone_position - trace: pkg_build: collection failed due to earlier dependency position, retry from scratch + trace: collect_build_prerequisites: pre-reeval bax/1.0.0 %.* - trace: pkg_build: refine package collection/plan execution from scratch - %.* - trace: collect_build: add libbox/0.1.0 - %.* - trace: collect_build_prerequisites: replace dependency at index 2 of existing dependent bax/1.0.0 with dependency libfoo/1.0.0 at index 1 + trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1 trace: collect_build: add libfoo/1.0.0 - trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0 + trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0 due to dependency libbox/0.1.0 trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}} trace: collect_build_postponed (0): begin trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}} %.* + trace: collect_build_prerequisites: pre-reeval bax/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1 + %.* + trace: collect_build_prerequisites: pre-reeval baz/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated baz/1.0.0: 1,1 trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}} trace: collect_build: add bax/1.0.0 trace: collect_build_prerequisites: reeval bax/1.0.0 @@ -7000,6 +7252,12 @@ test.arguments += --sys-no-query trace: collect_build_postponed (0): cfg-negotiation of {bax^ | libfoo->{bax/1,1}} failed due to dependent bax, refining configuration trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}} %.* + trace: collect_build_prerequisites: pre-reeval bax/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1 + trace: collect_build_prerequisites: pre-reeval baz/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated baz/1.0.0: 1,1 trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}} trace: collect_build: add bax/1.0.0 trace: collect_build_prerequisites: reeval bax/1.0.0 @@ -7018,7 +7276,6 @@ test.arguments += --sys-no-query trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}} - %.* trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: skip configured libfoo/1.0.0 trace: collect_build_prerequisites: skip configured libbar/1.0.0 @@ -7045,6 +7302,12 @@ test.arguments += --sys-no-query %.* trace: execute_plan: simulate: yes %.* + build plan: + downgrade libbox/0.1.0 + config.libbox.extras=true (set by bax) + reconfigure bax/1.0.0 (dependent of libfoo) + trace: execute_plan: simulate: no + %.* EOE $pkg_status -r >>EOO; @@ -7092,61 +7355,35 @@ test.arguments += --sys-no-query trace: collect_build_postponed (0): begin trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}} %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}} + trace: collect_build_prerequisites: pre-reeval bax/1.0.0 %.* + trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1 + trace: collect_build: add libfoo/1.0.0 + trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}} trace: collect_build: add bax/1.0.0 trace: collect_build_prerequisites: reeval bax/1.0.0 %.* - trace: collect_build: add libfoo/1.0.0 - %.* - trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0 - trace: collect_build: add libbar/1.0.0 - trace: postponed_configurations::add: add {bax^ 2,1: libbox libbar} to {box | libbox->{box/1,1}} - trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}} + trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}} + trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}} trace: collect_build_prerequisites: re-evaluated bax/1.0.0 + trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}} %.* - trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar - trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}} - %.* - trace: collect_build: add baz/1.0.0 - trace: collect_build_prerequisites: reeval baz/1.0.0 - %.* - trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}} - trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}} - trace: collect_build_prerequisites: re-evaluated baz/1.0.0 - %.* - trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libfoo - trace: collect_build_postponed (1): cannot re-evaluate dependent bax to dependency index 1 since it is already re-evaluated to greater index 2 in {bax^ baz^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}, throwing postpone_position - trace: pkg_build: collection failed due to earlier dependency position, retry from scratch - %.* - trace: pkg_build: refine package collection/plan execution from scratch - %.* - trace: collect_build: add box/0.1.0 - trace: collect_build_prerequisites: begin box/0.1.0 - %.* - trace: collect_build: add libbox/0.1.0 - info: package box dependency on (libbox == 0.1.0) is forcing downgrade of libbox/1.0.0 to 0.1.0 - trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent box/0.1.0 - trace: postponed_configurations::add: create {box | libbox->{box/1,1}} - trace: collect_build_prerequisites: postpone box/0.1.0 - trace: collect_build_postponed (0): begin - trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}} + trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies + trace: collect_build_prerequisites: begin libbox/0.1.0 + trace: collect_build_prerequisites: end libbox/0.1.0 + trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents + trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.1.0 + trace: collect_build_prerequisites: resume box/0.1.0 + trace: collect_build_prerequisites: end box/0.1.0 + trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}! + trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}} %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}} - trace: collect_build_postponed (1): pos-postpone existing dependent bax re-evaluation to dependency index 2 due to recorded index 1, skipping {box | libbox->{box/1,1}} - trace: collect_build_postponed (0): replace dependency at index 2 of existing dependent bax/1.0.0 with dependency libfoo/1.0.0 at index 1 - trace: collect_build: add libfoo/1.0.0 - trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}} - trace: collect_build_postponed (0): postpone cfg-negotiation of {box | libbox->{box/1,1}} - trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}} + trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}} - trace: collect_build: add bax/1.0.0 - trace: collect_build_prerequisites: reeval bax/1.0.0 + trace: collect_build_prerequisites: pre-reeval baz/1.0.0 %.* - trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}} - trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}} - trace: collect_build_prerequisites: re-evaluated bax/1.0.0 + trace: collect_build_prerequisites: pre-reevaluated baz/1.0.0: 1,1 + trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}} trace: collect_build: add baz/1.0.0 trace: collect_build_prerequisites: reeval baz/1.0.0 %.* @@ -7155,50 +7392,58 @@ test.arguments += --sys-no-query trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}} trace: collect_build_prerequisites: re-evaluated baz/1.0.0 %.* - trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar - trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar - trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}} + trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libbar + trace: collect_build_postponed (2): skip being built existing dependent baz of dependency libbar + trace: collect_build_postponed (2): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}} %.* - trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies + trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: skip configured libfoo/1.0.0 trace: collect_build_prerequisites: skip configured libbar/1.0.0 - trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents - trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0 + trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents + trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0 trace: collect_build_prerequisites: resume bax/1.0.0 %.* trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0 trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0 trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0 - trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}? - trace: postponed_configurations::add: merge {box | libbox->{box/1,1}} into {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1}}? - trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1 box/1,1}}?, throwing merge_configuration - trace: collect_build_postponed (0): cfg-negotiation of {bax^ | libfoo->{bax/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1 box/1,1}}? - trace: collect_build_postponed (0): force-merge {box | libbox->{box/1,1}} into {bax^ | libfoo->{bax/1,1}} - trace: collect_build_postponed (1): begin {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}} + trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {box | libbox->{box/1,1}}! + trace: postponed_configurations::add: merge {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}? into {bax box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}! + trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax baz^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 baz/1,1} libfoo->{bax/1,1 baz/1,1}}!, throwing merge_configuration + trace: collect_build_postponed (0): cfg-negotiation of {box | libbox->{box/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax baz^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 baz/1,1} libfoo->{bax/1,1 baz/1,1}}! + trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}} + %.* + trace: collect_build_prerequisites: pre-reeval bax/1.0.0 %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}} + trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1 + trace: collect_build: add libfoo/1.0.0 + trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}} trace: collect_build: add bax/1.0.0 trace: collect_build_prerequisites: reeval bax/1.0.0 %.* - trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}} (shadow cluster-based) - trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}} + trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {box | libbox->{box/1,1}} (shadow cluster-based) + trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ box | libbox->{box/1,1} libfoo->{bax/1,1}} trace: collect_build_prerequisites: re-evaluated bax/1.0.0 + %.* + trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libfoo + trace: collect_build_prerequisites: pre-reeval baz/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated baz/1.0.0: 1,1 + trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ box | libbox->{box/1,1} libfoo->{bax/1,1}} trace: collect_build: add baz/1.0.0 trace: collect_build_prerequisites: reeval baz/1.0.0 %.* trace: collect_build: add libbar/1.0.0 - trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}} (shadow cluster-based) - trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbox->{box/1,1} libbar->{baz/1,1}} + trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ box | libbox->{box/1,1} libfoo->{bax/1,1}} (shadow cluster-based) + trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ box | libbox->{box/1,1} libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}} trace: collect_build_prerequisites: re-evaluated baz/1.0.0 %.* trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar - trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbox->{box/1,1} libbar->{baz/1,1}} - %.* + trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ box | libbox->{box/1,1} libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}} trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies - trace: collect_build_prerequisites: skip configured libfoo/1.0.0 trace: collect_build_prerequisites: begin libbox/0.1.0 trace: collect_build_prerequisites: end libbox/0.1.0 + trace: collect_build_prerequisites: skip configured libfoo/1.0.0 trace: collect_build_prerequisites: skip configured libbar/1.0.0 trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0 @@ -7207,7 +7452,7 @@ test.arguments += --sys-no-query trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0 trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0 trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0 - trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbox->{box/1,1} libbar->{baz/1,1}}? (shadow cluster-based) + trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ box | libbox->{box/1,1} libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}? (shadow cluster-based) trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is shadow-negotiated trace: collect_build_prerequisites: dependency libbox/0.1.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping @@ -7218,12 +7463,19 @@ test.arguments += --sys-no-query trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.1.0 trace: collect_build_prerequisites: resume box/0.1.0 trace: collect_build_prerequisites: end box/0.1.0 - trace: collect_build_postponed (1): cfg-negotiate end {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 baz/1,1}}! - trace: collect_build_postponed (1): end {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}} + trace: collect_build_postponed (1): cfg-negotiate end {bax^ baz^ box | libbox->{bax/2,1 box/1,1} libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1}}! + trace: collect_build_postponed (1): end {box | libbox->{box/1,1}} trace: collect_build_postponed (0): end %.* trace: execute_plan: simulate: yes %.* + build plan: + downgrade libbox/0.1.0 (required by bax, box) + config.libbox.extras=true (set by box) + reconfigure bax/1.0.0 (dependent of libbox) + new box/0.1.0 + trace: execute_plan: simulate: no + %.* EOE $pkg_status -r >>EOO; @@ -7261,47 +7513,21 @@ test.arguments += --sys-no-query %.* trace: collect_build: add libbox/0.1.0 %.* - trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of existing dependent bax/1.0.0 - trace: postponed_configurations::add: create {bax^ | libbox->{bax/2,1}} - trace: collect_build_postponed (0): begin - trace: collect_build_postponed (1): begin {bax^ | libbox->{bax/2,1}} - %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libbox->{bax/2,1}} - %.* - trace: collect_build: add bax/1.0.0 - trace: collect_build_prerequisites: reeval bax/1.0.0 + trace: collect_build_prerequisites: pre-reeval bax/1.0.0 %.* + trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1 trace: collect_build: add libfoo/1.0.0 - %.* - trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0 - trace: collect_build: add libbar/1.0.0 - trace: postponed_configurations::add: add {bax^ 2,1: libbox libbar} to {bax^ | libbox->{bax/2,1}} - trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}} - trace: collect_build_prerequisites: re-evaluated bax/1.0.0 - %.* - trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar - trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}} - trace: collect_build_prerequisites: reeval baz/1.0.0 - %.* - trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}} - trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libbox->{bax/2,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}} - trace: collect_build_prerequisites: re-evaluated baz/1.0.0 - %.* - trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libfoo - trace: collect_build_postponed (1): cannot re-evaluate dependent bax to dependency index 1 since it is already re-evaluated to greater index 2 in {bax^ baz^ | libbox->{bax/2,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}, throwing postpone_position - trace: pkg_build: collection failed due to earlier dependency position, retry from scratch - %.* - trace: pkg_build: refine package collection/plan execution from scratch - %.* - trace: collect_build: add libbox/0.1.0 - %.* - trace: collect_build_prerequisites: replace dependency at index 2 of existing dependent bax/1.0.0 with dependency libfoo/1.0.0 at index 1 - trace: collect_build: add libfoo/1.0.0 - trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0 + trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0 due to dependency libbox/0.1.0 trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}} trace: collect_build_postponed (0): begin trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}} %.* + trace: collect_build_prerequisites: pre-reeval bax/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1 + trace: collect_build_prerequisites: pre-reeval baz/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated baz/1.0.0: 1,1 trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}} trace: collect_build: add bax/1.0.0 trace: collect_build_prerequisites: reeval bax/1.0.0 @@ -7336,6 +7562,12 @@ test.arguments += --sys-no-query trace: collect_build_postponed (0): cfg-negotiation of {bax^ | libfoo->{bax/1,1}} failed due to dependent bax, refining configuration trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}} %.* + trace: collect_build_prerequisites: pre-reeval bax/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1 + trace: collect_build_prerequisites: pre-reeval baz/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated baz/1.0.0: 1,1 trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}} trace: collect_build: add bax/1.0.0 trace: collect_build_prerequisites: reeval bax/1.0.0 @@ -7353,7 +7585,6 @@ test.arguments += --sys-no-query trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}} - %.* trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: skip configured libfoo/1.0.0 trace: collect_build_prerequisites: skip configured libbar/1.0.0 @@ -7401,14 +7632,19 @@ test.arguments += --sys-no-query %.* trace: collect_build: add libbox/0.1.0 %.* - trace: collect_build_prerequisites: replace dependency at index 2 of existing dependent bax/1.0.0 with dependency libfoo/1.0.0 at index 1 + trace: collect_build_prerequisites: pre-reeval bax/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1 trace: collect_build: add libfoo/1.0.0 - trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0 + trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0 due to dependency libbox/0.1.0 trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}} trace: collect_drop: overwrite baz trace: collect_build_postponed (0): begin trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}} %.* + trace: collect_build_prerequisites: pre-reeval bax/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1 trace: collect_build_postponed (1): skip being dropped existing dependent baz of dependency libfoo trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}} trace: collect_build: add bax/1.0.0 @@ -7418,7 +7654,6 @@ test.arguments += --sys-no-query trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}} trace: collect_build_prerequisites: re-evaluated bax/1.0.0 trace: collect_build_postponed (1): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}} - %.* trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: skip configured libfoo/1.0.0 trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents @@ -7439,7 +7674,6 @@ test.arguments += --sys-no-query trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libbar trace: collect_build_postponed (2): skip being dropped existing dependent baz of dependency libbar trace: collect_build_postponed (2): cfg-negotiate begin {bax | libbox->{bax/2,1} libbar->{bax/2,1}} - %.* trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: begin libbox/0.1.0 trace: collect_build_prerequisites: end libbox/0.1.0 @@ -7455,6 +7689,13 @@ test.arguments += --sys-no-query %.* trace: execute_plan: simulate: yes %.* + build plan: + downgrade libbox/0.1.0 + config.libbox.extras=true (set by bax) + reconfigure bax/1.0.0 (dependent of libfoo) + drop baz/1.0.0 (unused) + trace: execute_plan: simulate: no + %.* EOE $pkg_status -r >>EOO; @@ -9792,66 +10033,19 @@ test.arguments += --sys-no-query %.* trace: collect_build: add tex/0.3.0 %.* - trace: collect_build_prerequisites: cfg-postpone dependency tex/0.3.0 of existing dependent tix/1.0.0 - trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}} - trace: collect_build_postponed (0): begin - trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}} - %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}} - %.* - trace: collect_build: add tix/1.0.0 - trace: collect_build_prerequisites: reeval tix/1.0.0 - %.* - trace: collect_build: add libbar/1.0.0 - %.* - trace: collect_build: pick tex/0.3.0 over tex/1.0.0 - trace: postponed_configurations::add: add {tix^ 2,1: tex} to {tix^ | tex->{tix/2,1}} - trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | tex->{tix/2,1}} - trace: collect_build_prerequisites: re-evaluated tix/1.0.0 - trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | tex->{tix/2,1}} - %.* - trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies - trace: collect_build_prerequisites: begin tex/0.3.0 - %.* - trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/0.3.0 - trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}} - trace: collect_build_prerequisites: postpone tex/0.3.0 - trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents - trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0 - trace: collect_build_prerequisites: resume tix/1.0.0 - trace: collect_build_prerequisites: end tix/1.0.0 - trace: collect_build_postponed (1): cfg-negotiate end {tix^ | tex->{tix/2,1}}! - trace: collect_build_postponed (2): begin {tex | libbar->{tex/1,1}} - %.* - trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libbar - trace: collect_build_postponed (2): re-evaluate existing dependents for {tex | libbar->{tex/1,1}} - trace: collect_build_postponed (2): cannot re-evaluate dependent tix to dependency index 1 due to greater dependency index 2 in {tix^ | tex->{tix/2,1}}!, throwing postpone_position - trace: pkg_build: collection failed due to earlier dependency position, retry from scratch - %.* - trace: pkg_build: refine package collection/plan execution from scratch - %.* - trace: collect_build: add tex/0.3.0 - %.* - trace: collect_build_prerequisites: cfg-postpone dependency tex/0.3.0 of existing dependent tix/1.0.0 - trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}} - trace: collect_build_postponed (0): begin - trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}} - %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}} - trace: collect_build_postponed (1): pos-postpone existing dependent tix re-evaluation to dependency index 2 due to recorded index 1, skipping {tix^ | tex->{tix/2,1}} - trace: collect_build_postponed (0): postpone cfg-negotiation of {tix^ | tex->{tix/2,1}} - trace: collect_build_postponed (0): non-negotiated clusters left and non-replace postponed positions are present, overriding first encountered non-replace position to replace - trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}} + trace: collect_build_prerequisites: pre-reeval tix/1.0.0 %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}} - trace: collect_build_postponed (1): pos-postpone existing dependent tix re-evaluation to dependency index 2 due to recorded index 1, skipping {tix^ | tex->{tix/2,1}} - trace: collect_build_postponed (0): replace dependency at index 2 of existing dependent tix/1.0.0 with dependency libbar/1.0.0 at index 1 + trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1 trace: collect_build: add libbar/1.0.0 + trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tix/1.0.0 due to dependency tex/0.3.0 trace: postponed_configurations::add: create {tix^ | libbar->{tix/1,1}} - trace: collect_build_postponed (0): postpone cfg-negotiation of {tix^ | tex->{tix/2,1}} + trace: collect_build_postponed (0): begin trace: collect_build_postponed (1): begin {tix^ | libbar->{tix/1,1}} %.* trace: collect_build_postponed (1): skip being built existing dependent tex of dependency libbar + trace: collect_build_prerequisites: pre-reeval tix/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1 trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | libbar->{tix/1,1}} trace: collect_build: add tix/1.0.0 trace: collect_build_prerequisites: reeval tix/1.0.0 @@ -9869,13 +10063,13 @@ test.arguments += --sys-no-query %.* trace: collect_build: pick tex/0.3.0 over tex/1.0.0 trace: collect_build_prerequisites: cfg-postpone dependency tex/0.3.0 of dependent tix/1.0.0 - trace: postponed_configurations::add: add {tix 2,1: tex} to {tix^ | tex->{tix/2,1}} + trace: postponed_configurations::add: create {tix | tex->{tix/2,1}} trace: collect_build_prerequisites: postpone tix/1.0.0 trace: collect_build_postponed (1): cfg-negotiate end {tix^ | libbar->{tix/1,1}}! - trace: collect_build_postponed (2): begin {tix^ | tex->{tix/2,1}} + trace: collect_build_postponed (2): begin {tix | tex->{tix/2,1}} %.* trace: collect_build_postponed (2): skip being built existing dependent tix of dependency tex - trace: collect_build_postponed (2): cfg-negotiate begin {tix^ | tex->{tix/2,1}} + trace: collect_build_postponed (2): cfg-negotiate begin {tix | tex->{tix/2,1}} %.* trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: begin tex/0.3.0 @@ -9893,7 +10087,7 @@ test.arguments += --sys-no-query trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0 trace: collect_build_prerequisites: resume tix/1.0.0 trace: collect_build_prerequisites: end tix/1.0.0 - trace: collect_build_postponed (2): cfg-negotiate end {tix^ | tex->{tix/2,1}}! + trace: collect_build_postponed (2): cfg-negotiate end {tix | tex->{tix/2,1}}! trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}} %.* trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo @@ -9907,12 +10101,18 @@ test.arguments += --sys-no-query trace: collect_build_prerequisites: end tex/0.3.0 trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}! trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}} - trace: collect_build_postponed (2): end {tix^ | tex->{tix/2,1}} + trace: collect_build_postponed (2): end {tix | tex->{tix/2,1}} trace: collect_build_postponed (1): end {tix^ | libbar->{tix/1,1}} trace: collect_build_postponed (0): end %.* trace: execute_plan: simulate: yes %.* + build plan: + downgrade tex/0.3.0 + config.tex.extras=true (set by tix) + reconfigure tix/1.0.0 (dependent of libbar) + trace: execute_plan: simulate: no + %.* EOE $pkg_drop tex tix @@ -9946,52 +10146,80 @@ test.arguments += --sys-no-query trace: collect_build: add tex/0.1.0 trace: collect_build_prerequisites: skip configured tix/1.0.0 %.* - trace: collect_build_prerequisites: cfg-postpone dependency tex/0.1.0 of existing dependent tix/1.0.0 - trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}} + trace: collect_build_prerequisites: pre-reeval tix/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1 + trace: collect_build: add libbar/1.0.0 + trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tix/1.0.0 due to dependency tex/0.1.0 + trace: postponed_configurations::add: create {tix^ | libbar->{tix/1,1}} trace: collect_build_postponed (0): begin - trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}} + trace: collect_build_postponed (1): begin {tix^ | libbar->{tix/1,1}} %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}} - trace: collect_build_prerequisites: reeval tix/1.0.0 + trace: collect_build_postponed (1): skip being built existing dependent tex of dependency libbar + trace: collect_build_prerequisites: pre-reeval tix/1.0.0 %.* - trace: collect_build: add libbar/1.0.0 + trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1 + trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | libbar->{tix/1,1}} + trace: collect_build_prerequisites: reeval tix/1.0.0 %.* - trace: collect_build: pick tex/0.1.0 over tex/1.0.0 - trace: postponed_configurations::add: add {tix^ 2,1: tex} to {tix^ | tex->{tix/2,1}} - trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | tex->{tix/2,1}} + trace: postponed_configurations::add: add {tix^ 1,1: libbar} to {tix^ | libbar->{tix/1,1}} + trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | libbar->{tix/1,1}} trace: collect_build_prerequisites: re-evaluated tix/1.0.0 - trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | tex->{tix/2,1}} + trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | libbar->{tix/1,1}} %.* trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies + trace: collect_build_prerequisites: skip configured libbar/1.0.0 + trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents + trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0 + trace: collect_build_prerequisites: resume tix/1.0.0 + %.* + trace: collect_build: pick tex/0.1.0 over tex/1.0.0 + trace: collect_build_prerequisites: cfg-postpone dependency tex/0.1.0 of dependent tix/1.0.0 + trace: postponed_configurations::add: create {tix | tex->{tix/2,1}} + trace: collect_build_prerequisites: postpone tix/1.0.0 + trace: collect_build_postponed (1): cfg-negotiate end {tix^ | libbar->{tix/1,1}}! + trace: collect_build_postponed (2): begin {tix | tex->{tix/2,1}} + %.* + trace: collect_build_postponed (2): skip being built existing dependent tix of dependency tex + trace: collect_build_postponed (2): cfg-negotiate begin {tix | tex->{tix/2,1}} + %.* + trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: begin tex/0.1.0 %.* trace: collect_build: add libfoo/1.0.0 trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/0.1.0 trace: postponed_configurations::add: create {tex | libfoo->{tex/1,1}} trace: collect_build_prerequisites: postpone tex/0.1.0 - trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents - trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0 + trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents + trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0 trace: collect_build_prerequisites: resume tix/1.0.0 trace: collect_build_prerequisites: end tix/1.0.0 - trace: collect_build_postponed (1): cfg-negotiate end {tix^ | tex->{tix/2,1}}! - trace: collect_build_postponed (2): begin {tex | libfoo->{tex/1,1}} + trace: collect_build_postponed (2): cfg-negotiate end {tix | tex->{tix/2,1}}! + trace: collect_build_postponed (3): begin {tex | libfoo->{tex/1,1}} %.* - trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo - trace: collect_build_postponed (2): cfg-negotiate begin {tex | libfoo->{tex/1,1}} + trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo + trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/1,1}} %.* - trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies + trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: skip configured libfoo/1.0.0 - trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents - trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/0.1.0 + trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents + trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/0.1.0 trace: collect_build_prerequisites: resume tex/0.1.0 trace: collect_build_prerequisites: end tex/0.1.0 - trace: collect_build_postponed (2): cfg-negotiate end {tex | libfoo->{tex/1,1}}! - trace: collect_build_postponed (2): end {tex | libfoo->{tex/1,1}} - trace: collect_build_postponed (1): end {tix^ | tex->{tix/2,1}} + trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/1,1}}! + trace: collect_build_postponed (3): end {tex | libfoo->{tex/1,1}} + trace: collect_build_postponed (2): end {tix | tex->{tix/2,1}} + trace: collect_build_postponed (1): end {tix^ | libbar->{tix/1,1}} trace: collect_build_postponed (0): end %.* trace: execute_plan: simulate: yes %.* + build plan: + downgrade tex/0.1.0 + config.tex.extras=true (set by tix) + reconfigure/update tix/1.0.0 + trace: execute_plan: simulate: no + %.* EOE $pkg_drop tex tix @@ -10026,52 +10254,80 @@ test.arguments += --sys-no-query %.* trace: pkg_build: refine package collection/plan execution %.* - trace: collect_build_prerequisites: cfg-postpone dependency tex/0.1.0 of existing dependent tix/1.0.0 - trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}} + trace: collect_build_prerequisites: pre-reeval tix/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1 + trace: collect_build: add libbar/1.0.0 + trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tix/1.0.0 due to dependency tex/0.1.0 + trace: postponed_configurations::add: create {tix^ | libbar->{tix/1,1}} trace: collect_build_postponed (0): begin - trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}} + trace: collect_build_postponed (1): begin {tix^ | libbar->{tix/1,1}} %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}} - trace: collect_build_prerequisites: reeval tix/1.0.0 + trace: collect_build_postponed (1): skip being built existing dependent tex of dependency libbar + trace: collect_build_prerequisites: pre-reeval tix/1.0.0 %.* - trace: collect_build: add libbar/1.0.0 + trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1 + trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | libbar->{tix/1,1}} + trace: collect_build_prerequisites: reeval tix/1.0.0 %.* - trace: collect_build: pick tex/0.1.0 over tex/1.0.0 - trace: postponed_configurations::add: add {tix^ 2,1: tex} to {tix^ | tex->{tix/2,1}} - trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | tex->{tix/2,1}} + trace: postponed_configurations::add: add {tix^ 1,1: libbar} to {tix^ | libbar->{tix/1,1}} + trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | libbar->{tix/1,1}} trace: collect_build_prerequisites: re-evaluated tix/1.0.0 - trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | tex->{tix/2,1}} + trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | libbar->{tix/1,1}} %.* trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies + trace: collect_build_prerequisites: skip configured libbar/1.0.0 + trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents + trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0 + trace: collect_build_prerequisites: resume tix/1.0.0 + %.* + trace: collect_build: pick tex/0.1.0 over tex/1.0.0 + trace: collect_build_prerequisites: cfg-postpone dependency tex/0.1.0 of dependent tix/1.0.0 + trace: postponed_configurations::add: create {tix | tex->{tix/2,1}} + trace: collect_build_prerequisites: postpone tix/1.0.0 + trace: collect_build_postponed (1): cfg-negotiate end {tix^ | libbar->{tix/1,1}}! + trace: collect_build_postponed (2): begin {tix | tex->{tix/2,1}} + %.* + trace: collect_build_postponed (2): skip being built existing dependent tix of dependency tex + trace: collect_build_postponed (2): cfg-negotiate begin {tix | tex->{tix/2,1}} + %.* + trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: begin tex/0.1.0 %.* trace: collect_build: add libfoo/1.0.0 trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/0.1.0 trace: postponed_configurations::add: create {tex | libfoo->{tex/1,1}} trace: collect_build_prerequisites: postpone tex/0.1.0 - trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents - trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0 + trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents + trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0 trace: collect_build_prerequisites: resume tix/1.0.0 trace: collect_build_prerequisites: end tix/1.0.0 - trace: collect_build_postponed (1): cfg-negotiate end {tix^ | tex->{tix/2,1}}! - trace: collect_build_postponed (2): begin {tex | libfoo->{tex/1,1}} + trace: collect_build_postponed (2): cfg-negotiate end {tix | tex->{tix/2,1}}! + trace: collect_build_postponed (3): begin {tex | libfoo->{tex/1,1}} %.* - trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo - trace: collect_build_postponed (2): cfg-negotiate begin {tex | libfoo->{tex/1,1}} + trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo + trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/1,1}} %.* - trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies + trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: skip configured libfoo/1.0.0 - trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents - trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/0.1.0 + trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents + trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/0.1.0 trace: collect_build_prerequisites: resume tex/0.1.0 trace: collect_build_prerequisites: end tex/0.1.0 - trace: collect_build_postponed (2): cfg-negotiate end {tex | libfoo->{tex/1,1}}! - trace: collect_build_postponed (2): end {tex | libfoo->{tex/1,1}} - trace: collect_build_postponed (1): end {tix^ | tex->{tix/2,1}} + trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/1,1}}! + trace: collect_build_postponed (3): end {tex | libfoo->{tex/1,1}} + trace: collect_build_postponed (2): end {tix | tex->{tix/2,1}} + trace: collect_build_postponed (1): end {tix^ | libbar->{tix/1,1}} trace: collect_build_postponed (0): end %.* trace: execute_plan: simulate: yes %.* + build plan: + downgrade/unhold tex/0.1.0 + config.tex.extras=true (set by tix) + reconfigure/update tix/1.0.0 + trace: execute_plan: simulate: no + %.* EOE $pkg_drop tix @@ -10079,7 +10335,7 @@ test.arguments += --sys-no-query : dependency-downgrade-unhold-premature : - : As above but the dependency (tex) depends on libbar without + : As above but the dependency (tex/0.2.0) depends on libbar without : configuration clause. : { @@ -10107,54 +10363,82 @@ test.arguments += --sys-no-query %.* trace: pkg_build: refine package collection/plan execution %.* - trace: collect_build_prerequisites: cfg-postpone dependency tex/0.2.0 of existing dependent tix/1.0.0 - trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}} + trace: collect_build_prerequisites: pre-reeval tix/1.0.0 + %.* + trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1 + trace: collect_build: add libbar/1.0.0 + trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tix/1.0.0 due to dependency tex/0.2.0 + trace: postponed_configurations::add: create {tix^ | libbar->{tix/1,1}} trace: collect_build_postponed (0): begin - trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}} + trace: collect_build_postponed (1): begin {tix^ | libbar->{tix/1,1}} %.* - trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}} - trace: collect_build_prerequisites: reeval tix/1.0.0 + trace: collect_build_postponed (1): skip being built existing dependent tex of dependency libbar + trace: collect_build_prerequisites: pre-reeval tix/1.0.0 %.* - trace: collect_build: add libbar/1.0.0 + trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1 + trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | libbar->{tix/1,1}} + trace: collect_build_prerequisites: reeval tix/1.0.0 %.* - trace: collect_build: pick tex/0.2.0 over tex/1.0.0 - trace: postponed_configurations::add: add {tix^ 2,1: tex} to {tix^ | tex->{tix/2,1}} - trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | tex->{tix/2,1}} + trace: postponed_configurations::add: add {tix^ 1,1: libbar} to {tix^ | libbar->{tix/1,1}} + trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | libbar->{tix/1,1}} trace: collect_build_prerequisites: re-evaluated tix/1.0.0 - trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | tex->{tix/2,1}} + trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | libbar->{tix/1,1}} %.* trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies + trace: collect_build_prerequisites: skip configured libbar/1.0.0 + trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents + trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0 + trace: collect_build_prerequisites: resume tix/1.0.0 + %.* + trace: collect_build: pick tex/0.2.0 over tex/1.0.0 + trace: collect_build_prerequisites: cfg-postpone dependency tex/0.2.0 of dependent tix/1.0.0 + trace: postponed_configurations::add: create {tix | tex->{tix/2,1}} + trace: collect_build_prerequisites: postpone tix/1.0.0 + trace: collect_build_postponed (1): cfg-negotiate end {tix^ | libbar->{tix/1,1}}! + trace: collect_build_postponed (2): begin {tix | tex->{tix/2,1}} + %.* + trace: collect_build_postponed (2): skip being built existing dependent tix of dependency tex + trace: collect_build_postponed (2): cfg-negotiate begin {tix | tex->{tix/2,1}} + %.* + trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: begin tex/0.2.0 %.* - trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent tex/0.2.0 + trace: collect_build_prerequisites: dep-postpone dependency libbar/1.0.0 of dependent tex/0.2.0 %.* trace: collect_build: add libfoo/1.0.0 trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/0.2.0 trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}} trace: collect_build_prerequisites: postpone tex/0.2.0 - trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents - trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0 + trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents + trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0 trace: collect_build_prerequisites: resume tix/1.0.0 trace: collect_build_prerequisites: end tix/1.0.0 - trace: collect_build_postponed (1): cfg-negotiate end {tix^ | tex->{tix/2,1}}! - trace: collect_build_postponed (2): begin {tex | libfoo->{tex/2,1}} + trace: collect_build_postponed (2): cfg-negotiate end {tix | tex->{tix/2,1}}! + trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}} %.* - trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo - trace: collect_build_postponed (2): cfg-negotiate begin {tex | libfoo->{tex/2,1}} + trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo + trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}} %.* - trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies + trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies trace: collect_build_prerequisites: skip configured libfoo/1.0.0 - trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents - trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/0.2.0 + trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents + trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/0.2.0 trace: collect_build_prerequisites: resume tex/0.2.0 trace: collect_build_prerequisites: end tex/0.2.0 - trace: collect_build_postponed (2): cfg-negotiate end {tex | libfoo->{tex/2,1}}! - trace: collect_build_postponed (2): end {tex | libfoo->{tex/2,1}} - trace: collect_build_postponed (1): end {tix^ | tex->{tix/2,1}} + trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}! + trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}} + trace: collect_build_postponed (2): end {tix | tex->{tix/2,1}} + trace: collect_build_postponed (1): end {tix^ | libbar->{tix/1,1}} trace: collect_build_postponed (0): end %.* trace: execute_plan: simulate: yes %.* + build plan: + downgrade/unhold tex/0.2.0 + config.tex.extras=true (set by tix) + reconfigure/update tix/1.0.0 + trace: execute_plan: simulate: no + %.* EOE $pkg_drop tix @@ -12260,130 +12544,136 @@ test.arguments += --sys-no-query : or hang and ends up with an expected packages setup. : { - $clone_cfg; + +$clone_cfg - $* libfoo libbar ?libbaz/0.1.0 ?libbox/0.1.0 \ - foo fox fux fix fex bar baz bac bat bas bus \ - box bax bux bix bex boo biz buz buc tax tex \ - tix tiz toz tez tux dex dix diz dox 2>!; + : all-new + : + { + $clone_cfg; - $pkg_status -r >>EOO; - !libfoo configured 1.0.0 - !libbar configured 1.0.0 - !bat configured 1.0.0 - libbaz configured !0.1.0 available 1.0.0 - !tix configured 0.1.0 available 1.0.0 - !toz configured 0.1.0 available 1.0.0 0.2.0 - !tux configured 1.0.0 - libbox configured !0.1.0 available 1.0.0 - !tix configured 0.1.0 available 1.0.0 - !bar configured 1.0.0 - !libbar configured 1.0.0 - !bux configured 1.0.0 - !libbar configured 1.0.0 - !bex configured 1.0.0 - !libbar configured 1.0.0 - !boo configured 1.0.0 - !libbar configured 1.0.0 - !biz configured 1.0.0 - !boo configured 1.0.0 - !libbar configured 1.0.0 - !buz configured 1.0.0 - !bux configured 1.0.0 - !libbar configured 1.0.0 - !tez configured 1.0.0 + $* libfoo libbar ?libbaz/0.1.0 ?libbox/0.1.0 \ + foo fox fux fix fex bar baz bac bat bas bus \ + box bax bux bix bex boo biz buz buc tax tex \ + tix tiz toz tez tux dex dix diz dox 2>!; + + $pkg_status -r >>EOO; + !libfoo configured 1.0.0 !libbar configured 1.0.0 - libbox configured !0.1.0 available 1.0.0 + !bat configured 1.0.0 + libbaz configured !0.1.0 available 1.0.0 + !tix configured 0.1.0 available 1.0.0 !toz configured 0.1.0 available 1.0.0 0.2.0 - !bix configured 1.0.0 + !tux configured 1.0.0 + libbox configured !0.1.0 available 1.0.0 + !tix configured 0.1.0 available 1.0.0 !bar configured 1.0.0 !libbar configured 1.0.0 !bux configured 1.0.0 !libbar configured 1.0.0 - !libbar configured 1.0.0 - !foo configured 1.0.0 - !libfoo configured 1.0.0 - !fox configured 1.0.0 - !libfoo configured 1.0.0 - !fux configured 1.0.0 - !libfoo configured 1.0.0 - !baz configured 1.0.0 - !libbar configured 1.0.0 - !libfoo configured 1.0.0 - !bac configured 1.0.0 - !libbar configured 1.0.0 - libbaz configured !0.1.0 available 1.0.0 - !libfoo configured 1.0.0 - !fix configured 1.0.0 + !bex configured 1.0.0 + !libbar configured 1.0.0 + !boo configured 1.0.0 + !libbar configured 1.0.0 + !biz configured 1.0.0 + !boo configured 1.0.0 + !libbar configured 1.0.0 + !buz configured 1.0.0 + !bux configured 1.0.0 + !libbar configured 1.0.0 + !tez configured 1.0.0 + !libbar configured 1.0.0 + libbox configured !0.1.0 available 1.0.0 + !toz configured 0.1.0 available 1.0.0 0.2.0 + !bix configured 1.0.0 + !bar configured 1.0.0 + !libbar configured 1.0.0 + !bux configured 1.0.0 + !libbar configured 1.0.0 + !libbar configured 1.0.0 !foo configured 1.0.0 !libfoo configured 1.0.0 - !fex configured 1.0.0 - !foo configured 1.0.0 + !fox configured 1.0.0 !libfoo configured 1.0.0 - !libfoo configured 1.0.0 - !bus configured 1.0.0 - !foo configured 1.0.0 + !fux configured 1.0.0 + !libfoo configured 1.0.0 + !baz configured 1.0.0 + !libbar configured 1.0.0 + !libfoo configured 1.0.0 + !bac configured 1.0.0 + !libbar configured 1.0.0 + libbaz configured !0.1.0 available 1.0.0 + !libfoo configured 1.0.0 + !fix configured 1.0.0 + !foo configured 1.0.0 + !libfoo configured 1.0.0 + !fex configured 1.0.0 + !foo configured 1.0.0 + !libfoo configured 1.0.0 !libfoo configured 1.0.0 - libbaz configured !0.1.0 available 1.0.0 - !bas configured 1.0.0 !bus configured 1.0.0 !foo configured 1.0.0 !libfoo configured 1.0.0 libbaz configured !0.1.0 available 1.0.0 - !libbar configured 1.0.0 - !box configured 1.0.0 - !libbar configured 1.0.0 - !libfoo configured 1.0.0 - !bax configured 1.0.0 - !libbar configured 1.0.0 - libbox configured !0.1.0 available 1.0.0 - !libfoo configured 1.0.0 - !buc configured 1.0.0 - !bux configured 1.0.0 + !bas configured 1.0.0 + !bus configured 1.0.0 + !foo configured 1.0.0 + !libfoo configured 1.0.0 + libbaz configured !0.1.0 available 1.0.0 !libbar configured 1.0.0 - !libfoo configured 1.0.0 - !tax configured 1.0.0 - !libbar configured 1.0.0 - !libfoo configured 1.0.0 - !tex configured 1.0.0 - !libbar configured 1.0.0 - !libfoo configured 1.0.0 - !tiz configured 1.0.0 - !libbar configured 1.0.0 + !box configured 1.0.0 + !libbar configured 1.0.0 + !libfoo configured 1.0.0 + !bax configured 1.0.0 + !libbar configured 1.0.0 + libbox configured !0.1.0 available 1.0.0 + !libfoo configured 1.0.0 + !buc configured 1.0.0 + !bux configured 1.0.0 + !libbar configured 1.0.0 + !libfoo configured 1.0.0 + !tax configured 1.0.0 + !libbar configured 1.0.0 + !libfoo configured 1.0.0 !tex configured 1.0.0 !libbar configured 1.0.0 !libfoo configured 1.0.0 - !dex configured 1.0.0 - !bar configured 1.0.0 + !tiz configured 1.0.0 !libbar configured 1.0.0 - !libfoo configured 1.0.0 - !dox configured 1.0.0 + !tex configured 1.0.0 + !libbar configured 1.0.0 + !libfoo configured 1.0.0 !dex configured 1.0.0 !bar configured 1.0.0 !libbar configured 1.0.0 !libfoo configured 1.0.0 - !dix configured 1.0.0 - !dox configured 1.0.0 - !dex configured 1.0.0 - !bar configured 1.0.0 - !libbar configured 1.0.0 - !libfoo configured 1.0.0 - !libbar configured 1.0.0 - libbox configured !0.1.0 available 1.0.0 - !diz configured 1.0.0 !dox configured 1.0.0 !dex configured 1.0.0 !bar configured 1.0.0 !libbar configured 1.0.0 !libfoo configured 1.0.0 - !libbar configured 1.0.0 - libbox configured !0.1.0 available 1.0.0 - EOO + !dix configured 1.0.0 + !dox configured 1.0.0 + !dex configured 1.0.0 + !bar configured 1.0.0 + !libbar configured 1.0.0 + !libfoo configured 1.0.0 + !libbar configured 1.0.0 + libbox configured !0.1.0 available 1.0.0 + !diz configured 1.0.0 + !dox configured 1.0.0 + !dex configured 1.0.0 + !bar configured 1.0.0 + !libbar configured 1.0.0 + !libfoo configured 1.0.0 + !libbar configured 1.0.0 + libbox configured !0.1.0 available 1.0.0 + EOO - $pkg_drop libfoo libbar foo fox fux fix fex bar \ - baz bac bat bas bus box bax bux bix bex \ - boo biz buz buc tax tex tix tiz toz tez \ - tux dex dix diz dox + $pkg_drop libfoo libbar foo fox fux fix fex bar \ + baz bac bat bas bus box bax bux bix bex \ + boo biz buz buc tax tex tix tiz toz tez \ + tux dex dix diz dox + } } } |