From 5d54628076bd7fc97e90c81b6d0df0fef4ceae20 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 14 May 2018 16:39:45 +0200 Subject: Tolerate misconfigured src_root in info and disfigure meta-operations --- build2/b.cxx | 71 +++++++++++++++++++++++++-------------- build2/config/operation.cxx | 2 ++ build2/dist/operation.cxx | 1 + build2/file.cxx | 81 +++++++++++++++++++++++++++++++++++---------- build2/file.hxx | 5 +++ build2/operation.cxx | 3 ++ build2/operation.hxx | 6 ++++ 7 files changed, 126 insertions(+), 43 deletions(-) diff --git a/build2/b.cxx b/build2/b.cxx index ba84b1c..70fb470 100644 --- a/build2/b.cxx +++ b/build2/b.cxx @@ -842,14 +842,30 @@ main (int argc, char* argv[]) // If we also have src_root specified by the user, make sure // they match. // - const dir_path& p (cast (v)); + dir_path& p (cast (v)); if (src_root.empty ()) src_root = p; else if (src_root != p) { - fail << "bootstrapped src_root " << p << " does not match " - << (forwarded ? "forwarded " : "specified ") << src_root; + // We used to fail here but that meant there were no way to + // actually fix the problem (i.e., remove a forward or + // reconfigure the out directory). So now we warn (unless + // quiet, which is helful to tools like the package manager + // that are running info underneath). + // + // We also save the old/new values since we may have to remap + // src_root for subprojects (amalgamations are handled by not + // loading outer project for disfigure and info). + // + if (verb) + warn << "configured src_root " << p << " does not match " + << (forwarded ? "forwarded " : "specified ") + << src_root; + + new_src_root = src_root; + old_src_root = move (p); + p = src_root; } } else @@ -921,15 +937,6 @@ main (int argc, char* argv[]) } } - // Create and bootstrap outer roots if any. Loading is done - // by load_root_pre() (that would normally be called by the - // meta-operation's load() callback below). - // - create_bootstrap_outer (rs); - - if (!bstrapped) - bootstrap_post (rs); - // The src bootstrap should have loaded all the modules that // may add new meta/operations. So at this stage they should // all be known. We store the combined action id in uint8_t; @@ -976,7 +983,8 @@ main (int argc, char* argv[]) // If this is the first target in the meta-operation batch, then // set the batch meta-operation id. // - if (mid == 0) + bool first (mid == 0); + if (first) { mid = m; mif = rs.meta_operations[m]; @@ -984,18 +992,6 @@ main (int argc, char* argv[]) if (mif == nullptr) fail (l) << "target " << tn << " does not support meta-" << "operation " << meta_operation_table[m].name; - - l5 ([&]{trace << "start meta-operation batch " << mif->name - << ", id " << static_cast (mid);}); - - if (mif->meta_operation_pre != nullptr) - mif->meta_operation_pre (mparams, l); - else if (!mparams.empty ()) - fail (l) << "unexpected parameters for meta-operation " - << mif->name; - - set_current_mif (*mif); - dirty = true; } // // Otherwise, check that all the targets in a meta-operation @@ -1014,6 +1010,31 @@ main (int argc, char* argv[]) << mif->name << " in the same meta-operation batch"; } + // Create and bootstrap outer roots if any. Loading is done by + // load_root() (that would be called by the meta-operation's + // load() callback below). + // + if (mif->bootstrap_outer) + create_bootstrap_outer (rs); + + if (!bstrapped) + bootstrap_post (rs); + + if (first) + { + l5 ([&]{trace << "start meta-operation batch " << mif->name + << ", id " << static_cast (mid);}); + + if (mif->meta_operation_pre != nullptr) + mif->meta_operation_pre (mparams, l); + else if (!mparams.empty ()) + fail (l) << "unexpected parameters for meta-operation " + << mif->name; + + set_current_mif (*mif); + dirty = true; + } + // If this is the first target in the operation batch, then set // the batch operation id. // diff --git a/build2/config/operation.cxx b/build2/config/operation.cxx index cdf2f9a..54e3211 100644 --- a/build2/config/operation.cxx +++ b/build2/config/operation.cxx @@ -562,6 +562,7 @@ namespace build2 "configuring", "configured", "is configured", + true, // bootstrap_outer &configure_pre, // meta-operation pre &configure_operation_pre, &configure_load, // normal load unless configuring forward @@ -810,6 +811,7 @@ namespace build2 "disfiguring", "disfigured", "is disfigured", + false, // bootstrap_outer disfigure_pre, // meta-operation pre &disfigure_operation_pre, &disfigure_load, diff --git a/build2/dist/operation.cxx b/build2/dist/operation.cxx index 659b7b8..8921b7b 100644 --- a/build2/dist/operation.cxx +++ b/build2/dist/operation.cxx @@ -630,6 +630,7 @@ namespace build2 "distributing", "distributed", "has nothing to distribute", // We cannot "be distributed". + true, // bootstrap_outer nullptr, // meta-operation pre &dist_operation_pre, &load, // normal load diff --git a/build2/file.cxx b/build2/file.cxx index 7cc6b5e..cadcc29 100644 --- a/build2/file.cxx +++ b/build2/file.cxx @@ -96,6 +96,23 @@ namespace build2 return make_pair (dir_path (), false); } + dir_path old_src_root; + dir_path new_src_root; + + // Remap the src_root variable value if it is inside old_src_root. + // + static inline void + remap_src_root (value& v) + { + if (!old_src_root.empty ()) + { + dir_path& d (cast (v)); + + if (d.sub (old_src_root)) + d = new_src_root / d.leaf (old_src_root); + } + } + static void source (scope& root, scope& base, const path& bf, bool boot) { @@ -444,32 +461,50 @@ namespace build2 { tracer trace ("find_project_name"); + // First check if the root scope for this project has already been setup + // in which case we will have src_root and maybe even the name. + // + const dir_path* src_root (nullptr); + const scope& s (scopes.find (out_root)); + + if (s.root_scope () == &s && s.out_path () == out_root) + { + if (lookup l = s.vars[var_project]) + return cast (l); + + src_root = s.src_path_; + } + // Load the project name. If this subdirectory is the subproject's - // src_root, then we can get directly to that. Otherwise, we first - // have to discover its src_root. + // src_root, then we can get directly to that. Otherwise, we first have to + // discover its src_root. // - const dir_path* src_root; value src_root_v; // Need it to live until the end. - if (src_hint != nullptr ? *src_hint : is_src_root (out_root)) - src_root = &out_root; - else + if (src_root == nullptr) { - path f (out_root / src_root_file); - - if (!fallback_src_root.empty () && !exists (f)) - src_root = &fallback_src_root; + if (src_hint != nullptr ? *src_hint : is_src_root (out_root)) + src_root = &out_root; else { - auto p (extract_variable (f, *var_src_root)); + path f (out_root / src_root_file); + + if (!fallback_src_root.empty () && !exists (f)) + src_root = &fallback_src_root; + else + { + auto p (extract_variable (f, *var_src_root)); + + if (!p.second) + fail << "variable src_root expected as first line in " << f; - if (!p.second) - fail << "variable src_root expected as first line in " << f; + src_root_v = move (p.first); + remap_src_root (src_root_v); // Remap if inside old_src_root. + src_root = &cast (src_root_v); - src_root_v = move (p.first); - src_root = &cast (src_root_v); - l5 ([&]{trace << "extracted src_root " << *src_root << " for " - << out_root;}); + l5 ([&]{trace << "extracted src_root " << *src_root + << " for " << out_root;}); + } } } @@ -871,6 +906,8 @@ namespace build2 v = move (src_root); } } + else + remap_src_root (v); // Remap if inside old_src_root. setup_root (rs, forwarded (root, out_root, v.as ())); bootstrap_pre (rs); @@ -917,9 +954,13 @@ namespace build2 value& v (rs.assign (var_src_root)); if (!v) + { v = is_src_root (out_root) ? out_root : (root.src_path () / p.second); + } + else + remap_src_root (v); // Remap if inside old_src_root. setup_root (rs, forwarded (root, out_root, v.as ())); bootstrap_pre (rs); @@ -1234,10 +1275,14 @@ namespace build2 auto l (root->vars[*var_src_root]); if (l) { + // Note that unlike main() here we fail hard. The idea is that if + // the project we are importing is misconfigured, then it should be + // fixed first. + // const dir_path& p (cast (l)); if (!src_root.empty () && p != src_root) - fail (loc) << "bootstrapped src_root " << p << " does not match " + fail (loc) << "configured src_root " << p << " does not match " << "discovered " << src_root; } else diff --git a/build2/file.hxx b/build2/file.hxx index 23362c8..08d089d 100644 --- a/build2/file.hxx +++ b/build2/file.hxx @@ -57,6 +57,11 @@ namespace build2 pair find_out_root (const dir_path&); + // The old/new src_root paths. See main() (where they are set) for details. + // + extern dir_path old_src_root; + extern dir_path new_src_root; + // If buildfile is '-', then read from STDIN. // void diff --git a/build2/operation.cxx b/build2/operation.cxx index 10ae6e7..56f2979 100644 --- a/build2/operation.cxx +++ b/build2/operation.cxx @@ -52,6 +52,7 @@ namespace build2 "", // to do anything. "", "", + true, // bootstrap_outer nullptr, // meta-operation pre nullptr, // operation pre &load, @@ -416,6 +417,7 @@ namespace build2 "", "", "", + true, // bootstrap_outer nullptr, // meta-operation pre nullptr, // operation pre &load, @@ -507,6 +509,7 @@ namespace build2 "", "", "", + false, // bootstrap_outer nullptr, // meta-operation pre &info_operation_pre, &info_load, diff --git a/build2/operation.hxx b/build2/operation.hxx index fd8ca0c..d70db28 100644 --- a/build2/operation.hxx +++ b/build2/operation.hxx @@ -253,6 +253,12 @@ namespace build2 const string name_did; // E.g., 'configured'. const string name_done; // E.g., 'is configured'. + // Whether to bootstrap outer projects. If load() below calls load_root(), + // then this must be true. Note that this happens before + // meta_operation_pre() is called. + // + const bool bootstrap_outer; + // The first argument in all the callback is the meta-operation // parameters. // -- cgit v1.1