diff options
Diffstat (limited to 'bpkg/pkg-configure.cxx')
-rw-r--r-- | bpkg/pkg-configure.cxx | 739 |
1 files changed, 613 insertions, 126 deletions
diff --git a/bpkg/pkg-configure.cxx b/bpkg/pkg-configure.cxx index a86752e..eb5b85b 100644 --- a/bpkg/pkg-configure.cxx +++ b/bpkg/pkg-configure.cxx @@ -3,11 +3,23 @@ #include <bpkg/pkg-configure.hxx> +#include <libbuild2/types.hxx> +#include <libbuild2/utility.hxx> +#include <libbuild2/diagnostics.hxx> + +#include <libbuild2/file.hxx> +#include <libbuild2/scope.hxx> +#include <libbuild2/operation.hxx> +#include <libbuild2/config/operation.hxx> + +#include <bpkg/bpkg.hxx> // build2_init(), etc + #include <bpkg/package.hxx> #include <bpkg/package-odb.hxx> #include <bpkg/database.hxx> #include <bpkg/diagnostics.hxx> #include <bpkg/satisfaction.hxx> +#include <bpkg/package-query.hxx> #include <bpkg/manifest-utility.hxx> #include <bpkg/pkg-verify.hxx> @@ -18,32 +30,9 @@ using namespace butl; namespace bpkg { - // 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. See - // pkg_configure() for the semantics of the dependency list. Fail if for - // some of the dependency alternative lists there is no satisfactory - // alternative (all its dependencies are configured, satisfy the respective - // constraints, etc). - // - struct configure_prerequisites_result - { - package_prerequisites prerequisites; - 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 - // not the project variables for the specified package (module - // configuration variables, etc). Thus, it is not parallel to the - // config_variables member. - // - vector<config_variable> config_sources; // Note: name and source. - }; + static optional<version_constraint> absent_constraint; - // Note: loads selected packages. - // - static configure_prerequisites_result + configure_prerequisites_result pkg_configure_prerequisites (const common_options& o, database& db, transaction&, @@ -52,16 +41,94 @@ namespace bpkg package_skeleton&& ps, const vector<package_name>* prev_prereqs, bool simulate, - const function<find_database_function>& fdb) + const function<find_database_function>& fdb, + const function<find_package_state_function>& fps, + const vector<package_key>* unconstrain_deps) { + tracer trace ("pkg_configure_prerequisites"); + + // Unconstraining dependencies are only allowed in the simulation mode. + // + assert (unconstrain_deps == nullptr || simulate); + + // No use case for both being specified. + // + assert (alts == nullptr || prev_prereqs == nullptr); + + tracer_guard tg (db, trace); + package_prerequisites prereqs; + vector<size_t> dep_alts; strings vars; + // Notes on the buildfile clauses evaluation: + // + // - In the manual configuration mode (alts == NULL, prev_prereqs == NULL) + // we always evaluate the enable and reflect clauses. We, however, fail + // if any of the prefer or require clauses are specified in any of the + // enabled dependency alternatives, assuming that this package didn't + // negotiate its preferences/requirements for the dependency + // configurations. + // + // Note that evaluating the require and prefer clauses in this case is + // meaningless since we don't reconfigure the dependencies nor negotiate + // configurations with other dependents. What we should probably do is + // load configurations of the dependencies and use them while evaluating + // the dependent's enable and reflect clauses as we go along. Probably + // we should still evaluate the accept clauses to make sure that the + // dependency is configured acceptably for the dependent. + // + // - In the pre-selected alternatives mode (alts != NULL, prev_prereqs == + // NULL) we don't evaluate the enable, prefer, and require clauses since + // they have already been evaluated as a part of the dependency + // alternatives selection and the dependency configurations negotiation. + // We, however always evaluate the reflect clauses. + // + // - In the reconfiguration mode (prev_prereqs != NULL, alts == NULL) we + // don't evaluate the prefer and require clauses, assuming that was done + // 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. 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); + + // In the reconfiguration mode keep track of configuration variable + // prefixes (in the 'config.<dependency>.' form) for dependencies in the + // selected alternatives with the prefer or require clauses specified and + // fail if any enable or reflect clause refers to them. + // + // Note that the enable and reflect clauses may only refer to dependency + // configuration variables of already selected alternatives with the + // prefer or require clauses specified. + // + vector<string> banned_var_prefixes; + + auto verify_banned_vars = [&ps, + &banned_var_prefixes] (const string& clause, + const char* what) + { + for (const string& p: banned_var_prefixes) + { + if (clause.find (p) != string::npos) + { + fail << "unable to reconfigure dependent " << ps.package.name + << " with " << what << " clause that refers to dependency " + << "configuration variables" << + info << "please report in https://github.com/build2/build2/issues/302"; + } + } + }; + // Alternatives argument must be parallel to the dependencies argument if // specified. // 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 @@ -70,45 +137,51 @@ 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>, 2> edas; - // If the dependency alternatives are not pre-selected, then evaluate - // the enable clauses. - // - // Note that evaluating the require and prefer clauses in this case is - // meaningless since we don't reconfigure the dependencies nor negotiate - // configurations with other dependents. What we should probably do is - // load configurations of the dependencies and use them while evaluating - // the dependent's enable and reflect clauses as we go along. Probably - // we should still evaluate the accept clauses to make sure that the - // dependency is configured acceptably for the dependent. For now we - // fail and will support this maybe later. - // 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) { const dependency_alternative& da (das[i]); - if (!da.enable || ps.evaluate_enable (*da.enable, make_pair (di, i))) + // Evaluate the dependency alternative enable clause, if present, + // unless it refers to any banned variables in which case we fail. + // + if (da.enable) { - if (da.prefer || da.require) - fail << "manual configuration of dependents with prefer or " - << "require clauses is not yet supported"; + if (!banned_var_prefixes.empty ()) + verify_banned_vars (*da.enable, "enable"); - edas.push_back (make_pair (ref (da), i)); + if (!ps.evaluate_enable (*da.enable, make_pair (di, i))) + continue; } + + if (manual && (da.prefer || da.require)) + fail << "manual configuration of dependents with prefer or " + << "require clauses is not yet supported"; + + edas.push_back (make_pair (ref (da), i)); } if (edas.empty ()) + { + dep_alts.push_back (0); continue; + } } else { @@ -129,13 +202,16 @@ 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);;) { - bool satisfied (false); + const pair<reference_wrapper<const dependency_alternative>, + size_t>* selected_alt (nullptr); + 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 @@ -166,9 +242,31 @@ namespace bpkg const shared_ptr<selected_package>& dp (spd.first); - if (dp == nullptr || - dp->state != package_state::configured || - !satisfies (dp->version, d.constraint) || + if (dp == nullptr) + break; + + database& pdb (*spd.second); + + optional<pair<package_state, package_substate>> dps; + if (fps != nullptr) + dps = fps (dp); + + const optional<version_constraint>* dc (&d.constraint); + + // Unconstrain this dependency, if requested. + // + if (unconstrain_deps != nullptr) + { + const vector<package_key>& uds (*unconstrain_deps); + if (find (uds.begin (), uds.end (), package_key (pdb, n)) != + uds.end ()) + { + dc = &absent_constraint; + } + } + + if ((dps ? dps->first : dp->state) != package_state::configured || + !satisfies (dp->version, *dc) || (pps != nullptr && find (pps->begin (), pps->end (), dp->name) == pps->end ())) break; @@ -176,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> (*spd.second, dp), - prerequisite_info {d.constraint, - make_pair (conf ? di + 1 : 0, - conf ? dai + 1 : 0)}); + lazy_shared_ptr<selected_package> (pdb, dp), + prerequisite_info {*dc}); } // Try the next alternative if there are unresolved dependencies for @@ -221,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, @@ -243,7 +328,13 @@ namespace bpkg { shared_ptr<selected_package> sp (pr.first.load ()); - if (!sp->system ()) + optional<pair<package_state, package_substate>> ps; + if (fps != nullptr) + ps = fps (sp); + + if (ps + ? ps->second != package_substate::system + : !sp->system ()) { // @@ Note that this doesn't work for build2 modules that // require bootstrap. For their dependents we need to @@ -262,20 +353,53 @@ namespace bpkg // Also note that such modules are marked with `requires: // bootstrap` in their manifest. // - dir_path od (sp->effective_out_root (pdb.config)); + // Note that we currently don't support global overrides + // in the shared build2 context (but could probably do, + // if necessary). + // + + dir_path od; + if (ps) + { + // There is no out_root for a would-be configured package. + // So we calculate it like in pkg_configure() below (yeah, + // it's an ugly hack). + // + od = sp->external () + ? pdb.config / dir_path (sp->name.string ()) + : pdb.config / dir_path (sp->name.string () + '-' + + sp->version.string ()); + } + else + od = sp->effective_out_root (pdb.config); + + // We tried to use global overrides to recreate the original + // behavior of not warning about unused config.import.* + // variables (achived via the config.config.persist value in + // amalgamation). Even though it's probably misguided (we + // don't actually save the unused values anywhere, just + // don't warn about them). + // + // Can we somehow cause a clash, say if the same package + // comes from different configurations? Yeah, we probably + // can. So could add it as undermined (?), detect a clash, + // and "fallforward" to the correct behavior. + // + // But we can clash with an absent value -- that is, we + // force importing from a wrong configuration where without + // any import things would have been found in the same + // amalgamation. Maybe we could detect that (no import + // for the same package -- but it could be for a package + // we are not configuring). + // vars.push_back ("config.import." + sp->name.variable () + - "='" + od.representation () + "'"); + "='" + od.representation () + '\''); } } } } - // Evaluate the dependency alternative reflect clause, if present. - // - if (da.reflect) - ps.evaluate_reflect (*da.reflect, make_pair (di, dai)); - - satisfied = true; + selected_alt = &eda; break; } @@ -283,7 +407,7 @@ namespace bpkg // "recreate dependency decisions" mode. In the latter case fall back // to the "make dependency decisions" mode and retry. // - if (!satisfied) + if (selected_alt == nullptr) { if (pps != nullptr) { @@ -294,6 +418,38 @@ namespace bpkg fail << "unable to satisfy dependency on " << das; } + const dependency_alternative& da (selected_alt->first); + + // In the reconfiguration mode ban the usage of the selected + // alternative dependency configuration variables in the subsequent + // enable and reflect clauses, unless we are also unconstraining + // dependencies (which indicates it's a relaxed mode that precedes + // a drop or failure with better diagnostics). + // + if (alts == nullptr && !manual && + unconstrain_deps == nullptr && + (da.prefer || da.require)) + { + for (const dependency& d: da) + banned_var_prefixes.push_back ( + "config." + d.name.variable () + '.'); + } + + // Evaluate the selected dependency alternative reflect clause, if + // present, unless it refers to any banned variables in which case we + // fail. + // + if (da.reflect) + { + if (!banned_var_prefixes.empty ()) + verify_banned_vars (*da.reflect, "reflect"); + + ps.evaluate_reflect (*da.reflect, + 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. @@ -302,13 +458,20 @@ 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. // vector<config_variable> srcs; + string checksum; if (!simulate) { + checksum = ps.config_checksum (); + pair<strings, vector<config_variable>> rvs (move (ps).collect_config ()); strings& vs (rvs.first); @@ -329,8 +492,78 @@ namespace bpkg } return configure_prerequisites_result {move (prereqs), + move (dep_alts), move (vars), - move (srcs)}; + move (srcs), + move (checksum)}; + } + + + unique_ptr<build2::context> + pkg_configure_context ( + const common_options& o, + strings&& cmd_vars, + const function<build2::context::var_override_function>& var_ovr_func) + { + using namespace build2; + + // Initialize the build system. + // + // Note that this takes into account --build-option and default options + // files (which may have global overrides and which end up in + // build2_cmd_vars). + // + if (!build2_sched.started ()) + build2_init (o); + + // Re-tune the scheduler for parallel execution (see build2_init() + // for details). + // + if (build2_sched.tuned ()) + build2_sched.tune (0); + + auto merge_cmd_vars = [&cmd_vars] () -> const strings& + { + if (cmd_vars.empty ()) + return build2_cmd_vars; + + if (!build2_cmd_vars.empty ()) + cmd_vars.insert (cmd_vars.begin (), + build2_cmd_vars.begin (), build2_cmd_vars.end ()); + + return cmd_vars; + }; + + // Shouldn't we shared the module context with package skeleton + // contexts? Maybe we don't have to since we don't build modules in + // them concurrently (in a sence, we didn't share it when we were + // invoking the build system driver). + // + unique_ptr<context> ctx ( + new context (build2_sched, + build2_mutexes, + build2_fcache, + nullopt /* match_only */, + false /* no_external_modules */, + false /* dry_run */, + false /* no_diag_buffer */, + false /* keep_going */, + merge_cmd_vars (), + context::reserves { + 30000 /* targets */, + 1100 /* variables */}, + nullptr /* module_context */, + nullptr /* inherited_mudules_lock */, + var_ovr_func)); + + // Set the current meta-operation once per context so that we don't reset + // ctx->current_on. Note that this function also sets ctx->current_mname + // and var_build_meta_operation on global scope. + // + ctx->current_meta_operation (config::mo_configure); + ctx->current_oname = string (); // default + + return ctx; } void @@ -338,13 +571,15 @@ namespace bpkg database& db, transaction& t, const shared_ptr<selected_package>& p, - const dependencies& deps, - const vector<size_t>* alts, - package_skeleton&& ps, - const vector<package_name>* pps, - bool disfigured, - bool simulate, - const function<find_database_function>& fdb) + configure_prerequisites_result&& cpr, +#ifndef BPKG_OUTPROC_CONFIGURE + const unique_ptr<build2::context>& pctx, + const build2::variable_overrides& ovrs, +#else + const unique_ptr<build2::context>&, + const build2::variable_overrides&, // Still in cpr.config_variables. +#endif + bool simulate) { tracer trace ("pkg_configure"); @@ -353,39 +588,51 @@ namespace bpkg tracer_guard tg (db, trace); - const dir_path& c (db.config_orig); +#ifndef BPKG_OUTPROC_CONFIGURE + const dir_path& c (db.config); // Absolute. +#else + const dir_path& c (db.config_orig); // Relative. +#endif + dir_path src_root (p->effective_src_root (c)); // Calculate package's out_root. // + // Note: see a version of this in pkg_configure_prerequisites(). + // dir_path out_root ( p->external () ? c / dir_path (p->name.string ()) - : c / dir_path (p->name.string () + "-" + p->version.string ())); + : c / dir_path (p->name.string () + '-' + p->version.string ())); l4 ([&]{trace << "src_root: " << src_root << ", " << "out_root: " << out_root;}); - // Verify all our prerequisites are configured and populate the - // prerequisites list. - // - assert (p->prerequisites.empty ()); - - configure_prerequisites_result cpr ( - pkg_configure_prerequisites (o, - db, - t, - deps, - alts, - move (ps), - pps, - simulate, - fdb)); + 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. + // if (!simulate) { + // Original implementation that runs the standard build system driver. + // + // Note that the semantics doesn't match 100%. In particular, in the + // in-process implementation we enter overrides with global visibility + // in each project instead of the amalgamation (which is probably more + // accurate, since we don't re-configure the amalgamation nor some + // dependencies which could be affected by such overrides). In a sense, + // we enter them as if they were specified with the special .../ scope + // (but not with the % project visibility -- they must still be visible + // in subprojects). + // +#ifdef BPKG_OUTPROC_CONFIGURE // Form the buildspec. // string bspec; @@ -401,46 +648,211 @@ namespace bpkg l4 ([&]{trace << "buildspec: " << bspec;}); - // Unless this package has been completely disfigured, disfigure all the - // package configuration variables to reset all the old values to - // defaults (all the new user/dependent/reflec values, including old - // user, are returned by collect_config() and specified as overrides). - // Note that this semantics must be consistent with how we load things - // in the package skeleton during configuration negotiation. - // - // Note also that this means we don't really use the dependent and - // reflect sources that we save in the database. But let's keep them - // for the completeness of information (maybe could be useful during - // configuration reset or some such). + try + { + run_b (o, verb_b::quiet, cpr.config_variables, bspec); + } + catch (const failed&) + { + // See below for comments. + // + p->out_root = out_root.leaf (); + p->state = package_state::broken; + pkg_disfigure (o, db, t, p, true, true, false); + throw; + } +#else + // Print the out-process command line in the verbose mode. // - string dvar; - if (!disfigured) + if (verb >= 2) { - // Note: must be quoted to preserve the pattern. + string bspec; + + // Use path representation to get canonical trailing slash. // - dvar = "config.config.disfigure='config."; - dvar += p->name.variable (); - dvar += "**'"; + if (src_root == out_root) + bspec = "configure('" + out_root.representation () + "')"; + else + bspec = "configure('" + + src_root.representation () + "'@'" + + out_root.representation () + "')"; + + print_b (o, verb_b::quiet, cpr.config_variables, bspec); } - // Configure. - // try { - run_b (o, - verb_b::quiet, - cpr.config_variables, - (!dvar.empty () ? dvar.c_str () : nullptr), - bspec); + // Note: no bpkg::failed should be thrown from this block. + // + using namespace build2; + using build2::fail; + using build2::info; + using build2::endf; + using build2::location; + + // The build2_init() function initializes the build system verbosity + // as if running with verb_b::normal while we need verb_b::quiet. So + // we temporarily adjust the build2 verbosity (see map_verb_b() for + // details). + // + auto verbg (make_guard ([ov = build2::verb] () {build2::verb = ov;})); + if (bpkg::verb == 1) + build2::verb = 0; + + context& ctx (*pctx); + + // Bootstrap and load the project. + // + // Note: in many ways similar to package_skeleton code. + // + scope& rs (*create_root (ctx, out_root, src_root)->second.front ()); + + // If we are configuring in the dependency order (as we should), then + // it feels like the only situation where we can end up with an + // already bootstrapped project is an unspecified dependency. Note + // that this is a hard fail since it would have been loaded without + // the proper configuration. + // + if (bootstrapped (rs)) + { + fail << p->name << db << " loaded ahead of its dependents" << + info << "likely unspecified dependency on package " << p->name; + } + + optional<bool> altn; + value& v (bootstrap_out (rs, altn)); + + if (!v) + v = src_root; + else + { + dir_path& p (cast<dir_path> (v)); + + if (src_root != p) + { + // @@ Fuzzy if need this or can do as package skeleton (seeing + // that we know we are re-configuring). + // + ctx.new_src_root = src_root; + ctx.old_src_root = move (p); + p = src_root; + } + } + + setup_root (rs, false /* forwarded */); + + // Note: we already know our amalgamation. + // + bootstrap_pre (rs, altn); + bootstrap_src (rs, altn, + c.relative (out_root) /* amalgamation */, + true /* subprojects */); + + create_bootstrap_outer (rs, true /* subprojects */); + bootstrap_post (rs); + + values mparams; + const meta_operation_info& mif (config::mo_configure); + const operation_info& oif (op_default); + + // Skip configure_pre() and configure_operation_pre() calls since we + // don't pass any parameteres and pass default operation. We also know + // that op_default has no pre/post operations, naturally. + + // Find the root buildfile. Note that the implied buildfile logic does + // not apply (our target is the project root directory). + // + optional<path> bf (find_buildfile (src_root, src_root, altn)); + + if (!bf) + fail << "no buildfile in " << src_root; + + // Enter project-wide overrides. + // + // Note that the use of the root scope as amalgamation makes sure + // scenarious like below work correctly (see above for background). + // + // bpkg create -d cfg cc config.cc.coptions=-Wall + // bpkg build { config.cc.coptions+=-g }+ libfoo + // { config.cc.coptions+=-O }+ libbar + // + ctx.enter_project_overrides (rs, out_root, ovrs, &rs); + + // The goal here is to be more or less semantically equivalent to + // configuring several projects at once. Except that here we have + // interleaving load/match instead of first all load then all + // match. But presumably this shouldn't be a problem (we can already + // have match interrupted by load and the "island append" requirement + // should hold here as well). + // + // Note that either way we will be potentially re-matching the same + // dependency targets multiple times (see build2::configure_execute() + // for details). + // + const path_name bsn ("<buildspec>"); + const location loc (bsn, 0, 0); + + // out_root/dir{./} + // + target_key tk { + &dir::static_type, + &out_root, + &empty_dir_path, + &empty_string, + nullopt}; + + action_targets tgs; + mif.load (mparams, rs, *bf, out_root, src_root, loc); + mif.search (mparams, rs, rs, *bf, tk, loc, tgs); + + ctx.current_operation (oif, nullptr); + action a (ctx.current_action ()); + + mif.match (mparams, a, tgs, 2 /* diag */, true /* progress */); + mif.execute (mparams, a, tgs, 2 /* diag */, true /* progress */); + + // Note: no operation_post/meta_operation_post for configure. + + // Here is a tricky part: if this is a normal package, then it will be + // discovered as a subproject of the bpkg configuration when we load + // it for the first time (because they are all unpacked). However, if + // this is a package with src_root!=out_root (such as an external + // package or a package with a custom checkout_root) then there could + // be no out_root directory for it in the bpkg configuration yet. As a + // result, we need to manually add it as a newly discovered + // subproject. + // + if (!rs.out_eq_src ()) + { + scope* as (rs.parent_scope ()->root_scope ()); + assert (as != nullptr); // No bpkg configuration? + + // Kept NULL if there are no subprojects, so we may need to + // initialize it (see build2::bootstrap_src() for details). + // + subprojects* sp (*as->root_extra->subprojects); + if (sp == nullptr) + { + value& v (as->vars.assign (*ctx.var_subprojects)); + v = subprojects {}; + sp = *(as->root_extra->subprojects = &cast<subprojects> (v)); + } + + const project_name& n (**rs.root_extra->project); + + if (sp->find (n) == sp->end ()) + sp->emplace (n, out_root.leaf ()); + } } - catch (const failed&) + catch (const build2::failed&) { + // Assume the diagnostics has already been issued. + // If we failed to configure the package, make sure we revert // it back to the unpacked state by running disfigure (it is // valid to run disfigure on an un-configured build). And if // disfigure fails as well, then the package will be set into // the broken state. - // // Indicate to pkg_disfigure() we are partially configured. // @@ -454,10 +866,14 @@ namespace bpkg true /* clean */, true /* disfigure */, false /* simulate */); - throw; + + + throw bpkg::failed (); } +#endif p->config_variables = move (cpr.config_sources); + p->config_checksum = move (cpr.config_checksum); } p->out_root = out_root.leaf (); @@ -467,6 +883,73 @@ namespace bpkg t.commit (); } + void + pkg_configure (const common_options& o, + database& db, + transaction& t, + const shared_ptr<selected_package>& p, + const dependencies& deps, + const vector<size_t>* alts, + package_skeleton&& ps, + const vector<package_name>* pps, + bool disfigured, + bool simulate, + const function<find_database_function>& fdb) + { + configure_prerequisites_result cpr ( + pkg_configure_prerequisites (o, + db, + t, + deps, + alts, + move (ps), + pps, + simulate, + fdb, + nullptr)); + + if (!simulate) + { + // Unless this package has been completely disfigured, disfigure all the + // package configuration variables to reset all the old values to + // defaults (all the new user/dependent/reflec values, including old + // user, are returned by collect_config() and specified as overrides). + // Note that this semantics must be consistent with how we load things + // in the package skeleton during configuration negotiation. + // + // Note also that this means we don't really use the dependent and + // reflect sources that we save in the database. But let's keep them + // for the completeness of information (maybe could be useful during + // configuration reset or some such). + // + if (!disfigured) + { + // Note: must be quoted to preserve the pattern. + // + cpr.config_variables.push_back ( + "config.config.disfigure='config." + p->name.variable () + "**'"); + } + } + + unique_ptr<build2::context> ctx; + +#ifndef BPKG_OUTPROC_CONFIGURE + if (!simulate) + ctx = pkg_configure_context (o, move (cpr.config_variables)); +#endif + + pkg_configure (o, + db, + t, + p, + move (cpr), + ctx, + (ctx != nullptr + ? ctx->var_overrides + : build2::variable_overrides {}), + simulate); + } + shared_ptr<selected_package> pkg_configure_system (const package_name& n, const version& v, @@ -625,7 +1108,11 @@ namespace bpkg false /* disfigure */, &p->config_variables, move (src_root), - move (out_root)), + move (out_root), + nullopt /* old_src_root */, + nullopt /* old_out_root */, + package_skeleton::load_config_user | + package_skeleton::load_config_dependent), nullptr /* prerequisites */, false /* disfigured */, false /* simulate */); |