From 57b10c06925d0bdf6ffb38488ee908f085109e95 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 4 Jul 2019 19:12:15 +0300 Subject: Move config, dist, test, and install modules into library --- build2/test/script/script.cxx | 741 ------------------------------------------ 1 file changed, 741 deletions(-) delete mode 100644 build2/test/script/script.cxx (limited to 'build2/test/script/script.cxx') diff --git a/build2/test/script/script.cxx b/build2/test/script/script.cxx deleted file mode 100644 index 8e6351f..0000000 --- a/build2/test/script/script.cxx +++ /dev/null @@ -1,741 +0,0 @@ -// file : build2/test/script/script.cxx -*- C++ -*- -// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#include - -#include - -#include -#include - -using namespace std; - -namespace build2 -{ - namespace test - { - namespace script - { - ostream& - operator<< (ostream& o, line_type lt) - { - const char* s (nullptr); - - 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; - } - - return o << s; - } - - // Quote if empty or contains spaces or any of the special characters. - // Note that we use single quotes since double quotes still allow - // expansion. - // - // @@ What if it contains single quotes? - // - static void - to_stream_q (ostream& o, const string& s) - { - if (s.empty () || s.find_first_of (" |&<>=\\\"") != string::npos) - o << '\'' << s << '\''; - else - o << s; - }; - - void - to_stream (ostream& o, const command& c, command_to_stream m) - { - auto print_path = [&o] (const path& p) - { - using build2::operator<<; - - ostringstream s; - stream_verb (s, stream_verb (o)); - s << p; - - to_stream_q (o, s.str ()); - }; - - auto print_redirect = - [&o, print_path] (const redirect& r, const char* prefix) - { - o << ' ' << prefix; - - size_t n (string::traits_type::length (prefix)); - assert (n > 0); - - char d (prefix[n - 1]); // Redirect direction. - - switch (r.type) - { - case redirect_type::none: assert (false); break; - case redirect_type::pass: o << '|'; break; - case redirect_type::null: o << '-'; break; - case redirect_type::trace: o << '!'; break; - case redirect_type::merge: o << '&' << r.fd; break; - - case redirect_type::here_str_literal: - case redirect_type::here_doc_literal: - { - bool doc (r.type == redirect_type::here_doc_literal); - - // For here-document add another '>' or '<'. Note that here end - // marker never needs to be quoted. - // - if (doc) - o << d; - - o << r.modifiers; - - if (doc) - o << r.end; - else - { - const string& v (r.str); - to_stream_q (o, - r.modifiers.find (':') == string::npos - ? string (v, 0, v.size () - 1) // Strip newline. - : v); - } - - break; - } - - case redirect_type::here_str_regex: - case redirect_type::here_doc_regex: - { - bool doc (r.type == redirect_type::here_doc_regex); - - // For here-document add another '>' or '<'. Note that here end - // marker never needs to be quoted. - // - if (doc) - o << d; - - o << r.modifiers; - - const regex_lines& re (r.regex); - - if (doc) - o << re.intro + r.end + re.intro + re.flags; - else - { - assert (!re.lines.empty ()); // Regex can't be empty. - - regex_line l (re.lines[0]); - to_stream_q (o, re.intro + l.value + re.intro + l.flags); - } - - break; - } - - case redirect_type::file: - { - // For stdin or stdout-comparison redirect add '>>' or '<<' (and - // so make it '<<<' or '>>>'). Otherwise add '+' or '=' (and so - // make it '>+' or '>='). - // - if (d == '<' || r.file.mode == redirect_fmode::compare) - o << d << d; - else - o << (r.file.mode == redirect_fmode::append ? '+' : '='); - - print_path (r.file.path); - break; - } - - case redirect_type::here_doc_ref: assert (false); break; - } - }; - - auto print_doc = [&o] (const redirect& r) - { - o << endl; - - if (r.type == redirect_type::here_doc_literal) - o << r.str; - else - { - assert (r.type == redirect_type::here_doc_regex); - - const regex_lines& rl (r.regex); - - for (auto b (rl.lines.cbegin ()), i (b), e (rl.lines.cend ()); - i != e; ++i) - { - if (i != b) - o << endl; - - const regex_line& l (*i); - - if (l.regex) // Regex (possibly empty), - o << rl.intro << l.value << rl.intro << l.flags; - else if (!l.special.empty ()) // Special literal. - o << rl.intro; - else // Textual literal. - o << l.value; - - o << l.special; - } - } - - o << (r.modifiers.find (':') == string::npos ? "" : "\n") << r.end; - }; - - if ((m & command_to_stream::header) == command_to_stream::header) - { - // Program. - // - to_stream_q (o, c.program.string ()); - - // Arguments. - // - for (const string& a: c.arguments) - { - o << ' '; - to_stream_q (o, a); - } - - // Redirects. - // - if (c.in.effective ().type != redirect_type::none) - print_redirect (c.in.effective (), "<"); - - if (c.out.effective ().type != redirect_type::none) - print_redirect (c.out.effective (), ">"); - - if (c.err.effective ().type != redirect_type::none) - print_redirect (c.err.effective (), "2>"); - - for (const auto& p: c.cleanups) - { - o << " &"; - - if (p.type != cleanup_type::always) - o << (p.type == cleanup_type::maybe ? '?' : '!'); - - print_path (p.path); - } - - if (c.exit.comparison != exit_comparison::eq || c.exit.code != 0) - { - switch (c.exit.comparison) - { - case exit_comparison::eq: o << " == "; break; - case exit_comparison::ne: o << " != "; break; - } - - o << static_cast (c.exit.code); - } - } - - if ((m & command_to_stream::here_doc) == command_to_stream::here_doc) - { - // Here-documents. - // - if (c.in.type == redirect_type::here_doc_literal || - c.in.type == redirect_type::here_doc_regex) - print_doc (c.in); - - if (c.out.type == redirect_type::here_doc_literal || - c.out.type == redirect_type::here_doc_regex) - print_doc (c.out); - - if (c.err.type == redirect_type::here_doc_literal || - c.err.type == redirect_type::here_doc_regex) - print_doc (c.err); - } - } - - void - to_stream (ostream& o, const command_pipe& p, command_to_stream m) - { - if ((m & command_to_stream::header) == command_to_stream::header) - { - for (auto b (p.begin ()), i (b); i != p.end (); ++i) - { - if (i != b) - o << " | "; - - to_stream (o, *i, command_to_stream::header); - } - } - - if ((m & command_to_stream::here_doc) == command_to_stream::here_doc) - { - for (const command& c: p) - to_stream (o, c, command_to_stream::here_doc); - } - } - - void - to_stream (ostream& o, const command_expr& e, command_to_stream m) - { - if ((m & command_to_stream::header) == command_to_stream::header) - { - for (auto b (e.begin ()), i (b); i != e.end (); ++i) - { - if (i != b) - { - switch (i->op) - { - case expr_operator::log_or: o << " || "; break; - case expr_operator::log_and: o << " && "; break; - } - } - - to_stream (o, i->pipe, command_to_stream::header); - } - } - - if ((m & command_to_stream::here_doc) == command_to_stream::here_doc) - { - for (const expr_term& t: e) - to_stream (o, t.pipe, command_to_stream::here_doc); - } - } - - // redirect - // - redirect:: - redirect (redirect_type t) - : type (t) - { - switch (type) - { - case redirect_type::none: - case redirect_type::pass: - case redirect_type::null: - case redirect_type::trace: - case redirect_type::merge: break; - - case redirect_type::here_str_literal: - case redirect_type::here_doc_literal: new (&str) string (); break; - - case redirect_type::here_str_regex: - case redirect_type::here_doc_regex: - { - new (®ex) regex_lines (); - break; - } - - case redirect_type::file: new (&file) file_type (); break; - - case redirect_type::here_doc_ref: assert (false); break; - } - } - - redirect:: - redirect (redirect&& r) - : type (r.type), - modifiers (move (r.modifiers)), - end (move (r.end)), - end_line (r.end_line), - end_column (r.end_column) - { - switch (type) - { - case redirect_type::none: - case redirect_type::pass: - case redirect_type::null: - case redirect_type::trace: break; - - case redirect_type::merge: fd = r.fd; break; - - case redirect_type::here_str_literal: - case redirect_type::here_doc_literal: - { - new (&str) string (move (r.str)); - break; - } - case redirect_type::here_str_regex: - case redirect_type::here_doc_regex: - { - new (®ex) regex_lines (move (r.regex)); - break; - } - case redirect_type::file: - { - new (&file) file_type (move (r.file)); - break; - } - case redirect_type::here_doc_ref: - { - new (&ref) reference_wrapper (r.ref); - break; - } - } - } - - redirect:: - ~redirect () - { - switch (type) - { - case redirect_type::none: - case redirect_type::pass: - case redirect_type::null: - case redirect_type::trace: - case redirect_type::merge: break; - - case redirect_type::here_str_literal: - case redirect_type::here_doc_literal: str.~string (); break; - - case redirect_type::here_str_regex: - case redirect_type::here_doc_regex: regex.~regex_lines (); break; - - case redirect_type::file: file.~file_type (); break; - - case redirect_type::here_doc_ref: - { - ref.~reference_wrapper (); - break; - } - } - } - - redirect& redirect:: - operator= (redirect&& r) - { - if (this != &r) - { - this->~redirect (); - new (this) redirect (move (r)); // Assume noexcept move-constructor. - } - return *this; - } - - // scope - // - scope:: - scope (const string& id, scope* p, script* r) - : parent (p), - root (r), - vars (false /* global */), - id_path (cast (assign (root->id_var) = path ())), - wd_path (cast (assign (root->wd_var) = dir_path ())) - - { - // Construct the id_path as a string to ensure POSIX form. In fact, - // the only reason we keep it as a path is to be able to easily get id - // by calling leaf(). - // - { - string s (p != nullptr ? p->id_path.string () : string ()); - - if (!s.empty () && !id.empty ()) - s += '/'; - - s += id; - const_cast (id_path) = path (move (s)); - } - - // Calculate the working directory path unless this is the root scope - // (handled in an ad hoc way). - // - if (p != nullptr) - const_cast (wd_path) = dir_path (p->wd_path) /= id; - } - - void scope:: - clean (cleanup c, bool implicit) - { - using std::find; // Hidden by scope::find(). - - assert (!implicit || c.type == cleanup_type::always); - - const path& p (c.path); - if (!p.sub (root->wd_path)) - { - if (implicit) - return; - else - assert (false); // Error so should have been checked. - } - - auto pr = [&p] (const cleanup& v) -> bool {return v.path == p;}; - auto i (find_if (cleanups.begin (), cleanups.end (), pr)); - - if (i == cleanups.end ()) - cleanups.emplace_back (move (c)); - else if (!implicit) - i->type = c.type; - } - - void scope:: - clean_special (path p) - { - special_cleanups.emplace_back (move (p)); - } - - // script_base - // - script_base:: - script_base () - : // Enter the test.* variables with the same variable types as in - // buildfiles except for test: while in buildfiles it can be a - // target name, in testscripts it should be resolved to a path. - // - // Note: entering in a custom variable pool. - // - test_var (var_pool.insert ("test")), - options_var (var_pool.insert ("test.options")), - arguments_var (var_pool.insert ("test.arguments")), - redirects_var (var_pool.insert ("test.redirects")), - cleanups_var (var_pool.insert ("test.cleanups")), - - wd_var (var_pool.insert ("~")), - id_var (var_pool.insert ("@")), - cmd_var (var_pool.insert ("*")), - cmdN_var { - &var_pool.insert ("0"), - &var_pool.insert ("1"), - &var_pool.insert ("2"), - &var_pool.insert ("3"), - &var_pool.insert ("4"), - &var_pool.insert ("5"), - &var_pool.insert ("6"), - &var_pool.insert ("7"), - &var_pool.insert ("8"), - &var_pool.insert ("9")} {} - - // script - // - script:: - script (const target& tt, - const testscript& st, - const dir_path& rwd) - : group (st.name == "testscript" ? string () : st.name, this), - test_target (tt), - target_scope (tt.base_scope ()), - script_target (st) - { - // Set the script working dir ($~) to $out_base/test/ (id_path - // for root is just the id which is empty if st is 'testscript'). - // - const_cast (wd_path) = dir_path (rwd) /= id_path.string (); - - // Set the test variable at the script level. We do it even if it's - // set in the buildfile since they use different types. - // - { - value& v (assign (test_var)); - - // Note that the test variable's visibility is target. - // - lookup l (find_in_buildfile ("test", false)); - - // Note that we have similar code for simple tests. - // - const target* t (nullptr); - - if (l.defined ()) - { - const name* n (cast_null (l)); - - if (n == nullptr) - v = nullptr; - else if (n->empty ()) - v = path (); - else if (n->simple ()) - { - // Ignore the special 'true' value. - // - if (n->value != "true") - v = path (n->value); - else - t = &tt; - } - else if (n->directory ()) - v = path (n->dir); - else - { - // Must be a target name. - // - // @@ OUT: what if this is a @-qualified pair of names? - // - t = search_existing (*n, target_scope); - - if (t == nullptr) - fail << "unknown target '" << *n << "' in test variable"; - } - } - else - // By default we set it to the test target's path. - // - t = &tt; - - // If this is a path-based target, then we use the path. If this - // is an alias target (e.g., dir{}), then we use the directory - // path. Otherwise, we leave it NULL expecting the testscript to - // set it to something appropriate, if used. - // - if (t != nullptr) - { - if (auto* pt = t->is_a ()) - { - // Do some sanity checks: the target better be up-to-date with - // an assigned path. - // - v = pt->path (); - - if (v.empty ()) - fail << "target " << *pt << " specified in the test variable " - << "is out of date" << - info << "consider specifying it as a prerequisite of " << tt; - } - else if (t->is_a ()) - v = path (t->dir); - else if (t != &tt) - fail << "target " << *t << " specified in the test variable " - << "is not path-based"; - } - } - - // Set the special $*, $N variables. - // - reset_special (); - } - - lookup scope:: - find (const variable& var) const - { - // Search script scopes until we hit the root. - // - const scope* s (this); - - do - { - auto p (s->vars.find (var)); - if (p.first != nullptr) - return lookup (*p.first, p.second, s->vars); - } - while ((s->parent != nullptr ? (s = s->parent) : nullptr) != nullptr); - - return find_in_buildfile (var.name); - } - - - lookup scope:: - find_in_buildfile (const string& n, bool target_only) const - { - // Switch to the corresponding buildfile variable. Note that we don't - // want to insert a new variable into the pool (we might be running - // in parallel). Plus, if there is no such variable, then we cannot - // possibly find any value. - // - const variable* pvar (build2::var_pool.find (n)); - - if (pvar == nullptr) - return lookup (); - - const script& s (static_cast (*root)); - const variable& var (*pvar); - - // First check the target we are testing. - // - { - // Note that we skip applying the override if we did not find any - // value. In this case, presumably the override also affects the - // script target and we will pick it up there. A bit fuzzy. - // - auto p (s.test_target.find_original (var, target_only)); - - if (p.first) - { - if (var.overrides != nullptr) - p = s.target_scope.find_override (var, move (p), true); - - return p.first; - } - } - - // Then the script target followed by the scopes it is in. Note that - // while unlikely it is possible the test and script targets will be - // in different scopes which brings the question of which scopes we - // should search. - // - return s.script_target[var]; - } - - value& scope:: - append (const variable& var) - { - lookup l (find (var)); - - if (l.defined () && l.belongs (*this)) // Existing var in this scope. - return vars.modify (l); - - value& r (assign (var)); // NULL. - - if (l.defined ()) - r = *l; // Copy value (and type) from the outer scope. - - return r; - } - - void scope:: - reset_special () - { - // First assemble the $* value. - // - strings s; - - auto append = [&s] (const strings& v) - { - s.insert (s.end (), v.begin (), v.end ()); - }; - - if (lookup l = find (root->test_var)) - s.push_back (cast (l).representation ()); - - if (lookup l = find (root->options_var)) - append (cast (l)); - - if (lookup l = find (root->arguments_var)) - append (cast (l)); - - // Keep redirects/cleanups out of $N. - // - size_t n (s.size ()); - - if (lookup l = find (root->redirects_var)) - append (cast (l)); - - if (lookup l = find (root->cleanups_var)) - append (cast (l)); - - // Set the $N values if present. - // - for (size_t i (0); i <= 9; ++i) - { - value& v (assign (*root->cmdN_var[i])); - - if (i < n) - { - if (i == 0) - v = path (s[i]); - else - v = s[i]; - } - else - v = nullptr; // Clear any old values. - } - - // Set $*. - // - assign (root->cmd_var) = move (s); - } - } - } -} -- cgit v1.1