diff options
-rw-r--r-- | bbot/agent/agent.cxx | 479 | ||||
-rw-r--r-- | bbot/worker/worker.cxx | 218 | ||||
-rw-r--r-- | tests/integration/testscript | 15 |
3 files changed, 400 insertions, 312 deletions
diff --git a/bbot/agent/agent.cxx b/bbot/agent/agent.cxx index 7d734d3..5df470f 100644 --- a/bbot/agent/agent.cxx +++ b/bbot/agent/agent.cxx @@ -1073,10 +1073,11 @@ using bootstrapped_machines = vector<bootstrapped_machine>; static pair<toolchain_lock, bootstrapped_machines> enumerate_machines (const dir_path& machines) -try { tracer trace ("enumerate_machines", machines.string ().c_str ()); + size_t dir_iter_retry (0); // Directory iteration retry (see below). + for (;;) // From-scratch retry loop for after bootstrap (see below). { pair<toolchain_lock, bootstrapped_machines> pr; @@ -1149,280 +1150,307 @@ try // The first level are machine volumes. // - for (const dir_entry& ve: dir_iterator (machines, dir_iterator::no_follow)) + try { - const string vn (ve.path ().string ()); - - // Ignore hidden directories. - // - if (ve.type () != entry_type::directory || vn[0] == '.') - continue; - - const dir_path vd (dir_path (machines) /= vn); - - // Inside we have machines. - // - try + for (const dir_entry& ve: + dir_iterator (machines, dir_iterator::no_follow)) { - for (const dir_entry& me: dir_iterator (vd, dir_iterator::no_follow)) - { - const string mn (me.path ().string ()); + const string vn (ve.path ().string ()); - if (me.type () != entry_type::directory || mn[0] == '.') - continue; + // Ignore hidden directories. + // + if (ve.type () != entry_type::directory || vn[0] == '.') + continue; - const dir_path md (dir_path (vd) /= mn); + const dir_path vd (dir_path (machines) /= vn); - // Our endgoal here is to obtain a bootstrapped snapshot of this - // machine while watching out for potential race conditions (other - // instances as well as machines being added/upgraded/removed; see - // the manual for details). - // - // So here is our overall plan: - // - // 1. Resolve current subvolume link for our bootstrap protocol. - // - // 2. Lock the machine. This excludes any other instance from trying - // to perform the following steps. - // - // 3. If there is no link, cleanup old bootstrap (if any) and ignore - // this machine. - // - // 4. Try to create a snapshot of current subvolume (this operation - // is atomic). If failed (e.g., someone changed the link and - // removed the subvolume in the meantime), retry from #1. - // - // 5. Compare the snapshot to the already bootstrapped version (if - // any) and see if we need to re-bootstrap. If so, use the - // snapshot as a starting point. Rename to bootstrapped at the - // end (atomic). - // - dir_path lp (dir_path (md) /= (mn + '-' + bs_prot)); // -<P> - dir_path tp (dir_path (md) /= (mn + '-' + tc_name)); // -<toolchain> - - auto delete_bootstrapped = [&tp, &trace] () // Delete -<toolchain>. + // Inside we have machines. + // + try + { + for (const dir_entry& me: dir_iterator (vd, dir_iterator::no_follow)) { - run_btrfs (trace, "property", "set", "-ts", tp, "ro", "false"); - run_btrfs (trace, "subvolume", "delete", tp); - }; + const string mn (me.path ().string ()); - for (size_t retry (0);; ++retry) - { - if (retry != 0) - sleep (1); + if (me.type () != entry_type::directory || mn[0] == '.') + continue; + + const dir_path md (dir_path (vd) /= mn); - // Resolve the link to subvolume path. + // Our endgoal here is to obtain a bootstrapped snapshot of this + // machine while watching out for potential race conditions (other + // instances as well as machines being added/upgraded/removed; see + // the manual for details). // - dir_path sp; // <name>-<P>.<R> + // So here is our overall plan: + // + // 1. Resolve current subvolume link for our bootstrap protocol. + // + // 2. Lock the machine. This excludes any other instance from + // trying to perform the following steps. + // + // 3. If there is no link, cleanup old bootstrap (if any) and + // ignore this machine. + // + // 4. Try to create a snapshot of current subvolume (this + // operation is atomic). If failed (e.g., someone changed the + // link and removed the subvolume in the meantime), retry from + // #1. + // + // 5. Compare the snapshot to the already bootstrapped version (if + // any) and see if we need to re-bootstrap. If so, use the + // snapshot as a starting point. Rename to bootstrapped at the + // end (atomic). + // + dir_path lp (dir_path (md) /= (mn + '-' + bs_prot)); // -<P> + dir_path tp (dir_path (md) /= (mn + '-' + tc_name)); // -<toolchain> - try + auto delete_bootstrapped = [&tp, &trace] () // Delete -<toolchain>. { - sp = path_cast<dir_path> (readsymlink (lp)); + run_btrfs (trace, "property", "set", "-ts", tp, "ro", "false"); + run_btrfs (trace, "subvolume", "delete", tp); + }; - if (sp.relative ()) - sp = md / sp; - } - catch (const system_error& e) + for (size_t retry (0);; ++retry) { - // Leave the subvolume path empty if the subvolume link doesn't - // exist and fail on any other error. - // - if (e.code ().category () != std::generic_category () || - e.code ().value () != ENOENT) - fail << "unable to read subvolume link " << lp << ": " << e; - } + if (retry != 0) + sleep (1); - // Try to lock the machine. - // - machine_lock ml (lock_machine (tl, tp)); + // Resolve the link to subvolume path. + // + dir_path sp; // <name>-<P>.<R> - if (!ml.locked ()) - { - machine_manifest mm; - if (ml.prio) + try { - // Get the machine manifest (subset of the steps performed for - // the locked case below). - // - // Note that it's possible the machine we get is not what was - // originally locked by the other process (e.g., it has been - // upgraded since). It's also possible that if and when we - // interrupt and lock this machine, it will be a different - // machine (e.g., it has been upgraded since we read this - // machine manifest). To deal with all of that we will be - // reloading this information if/when we acquire the lock to - // this machine. - // - if (sp.empty ()) - { - l3 ([&]{trace << "skipping " << md << ": no subvolume link";}); - break; - } + sp = path_cast<dir_path> (readsymlink (lp)); - l3 ([&]{trace << "keeping " << md << ": locked by " << ml.pid - << " with priority " << *ml.prio;}); - - mm = parse_manifest<machine_manifest> ( - sp / "manifest", "machine"); - - none = none && mm.effective_role () == machine_role::auxiliary; + if (sp.relative ()) + sp = md / sp; } - else // Bootstrapping/suspended. + catch (const system_error& e) { - l3 ([&]{trace << "keeping " << md << ": being bootstrapped " - << "or suspened by " << ml.pid;}); - - // Assume it is a build machine (we cannot determine whether - // it is build or auxiliary without loading its manifest). + // Leave the subvolume path empty if the subvolume link + // doesn't exist and fail on any other error. // - none = false; + if (e.code ().category () != std::generic_category () || + e.code ().value () != ENOENT) + fail << "unable to read subvolume link " << lp << ": " << e; } - // Add the machine to the lists and bail out. + // Try to lock the machine. // - r.push_back (bootstrapped_machine { - move (ml), - move (tp), - bootstrapped_machine_manifest {move (mm), {}, {}}}); + machine_lock ml (lock_machine (tl, tp)); - break; - } + if (!ml.locked ()) + { + machine_manifest mm; + if (ml.prio) + { + // Get the machine manifest (subset of the steps performed + // for the locked case below). + // + // Note that it's possible the machine we get is not what + // was originally locked by the other process (e.g., it has + // been upgraded since). It's also possible that if and when + // we interrupt and lock this machine, it will be a + // different machine (e.g., it has been upgraded since we + // read this machine manifest). To deal with all of that we + // will be reloading this information if/when we acquire the + // lock to this machine. + // + if (sp.empty ()) + { + l3 ([&]{trace << "skipping " << md << ": no subvolume link";}); + break; + } - bool te (dir_exists (tp)); + l3 ([&]{trace << "keeping " << md << ": locked by " << ml.pid + << " with priority " << *ml.prio;}); - // If the resolution fails, then this means there is no current - // machine subvolume (for this bootstrap protocol). In this case - // we clean up our toolchain subvolume (-<toolchain>, if any) and - // ignore this machine. - // - if (sp.empty ()) - { - if (te) - delete_bootstrapped (); + mm = parse_manifest<machine_manifest> ( + sp / "manifest", "machine"); - l3 ([&]{trace << "skipping " << md << ": no subvolume link";}); - break; - } + none = + none && mm.effective_role () == machine_role::auxiliary; + } + else // Bootstrapping/suspended. + { + l3 ([&]{trace << "keeping " << md << ": being bootstrapped " + << "or suspened by " << ml.pid;}); - // <name>-<toolchain>-<xxx> - // - dir_path xp (snapshot_path (tp)); + // Assume it is a build machine (we cannot determine whether + // it is build or auxiliary without loading its manifest). + // + none = false; + } - if (btrfs_exit (trace, "subvolume", "snapshot", sp, xp) != 0) - { - if (retry >= 10) - fail << "unable to snapshot subvolume " << sp; + // Add the machine to the lists and bail out. + // + r.push_back (bootstrapped_machine { + move (ml), + move (tp), + bootstrapped_machine_manifest {move (mm), {}, {}}}); - continue; - } + break; + } - // Load the (original) machine manifest. - // - machine_manifest mm ( - parse_manifest<machine_manifest> (sp / "manifest", "machine")); + bool te (dir_exists (tp)); - bool aux (mm.effective_role () == machine_role::auxiliary); + // If the resolution fails, then this means there is no current + // machine subvolume (for this bootstrap protocol). In this case + // we clean up our toolchain subvolume (-<toolchain>, if any) + // and ignore this machine. + // + if (sp.empty ()) + { + if (te) + delete_bootstrapped (); - // Skip machines for which we don't have sufficient RAM. - // - if (effective_ram_minimum (mm) > - (aux ? ops.auxiliary_ram () : ops.build_ram ())) - { - l3 ([&]{trace << "skipping " << md << ": insufficient RAM";}); - run_btrfs (trace, "subvolume", "delete", xp); - break; - } + l3 ([&]{trace << "skipping " << md << ": no subvolume link";}); + break; + } - none = none && aux; + // <name>-<toolchain>-<xxx> + // + dir_path xp (snapshot_path (tp)); - // If we already have <name>-<toolchain>, see if it needs to be - // re-bootstrapped. Things that render it obsolete: - // - // 1. New machine revision (compare machine ids). - // 2. New toolchain (compare toolchain ids, not auxiliary). - // 3. New bbot/libbbot (compare versions, not auxiliary). - // - // The last case has a complication: what should we do if we have - // bootstrapped a newer version of bbot? This would mean that we - // are about to be stopped and upgraded (and the upgraded version - // will probably be able to use the result). So we simply ignore - // this machine for this run. - // - // Note: see similar code in the machine interruption logic. - // - optional<bootstrapped_machine_manifest> bmm; - if (te) - { - bmm = parse_manifest<bootstrapped_machine_manifest> ( - tp / "manifest", "bootstrapped machine"); + if (btrfs_exit (trace, "subvolume", "snapshot", sp, xp) != 0) + { + if (retry >= 10) + fail << "unable to snapshot subvolume " << sp; + + continue; + } + + // Load the (original) machine manifest. + // + machine_manifest mm ( + parse_manifest<machine_manifest> (sp / "manifest", "machine")); - if (bmm->machine.id != mm.id) + bool aux (mm.effective_role () == machine_role::auxiliary); + + // Skip machines for which we don't have sufficient RAM. + // + if (effective_ram_minimum (mm) > + (aux ? ops.auxiliary_ram () : ops.build_ram ())) { - l3 ([&]{trace << "re-bootstrap " << tp << ": new machine";}); - te = false; + l3 ([&]{trace << "skipping " << md << ": insufficient RAM";}); + run_btrfs (trace, "subvolume", "delete", xp); + break; } - if (!aux) + none = none && aux; + + // If we already have <name>-<toolchain>, see if it needs to be + // re-bootstrapped. Things that render it obsolete: + // + // 1. New machine revision (compare machine ids). + // 2. New toolchain (compare toolchain ids, not auxiliary). + // 3. New bbot/libbbot (compare versions, not auxiliary). + // + // The last case has a complication: what should we do if we + // have bootstrapped a newer version of bbot? This would mean + // that we are about to be stopped and upgraded (and the + // upgraded version will probably be able to use the result). So + // we simply ignore this machine for this run. + // + // Note: see similar code in the machine interruption logic. + // + optional<bootstrapped_machine_manifest> bmm; + if (te) { - if (!tc_id.empty () && bmm->toolchain.id != tc_id) + bmm = parse_manifest<bootstrapped_machine_manifest> ( + tp / "manifest", "bootstrapped machine"); + + if (bmm->machine.id != mm.id) { - l3 ([&]{trace << "re-bootstrap " << tp << ": new toolchain";}); + l3 ([&]{trace << "re-bootstrap " << tp << ": new machine";}); te = false; } - if (int i = compare_bbot (bmm->bootstrap)) + if (!aux) { - if (i < 0) + if (!tc_id.empty () && bmm->toolchain.id != tc_id) { - l3 ([&]{trace << "re-bootstrap " << tp << ": new bbot";}); + l3 ([&]{trace << "re-bootstrap " << tp << ": new toolchain";}); te = false; } - else + + if (int i = compare_bbot (bmm->bootstrap)) { - l3 ([&]{trace << "ignoring " << tp << ": old bbot";}); - run_btrfs (trace, "subvolume", "delete", xp); - break; + if (i < 0) + { + l3 ([&]{trace << "re-bootstrap " << tp << ": new bbot";}); + te = false; + } + else + { + l3 ([&]{trace << "ignoring " << tp << ": old bbot";}); + run_btrfs (trace, "subvolume", "delete", xp); + break; + } } } + + if (!te) + delete_bootstrapped (); } + else + l3 ([&]{trace << "bootstrap " << tp;}); if (!te) - delete_bootstrapped (); - } - else - l3 ([&]{trace << "bootstrap " << tp;}); - - if (!te) - { - // Ignore any other machines that need bootstrapping. - // - if (!pboot) { - pboot = pending_bootstrap { - move (ml), move (tp), move (xp), move (mm), move (bmm)}; + // Ignore any other machines that need bootstrapping. + // + if (!pboot) + { + pboot = pending_bootstrap { + move (ml), move (tp), move (xp), move (mm), move (bmm)}; + } + else + run_btrfs (trace, "subvolume", "delete", xp); + + break; } else run_btrfs (trace, "subvolume", "delete", xp); + // Add the machine to the lists. + // + r.push_back ( + bootstrapped_machine {move (ml), move (tp), move (*bmm)}); + break; - } - else - run_btrfs (trace, "subvolume", "delete", xp); + } // Retry loop. + } // Inner dir_iterator loop. + } + catch (const system_error& e) + { + fail << "unable to iterate over " << vd << ": " << e; + } + } // Outer dir_iterator loop. + } + catch (const system_error& e) + { + // Once in a while we get ENOENT while iterating over the machines + // directory. This directory contains the machine directories (not + // subvolumes) and is not being changed when we get this error. Maybe + // this is due to directory sizes/timestamps changes, but then we would + // expect to get this error a lot more often..? So this feels like a + // btrfs bug which we are going to retry a few times. See GH issue #349 + // for additional information. + // + bool retry (dir_iter_retry++ != 2); - // Add the machine to the lists. - // - r.push_back ( - bootstrapped_machine {move (ml), move (tp), move (*bmm)}); + (retry ? warn : error) << "unable to iterate over " << machines + << ": " << e; + if (retry) + continue; // Re-enumerate from scratch. + else + throw failed (); + } - break; - } // Retry loop. - } // Inner dir_iterator loop. - } - catch (const system_error& e) - { - fail << "unable to iterate over " << vd << ": " << e; - } - } // Outer dir_iterator loop. + dir_iter_retry = 0; // Reset for re-enumeration due to other reasons. // See if there is a pending bootstrap and whether we can perform it. // @@ -1533,10 +1561,6 @@ try // Unreachable. } -catch (const system_error& e) -{ - fail << "unable to iterate over " << machines << ": " << e << endf; -} // Perform the build task throwing interrupt if it has been interrupted. // @@ -1577,7 +1601,9 @@ try const bootstrapped_machine_manifest& mm (am.manifest); path ef (tftp_put_dir / "environment"); // Environment upload file. + path efm (ef + '-' + mm.machine.name); // Environment upload saved file. try_rmfile (ef); + try_rmfile (efm); // <name>-<toolchain>-<xxx> // @@ -1744,7 +1770,7 @@ try l3 ([&]{trace << "completed startup in " << startup_to - to << "s";}); // Read the uploaded environment and, if necessary, append the name prefix - // (which we first make a valid C identifier). + // (which we first make a valid C identifier and uppercase). // // Note that it may seem like a good idea to validate the format here. // But that means we will essentially need to parse it twice (here and in @@ -1754,7 +1780,7 @@ try // string env_pfx (env_name.empty () ? string () - : sanitize_identifier (env_name) + '_'); + : ucase (sanitize_identifier (env_name)) + '_'); string env; try { @@ -1777,7 +1803,7 @@ try // Rename and keep the environment file for debugging (it will be removed // at the end as part of the tftp_put_dir cleanup). // - mvfile (ef, ef + '-' + mm.machine.name); + mvfile (ef, efm); return make_pair (auxiliary_machine_result {move (xp), move (m)}, move (env)); @@ -1984,6 +2010,17 @@ start_auxiliary_machines (const vector<bootstrapped_machine*>& ams, // string envs; // Combined environments. + auto amg ( + make_exception_guard ( + [&amrs] () + { + if (!amrs.empty ()) + { + info << "trying to force auxiliary machines down"; + stop_auxiliary_machines (amrs); + } + })); + for (size_t i (0); i != n; ++i) { const auxiliary_machine& tam (tm.auxiliary_machines[i]); @@ -1996,6 +2033,8 @@ start_auxiliary_machines (const vector<bootstrapped_machine*>& ams, })); assert (j != e); + // Note: can throw interrupt. + // pair<auxiliary_machine_result, string> p ( start_auxiliary_machine (**j, tam.environment_name, diff --git a/bbot/worker/worker.cxx b/bbot/worker/worker.cxx index 793b387..8fb7796 100644 --- a/bbot/worker/worker.cxx +++ b/bbot/worker/worker.cxx @@ -575,6 +575,7 @@ run_cmd (step_id step, const string& name, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, const process_env& pe, A&&... a) @@ -588,22 +589,32 @@ run_cmd (step_id step, // struct abort {}; - auto prompt = [&last_cmd, &next_cmd, &t, &log] (const string& what) + auto prompt = [&aux_env, &last_cmd, &next_cmd, &t, &log] (const string& what) { diag_record dr (text); dr << '\n' << what << '\n' - << " current dir: " << current_directory () << '\n' - << " environment: " << ops.env_script () << ' ' << ops.env_target (); + << " current dir: " << current_directory () << '\n' + << " environment: " << ops.env_script () << ' ' << ops.env_target (); + + if (!aux_env.empty ()) + { + dr << '\n' + << " auxiliary environment:"; + + for (const string& e: aux_env) + dr << '\n' + << " " << e; + } if (!last_cmd.empty ()) dr << '\n' - << " last command: " << last_cmd; + << " last command: " << last_cmd; if (!next_cmd.empty ()) dr << '\n' - << " next command: " << next_cmd; + << " next command: " << next_cmd; dr.flush (); @@ -782,6 +793,7 @@ run_cmd (step_id step, const string& name, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, const process_env& pe, A&&... a) @@ -793,9 +805,7 @@ run_cmd (step_id step, out_str, out_file, warn_detect, name, - bkp_step, - bkp_status, - last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, pe, forward<A> (a)...); } @@ -811,6 +821,7 @@ run_bpkg (step_id step, const regexes& warn_detect, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, const char* verbosity, const string& cmd, A&&... a) @@ -822,7 +833,7 @@ run_bpkg (step_id step, &out, path () /* out_file */, warn_detect, "bpkg " + cmd, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, process_env ("bpkg", envvars), verbosity, cmd, forward<A> (a)...); } @@ -835,6 +846,7 @@ run_bpkg (step_id step, string& log, const regexes& warn_detect, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, const char* verbosity, const string& cmd, A&&... a) @@ -845,7 +857,7 @@ run_bpkg (step_id step, nullptr /* out_str */, path () /* out_file */, warn_detect, "bpkg " + cmd, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, process_env ("bpkg", envvars), verbosity, cmd, forward<A> (a)...); } @@ -860,6 +872,7 @@ run_bpkg (step_id step, const regexes& warn_detect, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, const char* verbosity, const string& cmd, A&&... a) @@ -873,7 +886,7 @@ run_bpkg (step_id step, pre_run, out, warn_detect, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, verbosity, cmd, forward<A> (a)...); } @@ -885,6 +898,7 @@ run_bpkg (step_id step, string& log, const path& out, const regexes& warn_detect, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, const char* verbosity, const string& cmd, A&&... a) @@ -893,7 +907,7 @@ run_bpkg (step_id step, t, log, nullptr /* out_str */, out, warn_detect, "bpkg " + cmd, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, process_env ("bpkg", envvars), verbosity, cmd, forward<A> (a)...); } @@ -905,6 +919,7 @@ run_bpkg (step_id step, string& log, const path& out, const regexes& warn_detect, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, const char* verbosity, const string& cmd, A&&... a) @@ -915,7 +930,7 @@ run_bpkg (step_id step, envvars, t, log, out, warn_detect, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, verbosity, cmd, forward<A> (a)...); } @@ -926,6 +941,7 @@ run_bpkg (step_id step, string& log, const regexes& warn_detect, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, const char* verbosity, const string& cmd, A&&... a) @@ -936,7 +952,7 @@ run_bpkg (step_id step, envvars, t, log, warn_detect, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, verbosity, cmd, forward<A> (a)...); } @@ -948,6 +964,7 @@ run_b (step_id step, string& log, const regexes& warn_detect, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, const char* verbosity, const strings& buildspecs, A&&... a) @@ -966,7 +983,7 @@ run_b (step_id step, nullptr /* out_str */, path () /* out_file */, warn_detect, name, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, process_env ("b", envvars), verbosity, buildspecs, forward<A> (a)...); } @@ -979,6 +996,7 @@ run_b (step_id step, string& log, const regexes& warn_detect, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, const char* verbosity, const string& buildspec, A&&... a) @@ -988,7 +1006,7 @@ run_b (step_id step, nullptr /* out_str */, path () /* out_file */, warn_detect, "b " + buildspec, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, process_env ("b", envvars), verbosity, buildspec, forward<A> (a)...); } @@ -1000,6 +1018,7 @@ run_b (step_id step, string& log, const regexes& warn_detect, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, const char* verbosity, const string& buildspec, A&&... a) @@ -1009,7 +1028,7 @@ run_b (step_id step, envvars, t, log, warn_detect, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, verbosity, buildspec, forward<A> (a)...); } @@ -1020,6 +1039,7 @@ run_ldconfig (step_id step, string& log, const regexes& warn_detect, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, A&&... a) { @@ -1029,7 +1049,7 @@ run_ldconfig (step_id step, nullptr /* out_str */, path () /* out_file*/, warn_detect, "sudo ldconfig", - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, process_env ("sudo"), "ldconfig", forward<A> (a)...); } @@ -1041,6 +1061,7 @@ run_apt_get (step_id step, string& log, const regexes& warn_detect, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, const string& cmd, A&&... a) { @@ -1052,7 +1073,7 @@ run_apt_get (step_id step, nullptr /* out_str */, path () /* out_file*/, warn_detect, "sudo apt-get " + cmd, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, process_env ("sudo"), "apt-get", cmd, forward<A> (a)...); } @@ -1064,6 +1085,7 @@ run_dnf (step_id step, string& log, const regexes& warn_detect, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, const string& cmd, A&&... a) { @@ -1075,7 +1097,7 @@ run_dnf (step_id step, nullptr /* out_str */, path () /* out_file*/, warn_detect, "sudo dnf " + cmd, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, process_env ("sudo"), "dnf", cmd, forward<A> (a)...); } @@ -1088,6 +1110,7 @@ run_tar (step_id step, string& log, const regexes& warn_detect, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, bool sudo, A&&... a) @@ -1098,7 +1121,7 @@ run_tar (step_id step, nullptr /* out_str */, path () /* out_file*/, warn_detect, sudo ? "sudo tar" : "tar", - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, process_env (sudo ? "sudo" : "tar"), sudo ? "tar" : nullptr, forward<A> (a)...); } @@ -1110,6 +1133,7 @@ run_tar (step_id step, string& log, const regexes& warn_detect, const optional<step_id>& bkp_step, const optional<result_status>& bkp_status, + const strings& aux_env, string& last_cmd, bool /* sudo */, A&&... a) @@ -1123,7 +1147,7 @@ run_tar (step_id step, nullptr /* out_str */, path () /* out_file*/, warn_detect, "bsdtar", - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, process_env ("bsdtar"), forward<A> (a)...); } @@ -1299,6 +1323,12 @@ build (size_t argc, const char* argv[]) optional<result_status> bkp_status; string last_cmd; // Used in the user prompt. + // Parse the auxiliary environment, if present, to dump it into the + // configure operation log and to use it in the interactive build user + // prompt. Note that this environment is already set by the parent process. + // + strings aux_env; + for (;;) // The "breakout" loop. { auto fail_operation = [&trace] (operation_result& r, @@ -1383,6 +1413,17 @@ build (size_t argc, const char* argv[]) } } + // Parse the auxiliary environment, if present. + // + if (tm.auxiliary_environment) + { + // Note: cannot throw since has already been called successfully by the + // parent process. + // + aux_env = parse_auxiliary_environment (*tm.auxiliary_environment, + comment_begin); + } + // Split the argument into prefix (empty if not present) and unquoted // value (absent if not present) and determine the step status. If the // prefix is present and is prepended with the '+'/'-' character, then the @@ -2025,7 +2066,7 @@ build (size_t argc, const char* argv[]) // for the build2 process. Return true if the dist meta-operation // succeeds. // - auto redist = [&trace, &wre, &bkp_step, &bkp_status, &last_cmd] + auto redist = [&trace, &wre, &bkp_step, &bkp_status, &aux_env, &last_cmd] (step_id step, operation_result& r, const dir_path& dist_root, @@ -2055,7 +2096,7 @@ build (size_t argc, const char* argv[]) step, envvars, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "config.dist.root=" + redist_root.string (), import, @@ -2366,22 +2407,17 @@ build (size_t argc, const char* argv[]) // If we have auxiliary environment, show it in the logs. // - if (tm.auxiliary_environment) + if (!aux_env.empty ()) { - strings es (parse_auxiliary_environment (*tm.auxiliary_environment, - comment_begin)); - if (!es.empty ()) + for (const string& e: aux_env) { - for (const string& e: es) - { - r.log += e; - r.log += '\n'; - } - - // Add a trailing blank line to separate this from the rest. - // + r.log += e; r.log += '\n'; } + + // Add a trailing blank line to separate this from the rest. + // + r.log += '\n'; } // Noop, just for the log record. @@ -2431,7 +2467,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-V", "create", "-d", target_conf, @@ -2467,7 +2503,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-V", "create", "-d", host_conf, @@ -2497,7 +2533,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-V", "create", "-d", install_conf, @@ -2520,7 +2556,7 @@ build (size_t argc, const char* argv[]) r.status |= run_b ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-V", "create(" + host_conf.representation () + ",cc)", "config.config.load=~host", @@ -2534,7 +2570,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "create", "--existing", @@ -2595,7 +2631,7 @@ build (size_t argc, const char* argv[]) r.status |= run_b ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-V", "create(" + module_conf.representation () + ',' + mods + ')', "config.config.load=~build2", @@ -2612,7 +2648,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "create", "--existing", @@ -2646,7 +2682,7 @@ build (size_t argc, const char* argv[]) r.status |= run_b ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-V", "create(" + install_conf.representation () + ',' + mods + ')', "config.config.load=~build2", @@ -2663,7 +2699,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "create", "--existing", @@ -2689,7 +2725,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "link", "-d", target_conf, @@ -2704,7 +2740,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "link", "-d", target_conf, @@ -2722,7 +2758,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "link", "-d", host_conf, @@ -2742,7 +2778,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "link", "-d", install_conf, @@ -2756,7 +2792,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "link", "-d", install_conf, @@ -2782,7 +2818,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "add", "-d", main_pkg_conf, @@ -2805,7 +2841,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "fetch", "-d", main_pkg_conf, @@ -2830,7 +2866,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "add", "-d", install_conf, @@ -2853,7 +2889,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "fetch", "-d", install_conf, @@ -2879,7 +2915,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "add", "-d", target_conf, @@ -2902,7 +2938,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "fetch", "-d", target_conf, @@ -3384,7 +3420,7 @@ build (size_t argc, const char* argv[]) log_uuids, dependency_checksum, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "build", "--configure-only", @@ -3529,7 +3565,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "update", step_args (env_args, s), @@ -3574,7 +3610,7 @@ build (size_t argc, const char* argv[]) // configuration arguments are specified for them. // auto test = [&trace, &wre, - &bkp_step, &bkp_status, &last_cmd, + &bkp_step, &bkp_status, &aux_env, &last_cmd, &step_args, &env_args, &tgt_args, &pkg_args, &bootstrap_import, &redist] @@ -3657,7 +3693,7 @@ build (size_t argc, const char* argv[]) b, envvars, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "update", step_args (env_args, s, f), @@ -3692,7 +3728,7 @@ build (size_t argc, const char* argv[]) b, envvars, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "test", "--package-cwd", // See above for details. @@ -3746,7 +3782,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "test", "--package-cwd", @@ -3875,7 +3911,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "install", step_args (env_args, s), @@ -3900,7 +3936,7 @@ build (size_t argc, const char* argv[]) r.status |= run_ldconfig ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, step_args (env_args, s, nullopt, nullopt, ss), step_args (tgt_args, s, nullopt, nullopt, ss), step_args (pkg_args, s, nullopt, nullopt, ss)); @@ -4052,7 +4088,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, bindist_result_file, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "bindist", "--distribution", distribution, @@ -4354,7 +4390,7 @@ build (size_t argc, const char* argv[]) r.status |= run_apt_get ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "update", "--assume-yes", step_args (env_args, s, nullopt, nullopt, ss), @@ -4384,7 +4420,7 @@ build (size_t argc, const char* argv[]) r.status |= run_apt_get ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "install", "--assume-yes", step_args (env_args, s, nullopt, nullopt, ss), @@ -4424,7 +4460,7 @@ build (size_t argc, const char* argv[]) r.status |= run_dnf ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "install", "--refresh", "--assumeyes", @@ -4496,7 +4532,7 @@ build (size_t argc, const char* argv[]) r.status |= run_tar ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, true /* sudo */, "-xf", f, @@ -4526,7 +4562,7 @@ build (size_t argc, const char* argv[]) r.status |= run_ldconfig ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, step_args (env_args, s, nullopt, nullopt, ss), step_args (tgt_args, s, nullopt, nullopt, ss), step_args (pkg_args, s, nullopt, nullopt, ss)); @@ -4689,7 +4725,7 @@ build (size_t argc, const char* argv[]) r.status |= run_b ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-V", "create('" + out_dir.representation () + '\'' + mods + ')', step_args (env_args, s, f), @@ -4730,7 +4766,7 @@ build (size_t argc, const char* argv[]) b, envvars, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "configure('" + subprj_src_dir.representation () + "'@'" + @@ -4765,7 +4801,7 @@ build (size_t argc, const char* argv[]) b, envvars, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", test_specs, step_args (env_args, s), @@ -4877,7 +4913,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-V", "create", "-d", target_conf, @@ -4913,7 +4949,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-V", "create", "-d", host_conf, @@ -4943,7 +4979,7 @@ build (size_t argc, const char* argv[]) r.status |= run_b ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-V", "create(" + module_conf.representation () + ",cc)", "config.config.load=~build2", @@ -4957,7 +4993,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "create", "--existing", @@ -4983,7 +5019,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "link", "-d", target_conf, @@ -4998,7 +5034,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "link", "-d", target_conf, @@ -5016,7 +5052,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "link", "-d", host_conf, @@ -5043,7 +5079,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "add", "-d", runtime_tests_conf, @@ -5067,7 +5103,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "fetch", "-d", runtime_tests_conf, @@ -5094,7 +5130,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "add", "-d", target_conf, @@ -5118,7 +5154,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "fetch", "-d", target_conf, @@ -5281,7 +5317,7 @@ build (size_t argc, const char* argv[]) b, envvars, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "build", "--configure-only", @@ -5461,7 +5497,7 @@ build (size_t argc, const char* argv[]) r.status |= run_apt_get ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "remove", "--assume-yes", step_args (env_args, s, nullopt, nullopt, ss), @@ -5500,7 +5536,7 @@ build (size_t argc, const char* argv[]) r.status |= run_dnf ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "remove", "--assumeyes", step_args (env_args, s, nullopt, nullopt, ss), @@ -5556,7 +5592,7 @@ build (size_t argc, const char* argv[]) r.status |= run_bpkg ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, "-v", "uninstall", step_args (env_args, s), @@ -5758,7 +5794,7 @@ build (size_t argc, const char* argv[]) r.status |= run_tar ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, false /* sudo */, #ifndef __OpenBSD__ "--format", "ustar", @@ -5788,7 +5824,7 @@ build (size_t argc, const char* argv[]) r.status |= run_tar ( b, trace, r.log, wre, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, false /* sudo */, "-tf", upload_archive, @@ -5860,7 +5896,7 @@ build (size_t argc, const char* argv[]) nullptr /* out_str */, path () /* out_file */, regexes (), "" /* name */, - bkp_step, bkp_status, last_cmd, + bkp_step, bkp_status, aux_env, last_cmd, process_env ()); rm.status |= r.status; diff --git a/tests/integration/testscript b/tests/integration/testscript index 93a6807..988859f 100644 --- a/tests/integration/testscript +++ b/tests/integration/testscript @@ -472,6 +472,18 @@ rfp = yes #interactive="interactive: b.test-installed.configure" #interactive="interactive: warning" +#\ +aux_env = 'auxiliary-environment: +\ +# x86_64-linux_debian_12-postgresql_15 +# +DATABASE_HOST=10.0.213.126 +DATABASE_PORT=5432 +DATABASE_USER=test +DATABASE_NAME=test +\ +' +#\ +cat <<"EOI" >=task : 1 @@ -484,7 +496,8 @@ rfp = yes $tests machine: $machine target: $target - config: $config + $aux_env + target-config: $config $package_config $interactive $host |