From 67d7cdd57d3076ccf4c44de3a6b8045bb67d1441 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Sat, 9 Oct 2021 22:03:13 +0300 Subject: Add package_manifest constructors accepting manifest values list --- libbpkg/manifest.cxx | 221 ++++++++++++++++++++++++++++++++++++--------------- libbpkg/manifest.hxx | 42 +++++++++- 2 files changed, 197 insertions(+), 66 deletions(-) diff --git a/libbpkg/manifest.cxx b/libbpkg/manifest.cxx index ef91381..c8bf456 100644 --- a/libbpkg/manifest.cxx +++ b/libbpkg/manifest.cxx @@ -1074,26 +1074,69 @@ namespace bpkg // dependency_alternatives // - ostream& - operator<< (ostream& o, const dependency_alternatives& as) + dependency_alternatives:: + dependency_alternatives (const std::string& s) { - if (as.conditional) - o << '?'; + using std::string; + + // Allow specifying ?* in any order. + // + size_t n (s.size ()); + size_t cond ((n > 0 && s[0] == '?') || (n > 1 && s[1] == '?') ? 1 : 0); + size_t btim ((n > 0 && s[0] == '*') || (n > 1 && s[1] == '*') ? 1 : 0); + + auto vc (parser::split_comment (s)); + + conditional = (cond != 0); + buildtime = (btim != 0); + comment = move (vc.second); - if (as.buildtime) - o << '*'; + const string& vl (vc.first); + + string::const_iterator b (vl.begin ()); + string::const_iterator e (vl.end ()); - if (as.conditional || as.buildtime) - o << ' '; + if (conditional || buildtime) + { + string::size_type p (vl.find_first_not_of (spaces, cond + btim)); + b = p == string::npos ? e : b + p; + } + + list_parser lp (b, e, '|'); + for (string lv (lp.next ()); !lv.empty (); lv = lp.next ()) + push_back (dependency (move (lv))); + } + + string dependency_alternatives:: + string () const + { + using std::string; + + string r; + + if (conditional) + r += '?'; + + if (buildtime) + r += '*'; + + if (conditional || buildtime) + r += ' '; bool f (true); - for (const dependency& a: as) - o << (f ? (f = false, "") : " | ") << a; + for (const dependency& a: *this) + { + r += (f ? (f = false, "") : " | "); + r += a.string (); + } - if (!as.comment.empty ()) - o << "; " << as.comment; + if (!comment.empty ()) + { + r += "; "; + r += comment; + } - return o; + return r; } // requirement_alternatives @@ -1746,29 +1789,25 @@ namespace bpkg const version stub_version (0, "0", nullopt, nullopt, 0); + // Parse until next() returns end-of-manifest value. + // static void parse_package_manifest ( - parser& p, - name_value nv, - const function& tf, + const string& name, + const function& next, + const function& translate, bool iu, bool cd, package_manifest_flags fl, package_manifest& m) { - auto bad_name ([&p, &nv](const string& d) { - throw parsing (p.name (), nv.name_line, nv.name_column, d);}); + name_value nv; - auto bad_value ([&p, &nv](const string& d) { - throw parsing (p.name (), nv.value_line, nv.value_column, d);}); + auto bad_name ([&name, &nv](const string& d) { + throw parsing (name, nv.name_line, nv.name_column, d);}); - // Make sure this is the start and we support the version. - // - if (!nv.name.empty ()) - bad_name ("start of package manifest expected"); - - if (nv.value != "1") - bad_value ("unsupported format version"); + auto bad_value ([&name, &nv](const string& d) { + throw parsing (name, nv.value_line, nv.value_column, d);}); auto parse_email = [&bad_name] (const name_value& nv, optional& r, @@ -1866,7 +1905,7 @@ namespace bpkg optional description; optional description_type; - for (nv = p.next (); !nv.empty (); nv = p.next ()) + for (nv = next (); !nv.empty (); nv = next ()) { string& n (nv.name); string& v (nv.value); @@ -1905,9 +1944,9 @@ namespace bpkg if (m.version.release && m.version.release->empty ()) bad_value ("invalid package version release"); - if (tf) + if (translate) { - tf (m.version); + translate (m.version); // Re-validate the version after the translation. // @@ -2055,7 +2094,7 @@ namespace bpkg } else if (n == "email") { - parse_email (nv, m.email, "project", p.name ()); + parse_email (nv, m.email, "project", name); } else if (n == "doc-url") { @@ -2080,19 +2119,19 @@ namespace bpkg } else if (n == "package-email") { - parse_email (nv, m.package_email, "package", p.name ()); + parse_email (nv, m.package_email, "package", name); } else if (n == "build-email") { - parse_email (nv, m.build_email, "build", p.name (), true /* empty */); + parse_email (nv, m.build_email, "build", name, true /* empty */); } else if (n == "build-warning-email") { - parse_email (nv, m.build_warning_email, "build warning", p.name ()); + parse_email (nv, m.build_warning_email, "build warning", name); } else if (n == "build-error-email") { - parse_email (nv, m.build_error_email, "build error", p.name ()); + parse_email (nv, m.build_error_email, "build error", name); } else if (n == "priority") { @@ -2157,17 +2196,17 @@ namespace bpkg else if (n == "builds") { m.builds.push_back ( - parse_build_class_expr (nv, m.builds.empty (), p.name ())); + parse_build_class_expr (nv, m.builds.empty (), name)); } else if (n == "build-include") { m.build_constraints.push_back ( - parse_build_constraint (nv, false /* exclusion */, p.name ())); + parse_build_constraint (nv, false /* exclusion */, name)); } else if (n == "build-exclude") { m.build_constraints.push_back ( - parse_build_constraint (nv, true /* exclusion */, p.name ())); + parse_build_constraint (nv, true /* exclusion */, name)); } else if (n == "depends") { @@ -2371,41 +2410,24 @@ namespace bpkg const string& v (nv.value); - // Allow specifying ?* in any order. + // Parse dependency alternatives. // - size_t n (v.size ()); - size_t cond ((n > 0 && v[0] == '?') || (n > 1 && v[1] == '?') ? 1 : 0); - size_t btim ((n > 0 && v[0] == '*') || (n > 1 && v[1] == '*') ? 1 : 0); - - auto vc (parser::split_comment (v)); - - const string& vl (vc.first); - dependency_alternatives da (cond != 0, btim != 0, move (vc.second)); + try + { + dependency_alternatives da (v); - string::const_iterator b (vl.begin ()); - string::const_iterator e (vl.end ()); + if (da.empty ()) + bad_value ("empty package dependency specification"); - if (da.conditional || da.buildtime) - { - string::size_type p (vl.find_first_not_of (spaces, cond + btim)); - b = p == string::npos ? e : b + p; - } + for (dependency& d: da) + d = complete_constraint (move (d)); - try - { - list_parser lp (b, e, '|'); - for (string lv (lp.next ()); !lv.empty (); lv = lp.next ()) - da.push_back (complete_constraint (dependency (move (lv)))); + m.dependencies.push_back (move (da)); } catch (const invalid_argument& e) { bad_value (e.what ()); } - - if (da.empty ()) - bad_value ("empty package dependency specification"); - - m.dependencies.push_back (da); } // Parse the test dependencies. @@ -2439,6 +2461,37 @@ namespace bpkg bad_name ("no package sha256sum specified"); } + static void + parse_package_manifest ( + parser& p, + name_value nv, + const function& tf, + bool iu, + bool cd, + package_manifest_flags fl, + package_manifest& m) + { + // Make sure this is the start and we support the version. + // + if (!nv.name.empty ()) + throw parsing (p.name (), nv.name_line, nv.name_column, + "start of package manifest expected"); + + if (nv.value != "1") + throw parsing (p.name (), nv.value_line, nv.value_column, + "unsupported format version"); + + // Note that we rely on "small function object" optimization here. + // + parse_package_manifest (p.name (), + [&p] () {return p.next ();}, + tf, + iu, + cd, + fl, + m); + } + package_manifest pkg_package_manifest (parser& p, name_value nv, bool iu) { @@ -2483,6 +2536,46 @@ namespace bpkg } package_manifest:: + package_manifest (const string& name, + vector&& vs, + const function& tf, + bool iu, + bool cd, + package_manifest_flags fl) + { + auto i (vs.begin ()); + auto e (vs.end ()); + + // Note that we rely on "small function object" optimization here. + // + parse_package_manifest (name, + [&i, &e] () + { + return i != e ? move (*i++) : name_value (); + }, + tf, + iu, + cd, + fl, + *this); + } + + package_manifest:: + package_manifest (const string& name, + vector&& vs, + bool iu, + bool cd, + package_manifest_flags fl) + : package_manifest (name, + move (vs), + function (), + iu, + cd, + fl) + { + } + + package_manifest:: package_manifest (manifest_parser& p, name_value nv, bool iu, diff --git a/libbpkg/manifest.hxx b/libbpkg/manifest.hxx index 4aa9b73..8a11a85 100644 --- a/libbpkg/manifest.hxx +++ b/libbpkg/manifest.hxx @@ -429,10 +429,23 @@ namespace bpkg dependency_alternatives () = default; dependency_alternatives (bool d, bool b, std::string c) : conditional (d), buildtime (b), comment (std::move (c)) {} + + // Parse the dependency alternatives string representation in the + // `[?][*] [ '|' ]* [; ]` form. Throw + // std::invalid_argument if the value is invalid. + // + explicit LIBBPKG_EXPORT + dependency_alternatives (const std::string&); + + LIBBPKG_EXPORT std::string + string () const; }; - LIBBPKG_EXPORT std::ostream& - operator<< (std::ostream&, const dependency_alternatives&); + inline std::ostream& + operator<< (std::ostream& os, const dependency_alternatives& da) + { + return os << da.string (); + } // requires // @@ -846,6 +859,31 @@ namespace bpkg package_manifest_flags::forbid_sha256sum | package_manifest_flags::forbid_fragment); + // As above but construct the package manifest from the pre-parsed + // manifest values list. + // + // Note that the list is expected not to contain the format version nor + // the end-of-manifest/stream pairs. + // + package_manifest (const std::string& name, + std::vector&&, + bool ignore_unknown = false, + bool complete_dependencies = true, + package_manifest_flags = + package_manifest_flags::forbid_location | + package_manifest_flags::forbid_sha256sum | + package_manifest_flags::forbid_fragment); + + package_manifest (const std::string& name, + std::vector&&, + const std::function&, + bool ignore_unknown = false, + bool complete_depends = true, + package_manifest_flags = + package_manifest_flags::forbid_location | + package_manifest_flags::forbid_sha256sum | + package_manifest_flags::forbid_fragment); + // Create an element of the list manifest. // package_manifest (butl::manifest_parser&, -- cgit v1.1