aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/script/script.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/script/script.cxx')
-rw-r--r--libbuild2/script/script.cxx194
1 files changed, 166 insertions, 28 deletions
diff --git a/libbuild2/script/script.cxx b/libbuild2/script/script.cxx
index 6ee702e..b53fc23 100644
--- a/libbuild2/script/script.cxx
+++ b/libbuild2/script/script.cxx
@@ -3,6 +3,7 @@
#include <libbuild2/script/script.hxx>
+#include <chrono>
#include <sstream>
#include <cstring> // strchr()
@@ -19,14 +20,17 @@ namespace build2
switch (lt)
{
- case line_type::var: s = "variable"; break;
- case line_type::cmd: s = "command"; break;
- case line_type::cmd_if: s = "'if'"; break;
- case line_type::cmd_ifn: s = "'if!'"; break;
- case line_type::cmd_elif: s = "'elif'"; break;
- case line_type::cmd_elifn: s = "'elif!'"; break;
- case line_type::cmd_else: s = "'else'"; break;
- case line_type::cmd_end: s = "'end'"; break;
+ case line_type::var: s = "variable"; break;
+ case line_type::cmd: s = "command"; break;
+ case line_type::cmd_if: s = "'if'"; break;
+ case line_type::cmd_ifn: s = "'if!'"; break;
+ case line_type::cmd_elif: s = "'elif'"; break;
+ case line_type::cmd_elifn: s = "'elif!'"; break;
+ case line_type::cmd_else: s = "'else'"; break;
+ case line_type::cmd_while: s = "'while'"; break;
+ case line_type::cmd_for_args: s = "'for'"; break;
+ case line_type::cmd_for_stream: s = "'for'"; break;
+ case line_type::cmd_end: s = "'end'"; break;
}
return o << s;
@@ -185,14 +189,14 @@ namespace build2
void
dump (ostream& os, const string& ind, const lines& ls)
{
- // Additionally indent the if-branch lines.
+ // Additionally indent the flow control construct block lines.
//
- string if_ind;
+ string fc_ind;
for (const line& l: ls)
{
- // Before printing indentation, decrease it if the else or end line is
- // reached.
+ // Before printing indentation, decrease it if the else, end, etc line
+ // is reached.
//
switch (l.type)
{
@@ -201,9 +205,9 @@ namespace build2
case line_type::cmd_else:
case line_type::cmd_end:
{
- size_t n (if_ind.size ());
+ size_t n (fc_ind.size ());
assert (n >= 2);
- if_ind.resize (n - 2);
+ fc_ind.resize (n - 2);
break;
}
default: break;
@@ -211,9 +215,10 @@ namespace build2
// Print indentations.
//
- os << ind << if_ind;
+ os << ind << fc_ind;
- // After printing indentation, increase it for if/else branch.
+ // After printing indentation, increase it for the flow control
+ // construct block lines.
//
switch (l.type)
{
@@ -221,7 +226,10 @@ namespace build2
case line_type::cmd_ifn:
case line_type::cmd_elif:
case line_type::cmd_elifn:
- case line_type::cmd_else: if_ind += " "; break;
+ case line_type::cmd_else:
+ case line_type::cmd_while:
+ case line_type::cmd_for_args:
+ case line_type::cmd_for_stream: fc_ind += " "; break;
default: break;
}
@@ -408,13 +416,33 @@ namespace build2
if ((m & command_to_stream::header) == command_to_stream::header)
{
- // Print the env builtin arguments, if any environment variable
- // (un)sets are present.
+ // Print the env builtin if any of its options/arguments are present.
//
- if (!c.variables.empty ())
+ if (c.timeout || c.cwd || !c.variables.empty ())
{
o << "env";
+ // Timeout.
+ //
+ if (c.timeout)
+ {
+ o << " -t "
+ << chrono::duration_cast<chrono::seconds> (*c.timeout).count ();
+
+ if (c.timeout_success)
+ o << " -s";
+ }
+
+ // CWD.
+ //
+ if (c.cwd)
+ {
+ o << " -c ";
+ print_path (*c.cwd);
+ }
+
+ // Variable unsets/sets.
+ //
auto b (c.variables.begin ()), i (b), e (c.variables.end ());
// Print a variable name or assignment to the stream, quoting it if
@@ -456,8 +484,7 @@ namespace build2
//
// Print the variable unsets as the -u options until a variable set
// is encountered (contains '=') or the end of the variable list is
- // reached. In the former case, to avoid a potential ambiguity add
- // the '-' separator, if there are any options.
+ // reached.
//
// Note that we rely on the fact that unsets come first, which is
// guaranteed by parser::parse_env_builtin().
@@ -471,16 +498,15 @@ namespace build2
o << " -u "; print (v, true /* name*/);
}
else // Variable set.
- {
- if (i != b)
- o << " -";
-
break;
- }
}
// Variable sets.
//
+ // Note that we don't add the '-' separator since we always use the
+ // `-* <value>` option notation and so there can't be any ambiguity
+ // with a variable set.
+ //
for (; i != e; ++i)
{
o << ' '; print (*i, false /* name */);
@@ -603,6 +629,34 @@ namespace build2
}
}
+ // environment_vars
+ //
+ environment_vars::iterator environment_vars::
+ find (const string& var)
+ {
+ size_t n (var.find ('='));
+ if (n == string::npos)
+ n = var.size ();
+
+ return find_if (begin (), end (),
+ [&var, n] (const string& v)
+ {
+ return v.compare (0, n, var, 0, n) == 0 &&
+ (v[n] == '=' || v[n] == '\0');
+ });
+ }
+
+ void environment_vars::
+ add (string var)
+ {
+ iterator i (find (var));
+
+ if (i != end ())
+ *i = move (var);
+ else
+ push_back (move (var));
+ }
+
// redirect
//
redirect::
@@ -719,7 +773,9 @@ namespace build2
{
using script::cleanup;
- assert (!implicit || c.type == cleanup_type::always);
+ // Implicit never-cleanup doesn't make sense.
+ //
+ assert (!implicit || c.type != cleanup_type::never);
const path& p (c.path);
@@ -745,5 +801,87 @@ namespace build2
{
special_cleanups.emplace_back (move (p));
}
+
+ const environment_vars& environment::
+ exported_variables (environment_vars&)
+ {
+ return exported_vars;
+ }
+
+ const environment_vars& environment::
+ merge_exported_variables (const environment_vars& vars,
+ environment_vars& storage)
+ {
+ const environment_vars& own (exported_variables (storage));
+
+ // If both, the own and the specified variable (un)sets are present,
+ // then merge them. Otherwise, return the own (un)sets, if present, or
+ // the specified (un)sets otherwise.
+ //
+ if (!own.empty () && !vars.empty ())
+ {
+ // Copy the own (un)sets into the storage, if they are not there yet.
+ //
+ if (&storage != &own)
+ storage = own;
+
+ for (const string& v: vars)
+ storage.add (v);
+
+ return storage;
+ }
+ else if (!own.empty ())
+ return own;
+ else
+ return vars;
+ }
+
+ // Helpers.
+ //
+ void
+ verify_environment_var_name (const string& name,
+ const char* prefix,
+ const location& l,
+ const char* opt)
+ {
+ if (name.empty ())
+ {
+ diag_record dr (fail (l));
+ dr << prefix << "empty ";
+
+ if (opt == nullptr)
+ dr << "variable name";
+ else
+ dr << "value for option " << opt;
+ }
+
+ if (name.find ('=') != string::npos)
+ {
+ diag_record dr (fail (l));
+ dr << prefix << "invalid ";
+
+ if (opt == nullptr)
+ dr << "variable name '" << name << "'";
+ else
+ dr << "value '" << name << "' for option " << opt;
+
+ dr << ": contains '='";
+ }
+ }
+
+ void
+ verify_environment_var_assignment (const string& var,
+ const char* prefix,
+ const location& l)
+ {
+ size_t p (var.find ('='));
+
+ if (p == 0)
+ fail (l) << prefix << "empty variable name";
+
+ if (p == string::npos)
+ fail (l) << prefix << "expected variable assignment instead of '"
+ << var << "'";
+ }
}
}