aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2021-07-06 13:08:54 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2021-07-06 13:08:54 +0300
commit52c0f8e9669e5d80cefa62237202d5c911a2df32 (patch)
treeedd965d2bff61aeb38bf4c602f67c55e4b718534
parenta56f29d8685e9595d8bf9a29296a72427fd3cf7a (diff)
Add support for end step id in worker
-rw-r--r--bbot/worker/worker.cxx221
-rw-r--r--doc/manual.cli4
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<regex>;
// 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 <typename... A>
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<size_t> (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<size_t> (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> (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> (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 <typename V, typename... A>
@@ -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<step_id> bkp_step;
+ optional<result_status> 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<step_id> bkp_step;
- optional<result_status> 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 <package-name>
#
bpkg -v uninstall <package-name>
}
+
+# end
+#
+# This step id can only be used as a breakpoint.
\
For details on configuring and testing installation refer to