diff options
Diffstat (limited to 'libbuild2/functions-process.cxx')
-rw-r--r-- | libbuild2/functions-process.cxx | 160 |
1 files changed, 108 insertions, 52 deletions
diff --git a/libbuild2/functions-process.cxx b/libbuild2/functions-process.cxx index 73ca916..6faa798 100644 --- a/libbuild2/functions-process.cxx +++ b/libbuild2/functions-process.cxx @@ -1,9 +1,11 @@ // file : libbuild2/functions-process.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <libbutl/regex.mxx> -#include <libbutl/builtin.mxx> +#include <libbutl/regex.hxx> +#include <libbutl/builtin.hxx> +#include <libbuild2/scope.hxx> +#include <libbuild2/context.hxx> #include <libbuild2/function.hxx> #include <libbuild2/variable.hxx> @@ -141,6 +143,9 @@ namespace build2 builtin_callbacks cb; fdpipe ofd (open_pipe ()); + if (verb >= 3) + print_process (process_args (bn, args)); + uint8_t rs; // Storage. butl::builtin b (bf (rs, args, @@ -172,7 +177,16 @@ namespace build2 // While assuming that the builtin has issued the diagnostics on failure // we still print the error message (see process_finish() for details). // - fail << bn << " builtin " << process_exit (rs) << endf; + diag_record dr; + dr << fail << "builtin " << bn << " " << process_exit (rs); + + if (verb >= 1 && verb <= 2) + { + dr << info << "command line: "; + print_process (dr, process_args (bn, args)); + } + + dr << endf; } catch (const system_error& e) { @@ -181,18 +195,32 @@ namespace build2 } static inline value - run_builtin (builtin_function* bf, const strings& args, const string& bn) + run_builtin (const scope* s, + builtin_function* bf, + const strings& args, + const string& bn) { + // See below. + // + if (s != nullptr && s->ctx.phase != run_phase::load) + fail << "process.run() called during " << s->ctx.phase << " phase"; + return run_builtin_impl (bf, args, bn, read); } static inline value - run_builtin_regex (builtin_function* bf, + run_builtin_regex (const scope* s, + builtin_function* bf, const strings& args, const string& bn, const string& pat, const optional<string>& fmt) { + // See below. + // + if (s != nullptr && s->ctx.phase != run_phase::load) + fail << "process.run_regex() called during " << s->ctx.phase << " phase"; + // Note that we rely on the "small function object" optimization here. // return run_builtin_impl (bf, args, bn, @@ -217,7 +245,8 @@ namespace build2 size_t erase (0); // This can be a process_path (pair), process_path_ex (process_path - // followed by the name@ and checksum@ pairs), or just a path. + // optionally followed by the name@, checksum@, and env-checksum@ + // pairs), or just a path. // // First, check if the arguments begin with a process_path[_ex] and, if // that's the case, only use the leading name/pair to create the process @@ -292,6 +321,9 @@ namespace build2 [] (const string& s) {return s.c_str ();}); cargs.push_back (nullptr); + // Note that for now these functions can only be called during the load + // phase (see below) and so no diagnostics buffering is needed. + // return run_start (3 /* verbosity */, pp, cargs, @@ -308,15 +340,7 @@ namespace build2 void process_finish (const scope*, const cstrings& args, process& pr) { - try - { - if (!pr.wait ()) - fail << "process " << args[0] << " " << *pr.exit; - } - catch (const process_error& e) - { - fail << "unable to execute " << args[0] << ": " << e; - } + run_finish (args, pr, 2 /* verbosity */); } // Run a process. @@ -351,6 +375,15 @@ namespace build2 static inline value run_process (const scope* s, const process_path& pp, const strings& args) { + // The only plausible place where these functions can be called outside + // the load phase are scripts and there it doesn't make much sense to use + // them (the same can be achieved with commands in a uniform manner). Note + // that if there is no scope, then this is most likely (certainly?) the + // load phase (for example, command line). + // + if (s != nullptr && s->ctx.phase != run_phase::load) + fail << "process.run() called during " << s->ctx.phase << " phase"; + return run_process_impl (s, pp, args, read); } @@ -361,6 +394,11 @@ namespace build2 const string& pat, const optional<string>& fmt) { + // See above. + // + if (s != nullptr && s->ctx.phase != run_phase::load) + fail << "process.run_regex() called during " << s->ctx.phase << " phase"; + // Note that we rely on the "small function object" optimization here. // return run_process_impl (s, pp, args, @@ -376,7 +414,7 @@ namespace build2 if (builtin_function* bf = builtin (args)) { pair<string, strings> ba (builtin_args (bf, move (args), "run")); - return run_builtin (bf, ba.second, ba.first); + return run_builtin (s, bf, ba.second, ba.first); } else { @@ -394,7 +432,7 @@ namespace build2 if (builtin_function* bf = builtin (args)) { pair<string, strings> ba (builtin_args (bf, move (args), "run_regex")); - return run_builtin_regex (bf, ba.second, ba.first, pat, fmt); + return run_builtin_regex (s, bf, ba.second, ba.first, pat, fmt); } else { @@ -412,59 +450,77 @@ namespace build2 // $process.run(<prog>[ <args>...]) // - // Run builtin or external program and return trimmed stdout. + // Run builtin or external program and return trimmed `stdout` output. + // + // Note that if the result of executing the program can be affected by + // environment variables and this result can in turn affect the build + // result, then such variables should be reported with the + // `config.environment` directive. + // + // Note that this function is not pure and can only be called during the + // load phase. // - f[".run"] = [](const scope* s, names args) + f.insert (".run", false) += [](const scope* s, names args) { return run (s, move (args)); }; - f["run"] = [](const scope* s, process_path pp) + f.insert ("run", false) += [](const scope* s, process_path pp) { return run_process (s, pp, strings ()); }; - // $process.run_regex(<prog>[ <args>...], <pat> [, <fmt>]) + // $process.run_regex(<prog>[ <args>...], <pat>[, <fmt>]) // - // Run builtin or external program and return stdout lines matched and - // optionally processed with regex. + // Run builtin or external program and return `stdout` output lines + // matched and optionally processed with a regular expression. // // Each line of stdout (including the customary trailing blank) is matched // (as a whole) against <pat> and, if successful, returned, optionally - // processed with <fmt>, as an element of a list. + // processed with <fmt>, as an element of a list. See the `$regex.*()` + // function family for details on regular expressions and format strings. + // + // Note that if the result of executing the program can be affected by + // environment variables and this result can in turn affect the build + // result, then such variables should be reported with the + // `config.environment` directive. + // + // Note that this function is not pure and can only be called during the + // load phase. // - f[".run_regex"] = [](const scope* s, names a, string p, optional<string> f) { - return run_regex (s, move (a), p, f); - }; + auto e (f.insert (".run_regex", false)); - f[".run_regex"] = [] (const scope* s, names a, names p, optional<names> f) - { - return run_regex (s, - move (a), - convert<string> (move (p)), - f ? convert<string> (move (*f)) : nullopt_string); - }; + e += [](const scope* s, names a, string p, optional<string> f) + { + return run_regex (s, move (a), p, f); + }; - f["run_regex"] = [](const scope* s, - process_path pp, - string p, - optional<string> f) + e += [] (const scope* s, names a, names p, optional<names> f) + { + return run_regex (s, + move (a), + convert<string> (move (p)), + f ? convert<string> (move (*f)) : nullopt_string); + }; + } { - return run_process_regex (s, pp, strings (), p, f); - }; + auto e (f.insert ("run_regex", false)); - f["run_regex"] = [](const scope* s, - process_path pp, - names p, - optional<names> f) - { - return run_process_regex (s, - pp, strings (), - convert<string> (move (p)), - (f - ? convert<string> (move (*f)) - : nullopt_string)); - }; + e += [](const scope* s, process_path pp, string p, optional<string> f) + { + return run_process_regex (s, pp, strings (), p, f); + }; + + e += [](const scope* s, process_path pp, names p, optional<names> f) + { + return run_process_regex (s, + pp, strings (), + convert<string> (move (p)), + (f + ? convert<string> (move (*f)) + : nullopt_string)); + }; + } } } |