From 52c0f8e9669e5d80cefa62237202d5c911a2df32 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Tue, 6 Jul 2021 13:08:54 +0300 Subject: Add support for end step id in worker --- bbot/worker/worker.cxx | 221 +++++++++++++++++++++++++++++-------------------- doc/manual.cli | 4 + 2 files changed, 136 insertions(+), 89 deletions(-) diff --git a/bbot/worker/worker.cxx b/bbot/worker/worker.cxx index 6952af6..edbad5c 100644 --- a/bbot/worker/worker.cxx +++ b/bbot/worker/worker.cxx @@ -178,7 +178,8 @@ enum class step_id bpkg_test_separate_installed_configure_build, bpkg_test_separate_installed_update, bpkg_test_separate_installed_test, - bpkg_uninstall + bpkg_uninstall, + end }; static const strings step_id_str { @@ -207,7 +208,8 @@ static const strings step_id_str { "bpkg.test-separate-installed.configure.build", "bpkg.test-separate-installed.update", "bpkg.test-separate-installed.test", - "bpkg.uninstall"}; + "bpkg.uninstall", + "end"}; using std::regex; namespace regex_constants = std::regex_constants; @@ -223,6 +225,9 @@ using regexes = vector; // execution. If bkp_status is present, then ask for that if the command // execution results with the specified or more critical status. // +// For the special end step no command is executed. In this case only the user +// is potentially prompted and the step is traced/logged. +// template static result_status run_cmd (step_id step, @@ -288,42 +293,47 @@ run_cmd (step_id step, } }; + auto prompt_step = [step, &t, &log, &bkp_step, &prompt] () + { + const string& sid (step_id_str[static_cast (step)]); + + // Prompt the user if the breakpoint is reached. + // + if (bkp_step && *bkp_step == step) + prompt (sid + " step is reached"); + + string ts (to_string (system_clock::now (), + "%Y-%m-%d %H:%M:%S%[.N] %Z", + true /* special */, + true /* local */)); + + // Log the step id and the command to be executed. + // + l3 ([&]{t << "step id: " << sid << ' ' << ts;}); + +#ifndef _WIN32 + log += "# step id: "; +#else + log += "rem step id: "; +#endif + log += sid; + log += ' '; + log += ts; + log += '\n'; + }; + try { // Trace, log, and save the command line. // - auto cmdc = [step, &t, &log, &bkp_step, &next_cmd, &prompt] + auto cmdc = [step, &t, &log, &bkp_step, &next_cmd, &prompt, &prompt_step] (const char* c[], size_t n) { - const string& sid (step_id_str[static_cast (step)]); - std::ostringstream os; process::print (os, c, n); next_cmd = os.str (); - // Prompt the user if the breakpoint is reached. - // - if (bkp_step && *bkp_step == step) - prompt (sid + " step is reached"); - - string ts (to_string (system_clock::now (), - "%Y-%m-%d %H:%M:%S%[.N] %Z", - true /* special */, - true /* local */)); - - // Log the step id and the command to be executed. - // - l3 ([&]{t << "step id: " << sid << ' ' << ts;}); - -#ifndef _WIN32 - log += "# step id: "; -#else - log += "rem step id: "; -#endif - log += sid; - log += ' '; - log += ts; - log += '\n'; + prompt_step (); t (c, n); @@ -331,65 +341,87 @@ run_cmd (step_id step, log += '\n'; }; - fdpipe pipe (fdopen_pipe ()); // Text mode seems appropriate. - - process pr ( - process_start_callback (cmdc, - fdopen_null (), // Never reads from stdin. - 2, // 1>&2 - pipe, - pe, - forward (a)...)); - - pipe.out.close (); - result_status r (result_status::success); + if (step != step_id::end) { - ifdstream is (move (pipe.in), fdstream_mode::skip); // Skip on exception. - - for (string l; is.peek () != ifdstream::traits_type::eof (); ) + try { - getline (is, l); + fdpipe pipe (fdopen_pipe ()); // Text mode seems appropriate. + + process pr ( + process_start_callback (cmdc, + fdopen_null (), // Never reads from stdin. + 2, // 1>&2 + pipe, + pe, + forward (a)...)); + + pipe.out.close (); - // Match the log line with the warning-detecting regular expressions - // until the first match. - // - if (r != result_status::warning) { - for (const regex& re: warn_detect) + // Skip on exception. + // + ifdstream is (move (pipe.in), fdstream_mode::skip); + + for (string l; is.peek () != ifdstream::traits_type::eof (); ) { - // Only examine the first 512 bytes. Long lines (e.g., linker - // command lines) could trigger implementation-specific limitations - // (like stack overflow). Plus, it is a performance concern. + getline (is, l); + + // Match the log line with the warning-detecting regular + // expressions until the first match. // - if (regex_search (l.begin (), - l.size () < 512 ? l.end () : l.begin () + 512, - re)) + if (r != result_status::warning) { - r = result_status::warning; - break; + for (const regex& re: warn_detect) + { + // Only examine the first 512 bytes. Long lines (e.g., linker + // command lines) could trigger implementation-specific + // limitations (like stack overflow). Plus, it is a + // performance concern. + // + if (regex_search (l.begin (), + l.size () < 512 ? l.end () : l.begin () + 512, + re)) + { + r = result_status::warning; + break; + } + } } + + add (move (l), false /* trace */); } } - add (move (l), false /* trace */); - } - } - - if (!pr.wait ()) - { - const process_exit& e (*pr.exit); - add (name + " " + to_string (e)); - r = e.normal () ? result_status::error : result_status::abnormal; - } + if (!pr.wait ()) + { + const process_exit& e (*pr.exit); + add (name + " " + to_string (e)); + r = e.normal () ? result_status::error : result_status::abnormal; + } - last_cmd = move (next_cmd); + last_cmd = move (next_cmd); - if (bkp_status && r >= *bkp_status) + if (bkp_status && r >= *bkp_status) + { + next_cmd.clear (); // Note: used by prompt(). + prompt (!r ? "error occured" : "warning is issued"); + } + } + catch (const process_error& e) + { + fail << "unable to execute " << name << ": " << e; + } + catch (const io_error& e) + { + fail << "unable to read " << name << " diagnostics: " << e; + } + } + else { - next_cmd.clear (); // Note: used by prompt(). - prompt (!r ? "error occured" : "warning is issued"); + next_cmd.clear (); // Note: used by prompt_step(). + prompt_step (); } return r; @@ -398,14 +430,6 @@ run_cmd (step_id step, { return result_status::abort; } - catch (const process_error& e) - { - fail << "unable to execute " << name << ": " << e << endf; - } - catch (const io_error& e) - { - fail << "unable to read " << name << " diagnostics: " << e << endf; - } } template @@ -665,6 +689,15 @@ build (size_t argc, const char* argv[]) dir_path rwd; // Root working directory. + // Resolve the breakpoint specified by the interactive manifest value into + // the step id or the result status breakpoint. If the breakpoint is + // invalid, then log the error and abort the build. Note that we reuse the + // configure operation log here not to complicate things. + // + optional bkp_step; + optional bkp_status; + string last_cmd; // Used in the user prompt. + for (;;) // The "breakout" loop. { // Regular expressions that detect different forms of build2 toolchain @@ -684,15 +717,6 @@ build (size_t argc, const char* argv[]) for (const string& re: tm.unquoted_warning_regex ()) wre.emplace_back (re, f); - // Resolve the breakpoint specified by the interactive manifest value into - // the step id or the result status breakpoint. If the breakpoint is - // invalid, then log the error and abort the build. Note that we reuse the - // configure operation log here not to complicate things. - // - optional bkp_step; - optional bkp_status; - string last_cmd; // Used in the user prompt. - if (tm.interactive) { const string& b (*tm.interactive); @@ -2014,7 +2038,9 @@ build (size_t argc, const char* argv[]) if (!rm.results.empty ()) { - rm.status |= rm.results.back ().status; // Merge last in case of a break. + operation_result& r (rm.results.back ()); + + rm.status |= r.status; // Merge last in case of a break. // Also merge statuses of the configure and test operations, which logs // can potentially be shared across multiple steps and which results may @@ -2025,6 +2051,23 @@ build (size_t argc, const char* argv[]) if (test_result != nullptr) rm.status |= test_result->status; + + // Unless there is an error (or worse) encountered, log the special 'end' + // step and, if this step is specified in the interactive manifest value, + // ask the user if to continue the task execution. + // + bool error (!rm.status); + + if (!error) + { + r.status |= run_cmd (step_id::end, + trace, r.log, regexes (), + "" /* name */, + bkp_step, bkp_status, last_cmd, + process_env ()); + + rm.status |= r.status; + } } else assert (rm.status == result_status::abort); diff --git a/doc/manual.cli b/doc/manual.cli index d08a6ff..4326a5b 100644 --- a/doc/manual.cli +++ b/doc/manual.cli @@ -948,6 +948,10 @@ bpkg -v update # bpkg -v uninstall } + +# end +# +# This step id can only be used as a breakpoint. \ For details on configuring and testing installation refer to -- cgit v1.1