aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/functions-process.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/functions-process.cxx')
-rw-r--r--libbuild2/functions-process.cxx160
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));
+ };
+ }
}
}