diff options
Diffstat (limited to 'libbutl/b.cxx')
-rw-r--r-- | libbutl/b.cxx | 186 |
1 files changed, 109 insertions, 77 deletions
diff --git a/libbutl/b.cxx b/libbutl/b.cxx index e1caa4c..0b4472f 100644 --- a/libbutl/b.cxx +++ b/libbutl/b.cxx @@ -1,58 +1,19 @@ // file : libbutl/b.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#ifndef __cpp_modules_ts -#include <libbutl/b.mxx> -#endif - -// C includes. +#include <libbutl/b.hxx> +#include <ios> // ios::failure #include <cassert> - -#ifndef __cpp_lib_modules_ts -#include <string> -#include <vector> -#include <cstddef> -#include <cstdint> -#include <stdexcept> -#include <functional> - -#include <ios> // ios::failure -#include <utility> // move() +#include <utility> // move() #include <sstream> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -module butl.b; - -// Only imports additional to interface. -#ifdef __clang__ -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.url; -import butl.path; -import butl.process; -import butl.optional; -import butl.project_name; -import butl.standard_version; -#endif - -import butl.utility; // next_word(), eof(), etc -import butl.path_io; -import butl.fdstream; -import butl.process_io; // operator<<(ostream, process_path) -import butl.small_vector; -#else -#include <libbutl/utility.mxx> -#include <libbutl/path-io.mxx> -#include <libbutl/fdstream.mxx> -#include <libbutl/process-io.mxx> -#include <libbutl/small-vector.mxx> -#endif +#include <algorithm> + +#include <libbutl/utility.hxx> // next_word(), eof(), etc +#include <libbutl/path-io.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/process-io.hxx> // operator<<(ostream, process_path) +#include <libbutl/small-vector.hxx> using namespace std; @@ -71,15 +32,30 @@ namespace butl throw runtime_error ("invalid " + d); } - b_project_info - b_info (const dir_path& project, - bool ext_mods, + void + b_info (std::vector<b_project_info>& r, + const vector<dir_path>& projects, + b_info_flags fl, uint16_t verb, const function<b_callback>& cmd_callback, const path& program, const dir_path& search_fallback, const vector<string>& ops) { + // Bail out if the project list is empty. + // + if (projects.empty ()) + return; + + // Reserve enough space in the result and save its original size. + // + size_t rn (r.size ()); + { + size_t n (rn + projects.size ()); + if (r.capacity () < n) + r.reserve (n); + } + try { process_path pp ( @@ -105,6 +81,23 @@ namespace butl else vops.push_back ("-q"); + string spec ("info("); + + // Note that quoting is essential here. + // + for (size_t i (0); i != projects.size(); ++i) + { + if (i != 0) + spec += ' '; + + spec += '\'' + projects[i].representation () + '\''; + } + + if ((fl & b_info_flags::subprojects) == b_info_flags::none) + spec += ",no_subprojects"; + + spec += ')'; + pr = process_start_callback ( cmd_callback ? cmd_callback : [] (const char* const*, size_t) {}, 0 /* stdin */, @@ -112,10 +105,12 @@ namespace butl 2 /* stderr */, pp, vops, - ext_mods ? nullptr : "--no-external-modules", + ((fl & b_info_flags::ext_mods) == b_info_flags::none + ? "--no-external-modules" + : nullptr), "-s", ops, - "info:", "'" + project.representation () + "'"); + spec); pipe.out.close (); ifdstream is (move (pipe.in), fdstream_mode::skip, ifdstream::badbit); @@ -145,31 +140,52 @@ namespace butl } }; - b_project_info r; - for (string l; !eof (getline (is, l)); ) + b_project_info pi; + auto add_project = [&r, &pi] () { - if (l.compare (0, 9, "project: ") == 0) - { - string v (l, 9); - if (!v.empty ()) - r.project = parse_name (move (v), "project"); - } - else if (l.compare (0, 9, "version: ") == 0) + // Parse version string to standard version if the project loaded + // the version module. + // + const auto& ms (pi.modules); + if (find (ms.begin (), ms.end (), "version") != ms.end ()) { - string v (l, 9); - if (!v.empty ()) try { - r.version = standard_version (v, standard_version::allow_stub); + pi.version = standard_version (pi.version_string, + standard_version::allow_stub); } catch (const invalid_argument& e) { - bad_value ("version '" + v + "': " + e.what ()); + bad_value ("version '" + pi.version_string + "': " + e.what ()); } } + + // Add the project info and prepare for the next project info + // parsing. + // + r.push_back (move (pi)); + pi = b_project_info (); + }; + + for (string l; !eof (getline (is, l)); ) + { + if (l.empty ()) + { + add_project (); + } + else if (l.compare (0, 9, "project: ") == 0) + { + string v (l, 9); + if (!v.empty ()) + pi.project = parse_name (move (v), "project"); + } + else if (l.compare (0, 9, "version: ") == 0) + { + pi.version_string = string (l, 9); + } else if (l.compare (0, 9, "summary: ") == 0) { - r.summary = string (l, 9); + pi.summary = string (l, 9); } else if (l.compare (0, 5, "url: ") == 0) { @@ -177,7 +193,7 @@ namespace butl if (!v.empty ()) try { - r.url = url (v); + pi.url = url (v); } catch (const invalid_argument& e) { @@ -186,17 +202,17 @@ namespace butl } else if (l.compare (0, 10, "src_root: ") == 0) { - r.src_root = parse_dir (string (l, 10), "src_root"); + pi.src_root = parse_dir (string (l, 10), "src_root"); } else if (l.compare (0, 10, "out_root: ") == 0) { - r.out_root = parse_dir (string (l, 10), "out_root"); + pi.out_root = parse_dir (string (l, 10), "out_root"); } else if (l.compare (0, 14, "amalgamation: ") == 0) { string v (l, 14); if (!v.empty ()) - r.amalgamation = parse_dir (move (v), "amalgamation"); + pi.amalgamation = parse_dir (move (v), "amalgamation"); } else if (l.compare (0, 13, "subprojects: ") == 0) { @@ -214,7 +230,7 @@ namespace butl if (p != 0) sn = parse_name (string (s, 0, p), "subproject"); - r.subprojects.push_back ( + pi.subprojects.push_back ( b_project_info::subproject {move (sn), parse_dir (string (s, p + 1), "subproject")}); @@ -224,20 +240,36 @@ namespace butl { string v (l, 12); for (size_t b (0), e (0); next_word (v, b, e); ) - r.operations.push_back (string (v, b, e - b)); + pi.operations.push_back (string (v, b, e - b)); } else if (l.compare (0, 17, "meta-operations: ") == 0) { string v (l, 17); for (size_t b (0), e (0); next_word (v, b, e); ) - r.meta_operations.push_back (string (v, b, e - b)); + pi.meta_operations.push_back (string (v, b, e - b)); + } + else if (l.compare (0, 9, "modules: ") == 0) + { + string v (l, 9); + for (size_t b (0), e (0); next_word (v, b, e); ) + pi.modules.push_back (string (v, b, e - b)); } } is.close (); // Detect errors. if (pr.wait ()) - return r; + { + add_project (); // Add the remaining project info. + + if (r.size () - rn == projects.size ()) + return; + + ostringstream os; + os << "invalid " << pp << " output: expected information for " + << projects.size () << " projects instead of " << r.size () - rn; + throw b_error (os.str (), move (pr.exit)); + } } // Note that ios::failure inherits from std::runtime_error, so this // catch-clause must go last. @@ -276,7 +308,7 @@ namespace butl assert (!pr.wait ()); throw b_error ( - string ("process ") + pp.recall_string () + " " + to_string (*pr.exit), + string ("process ") + pp.recall_string () + ' ' + to_string (*pr.exit), move (pr.exit)); } catch (const process_error& e) |