diff options
Diffstat (limited to 'libbuild2/script/script.cxx')
-rw-r--r-- | libbuild2/script/script.cxx | 194 |
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 << "'"; + } } } |