aboutsummaryrefslogtreecommitdiff
path: root/libbpkg/manifest.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbpkg/manifest.hxx')
-rw-r--r--libbpkg/manifest.hxx888
1 files changed, 579 insertions, 309 deletions
diff --git a/libbpkg/manifest.hxx b/libbpkg/manifest.hxx
index 499d64d..feb3b96 100644
--- a/libbpkg/manifest.hxx
+++ b/libbpkg/manifest.hxx
@@ -10,8 +10,7 @@
#include <cassert>
#include <cstdint> // uint*_t
#include <ostream>
-#include <utility> // move()
-#include <stdexcept> // logic_error
+#include <utility> // move(), pair
#include <functional>
#include <libbutl/url.hxx>
@@ -102,7 +101,7 @@ namespace bpkg
version (version&&) = default;
version (const version&) = default;
- version& operator= (version&&);
+ version& operator= (version&&) noexcept;
version& operator= (const version&);
// If the revision is ignored, then the iteration (that semantically
@@ -111,23 +110,12 @@ namespace bpkg
std::string
string (bool ignore_revision = false, bool ignore_iteration = false) const;
- bool
- operator< (const version& v) const noexcept {return compare (v) < 0;}
-
- bool
- operator> (const version& v) const noexcept {return compare (v) > 0;}
-
- bool
- operator== (const version& v) const noexcept {return compare (v) == 0;}
-
- bool
- operator<= (const version& v) const noexcept {return compare (v) <= 0;}
-
- bool
- operator>= (const version& v) const noexcept {return compare (v) >= 0;}
-
- bool
- operator!= (const version& v) const noexcept {return compare (v) != 0;}
+ bool operator< (const version& v) const noexcept;
+ bool operator> (const version& v) const noexcept;
+ bool operator== (const version& v) const noexcept;
+ bool operator<= (const version& v) const noexcept;
+ bool operator>= (const version& v) const noexcept;
+ bool operator!= (const version& v) const noexcept;
// If the revision is ignored, then the iteration is also ignored,
// regardless of the argument (see above for details).
@@ -135,28 +123,7 @@ namespace bpkg
int
compare (const version& v,
bool ignore_revision = false,
- bool ignore_iteration = false) const noexcept
- {
- if (epoch != v.epoch)
- return epoch < v.epoch ? -1 : 1;
-
- if (int c = canonical_upstream.compare (v.canonical_upstream))
- return c;
-
- if (int c = canonical_release.compare (v.canonical_release))
- return c;
-
- if (!ignore_revision)
- {
- if (revision != v.revision)
- return revision < v.revision ? -1 : 1;
-
- if (!ignore_iteration && iteration != v.iteration)
- return iteration < v.iteration ? -1 : 1;
- }
-
- return 0;
- }
+ bool ignore_iteration = false) const noexcept;
bool
empty () const noexcept
@@ -207,33 +174,10 @@ namespace bpkg
return os << (v.empty () ? "<empty-version>" : v.string ());
}
- inline version::flags
- operator&= (version::flags& x, version::flags y)
- {
- return x = static_cast<version::flags> (
- static_cast<std::uint16_t> (x) &
- static_cast<std::uint16_t> (y));
- }
-
- inline version::flags
- operator|= (version::flags& x, version::flags y)
- {
- return x = static_cast<version::flags> (
- static_cast<std::uint16_t> (x) |
- static_cast<std::uint16_t> (y));
- }
-
- inline version::flags
- operator& (version::flags x, version::flags y)
- {
- return x &= y;
- }
-
- inline version::flags
- operator| (version::flags x, version::flags y)
- {
- return x |= y;
- }
+ version::flags operator& (version::flags, version::flags);
+ version::flags operator| (version::flags, version::flags);
+ version::flags operator&= (version::flags&, version::flags);
+ version::flags operator|= (version::flags&, version::flags);
// priority
//
@@ -251,11 +195,17 @@ namespace bpkg
operator value_type () const {return value;}
};
- // description
- // description-file
- // change
- // change-file
+ // language
//
+ struct language
+ {
+ std::string name;
+ bool impl; // True if implementation-only.
+
+ language (): impl (false) {}
+ language (std::string n, bool i): name (std::move (n)), impl (i) {}
+ };
+
class LIBBPKG_EXPORT text_file
{
public:
@@ -281,14 +231,80 @@ namespace bpkg
text_file (path_type p, std::string c)
: file (true), path (std::move (p)), comment (std::move (c)) {}
- text_file (text_file&&);
+ text_file (text_file&&) noexcept;
text_file (const text_file&);
- text_file& operator= (text_file&&);
+ text_file& operator= (text_file&&) noexcept;
text_file& operator= (const text_file&);
~text_file ();
};
+ enum class text_type
+ {
+ plain,
+ common_mark,
+ github_mark
+ };
+
+ LIBBPKG_EXPORT std::string
+ to_string (text_type);
+
+ // Throw std::invalid_argument if the argument is not a well-formed text
+ // type. Otherwise, return nullopt for an unknown text variant.
+ //
+ LIBBPKG_EXPORT butl::optional<text_type>
+ to_text_type (const std::string&);
+
+ inline std::ostream&
+ operator<< (std::ostream& os, text_type t)
+ {
+ return os << to_string (t);
+ }
+
+ // description
+ // description-file
+ // description-type
+ // package-description
+ // package-description-file
+ // package-description-type
+ // change
+ // change-file
+ // change-type
+ //
+ class LIBBPKG_EXPORT typed_text_file: public text_file
+ {
+ public:
+ butl::optional<std::string> type;
+
+ // File text constructor.
+ //
+ explicit
+ typed_text_file (std::string s = "",
+ butl::optional<std::string> t = butl::nullopt)
+ : text_file (std::move (s)), type (std::move (t)) {}
+
+ // File reference constructor.
+ //
+ typed_text_file (path_type p,
+ std::string c,
+ butl::optional<std::string> t = butl::nullopt)
+ : text_file (std::move (p), std::move (c)), type (std::move (t)) {}
+
+ // Return the type value if present, text_type::github_mark if it refers
+ // to a file with the .md or .markdown extension and text_type::plain if
+ // it refers to a file with the .txt extension or no extension or the text
+ // does not come from a file. Depending on the ignore_unknown value either
+ // throw std::invalid_argument or return nullopt if the type value or the
+ // file extension is unknown.
+ //
+ // Note: also throws std::invalid_argument if the type is not well-formed.
+ // This, however, may not happen for an object created by the package
+ // manifest parser since it has already verified that.
+ //
+ butl::optional<text_type>
+ effective_type (bool ignore_unknown = false) const;
+ };
+
// license
//
class licenses: public butl::small_vector<std::string, 1>
@@ -415,17 +431,10 @@ namespace bpkg
}
inline bool
- operator== (const version_constraint& x, const version_constraint& y)
- {
- return x.min_version == y.min_version && x.max_version == y.max_version &&
- x.min_open == y.min_open && x.max_open == y.max_open;
- }
+ operator== (const version_constraint&, const version_constraint&);
inline bool
- operator!= (const version_constraint& x, const version_constraint& y)
- {
- return !(x == y);
- }
+ operator!= (const version_constraint&, const version_constraint&);
struct LIBBPKG_EXPORT dependency
{
@@ -447,11 +456,8 @@ namespace bpkg
string () const;
};
- inline std::ostream&
- operator<< (std::ostream& os, const dependency& d)
- {
- return os << d.string ();
- }
+ std::ostream&
+ operator<< (std::ostream&, const dependency&);
// depends
//
@@ -516,6 +522,12 @@ namespace bpkg
// <reflect-config> - buildfile fragment containing dependent package
// configuration variables assignments
//
+ // In the multi-line form the block may contain comments besides the
+ // clauses. The '#' character starts a single-line comment which spans
+ // until the end of the line. Unless it is followed with '\' followed by
+ // the newline in which case this is a multi-line comment which spans
+ // until the closing '#\' is encountered.
+ //
// The dependency alternative is only considered by bpkg if the enable
// condition evaluates to true. If the enable clause is not specified, then
// it is always considered.
@@ -561,6 +573,22 @@ namespace bpkg
accept (std::move (a)),
require (std::move (q)) {}
+ // Can be used to copy a dependency alternative object, while omitting
+ // some clauses which are no longer needed.
+ //
+ dependency_alternative (butl::optional<std::string> e,
+ butl::optional<std::string> r,
+ butl::optional<std::string> p,
+ butl::optional<std::string> a,
+ butl::optional<std::string> q,
+ butl::small_vector<dependency, 1> ds)
+ : small_vector<dependency, 1> (move (ds)),
+ enable (std::move (e)),
+ reflect (std::move (r)),
+ prefer (std::move (p)),
+ accept (std::move (a)),
+ require (std::move (q)) {}
+
// Return the single-line representation if possible (the prefer and
// require clauses are absent and the reflect clause either absent or
// contains no newlines).
@@ -571,10 +599,21 @@ namespace bpkg
// Return true if the string() function would return the single-line
// representation.
//
- LIBBPKG_EXPORT bool
- single_line () const;
+ bool
+ single_line () const
+ {
+ return !prefer &&
+ !require &&
+ (!reflect || reflect->find ('\n') == std::string::npos);
+ }
};
+ inline std::ostream&
+ operator<< (std::ostream& os, const dependency_alternative& da)
+ {
+ return os << da.string ();
+ }
+
class dependency_alternatives:
public butl::small_vector<dependency_alternative, 1>
{
@@ -622,14 +661,14 @@ namespace bpkg
// Return true if there is a conditional alternative in the list.
//
- LIBBPKG_EXPORT bool
+ bool
conditional () const;
};
inline std::ostream&
- operator<< (std::ostream& os, const dependency_alternatives& da)
+ operator<< (std::ostream& os, const dependency_alternatives& das)
{
- return os << da.string ();
+ return os << das.string ();
}
// requires
@@ -673,8 +712,11 @@ namespace bpkg
// Return true if the string() function would return the single-line
// representation.
//
- LIBBPKG_EXPORT bool
- single_line () const;
+ bool
+ single_line () const
+ {
+ return !reflect || reflect->find ('\n') == std::string::npos;
+ }
// Return true if this is a single requirement with an empty id or an
// empty enable condition.
@@ -727,7 +769,7 @@ namespace bpkg
// Return true if there is a conditional alternative in the list.
//
- LIBBPKG_EXPORT bool
+ bool
conditional () const;
// Return true if this is a single simple requirement alternative.
@@ -748,7 +790,7 @@ namespace bpkg
class build_constraint
{
public:
- // If true, then the package should not be built for matching
+ // If true, then the package should not be built for matching target
// configurations by automated build bots.
//
bool exclusion;
@@ -783,48 +825,33 @@ namespace bpkg
//
enum class package_manifest_flags: std::uint16_t
{
- none = 0x00,
-
- forbid_file = 0x01, // Forbid *-file manifest values.
- forbid_location = 0x02,
- forbid_sha256sum = 0x04,
- forbid_fragment = 0x08,
- forbid_incomplete_dependencies = 0x10,
-
- require_location = 0x20,
- require_sha256sum = 0x40,
- require_description_type = 0x80
+ none = 0x000,
+
+ forbid_file = 0x001, // Forbid *-file manifest values.
+ forbid_location = 0x002,
+ forbid_sha256sum = 0x004,
+ forbid_fragment = 0x008,
+ forbid_incomplete_values = 0x010, // depends, <distribution>-version, etc.
+
+ require_location = 0x020,
+ require_sha256sum = 0x040,
+ require_text_type = 0x080, // description-type, changes-type, etc.
+ require_bootstrap_build = 0x100
};
- inline package_manifest_flags
- operator&= (package_manifest_flags& x, package_manifest_flags y)
- {
- return x = static_cast<package_manifest_flags> (
- static_cast<std::uint16_t> (x) &
- static_cast<std::uint16_t> (y));
- }
+ package_manifest_flags
+ operator& (package_manifest_flags, package_manifest_flags);
- inline package_manifest_flags
- operator|= (package_manifest_flags& x, package_manifest_flags y)
- {
- return x = static_cast<package_manifest_flags> (
- static_cast<std::uint16_t> (x) |
- static_cast<std::uint16_t> (y));
- }
+ package_manifest_flags
+ operator| (package_manifest_flags, package_manifest_flags);
- inline package_manifest_flags
- operator& (package_manifest_flags x, package_manifest_flags y)
- {
- return x &= y;
- }
+ package_manifest_flags
+ operator&= (package_manifest_flags&, package_manifest_flags);
- inline package_manifest_flags
- operator| (package_manifest_flags x, package_manifest_flags y)
- {
- return x |= y;
- }
+ package_manifest_flags
+ operator|= (package_manifest_flags&, package_manifest_flags);
- // Build configuration class term.
+ // Target build configuration class term.
//
class LIBBPKG_EXPORT build_class_term
{
@@ -853,9 +880,9 @@ namespace bpkg
build_class_term ()
: operation ('\0'), inverted (false), simple (true), name () {}
- build_class_term (build_class_term&&);
+ build_class_term (build_class_term&&) noexcept;
build_class_term (const build_class_term&);
- build_class_term& operator= (build_class_term&&);
+ build_class_term& operator= (build_class_term&&) noexcept;
build_class_term& operator= (const build_class_term&);
~build_class_term ();
@@ -874,8 +901,8 @@ namespace bpkg
//
using build_class_inheritance_map = std::map<std::string, std::string>;
- // Build configuration class expression. Includes comment and optional
- // underlying set.
+ // Target build configuration class expression. Includes comment and
+ // optional underlying set.
//
class LIBBPKG_EXPORT build_class_expr
{
@@ -924,10 +951,10 @@ namespace bpkg
std::string
string () const;
- // Match a build configuration that belongs to the specified list of
- // classes (and recursively to their bases) against the expression. Either
- // return or update the result (the latter allows to sequentially matching
- // against a list of expressions).
+ // Match a target build configuration that belongs to the specified list
+ // of classes (and recursively to their bases) against the expression.
+ // Either return or update the result (the latter allows to sequentially
+ // matching against a list of expressions).
//
// Notes:
//
@@ -935,7 +962,8 @@ namespace bpkg
// inheritance cycles, etc.).
//
// - The underlying class set doesn't affect the match in any way (it
- // should have been used to pre-filter the set of build configurations).
+ // should have been used to pre-filter the set of target build
+ // configurations).
//
void
match (const strings&,
@@ -943,12 +971,7 @@ namespace bpkg
bool& result) const;
bool
- match (const strings& cs, const build_class_inheritance_map& bs) const
- {
- bool r (false);
- match (cs, bs, r);
- return r;
- }
+ match (const strings&, const build_class_inheritance_map&) const;
};
inline std::ostream&
@@ -957,27 +980,173 @@ namespace bpkg
return os << bce.string ();
}
- enum class text_type
+ // Build auxiliary configuration name-matching wildcard. Includes optional
+ // environment name (specified as a suffix in the [*-]build-auxiliary[-*]
+ // value name) and comment.
+ //
+ class LIBBPKG_EXPORT build_auxiliary
{
- plain,
- common_mark,
- github_mark
- };
+ public:
+ std::string environment_name;
- LIBBPKG_EXPORT std::string
- to_string (text_type);
+ // Filesystem wildcard pattern for the build auxiliary configuration name.
+ //
+ std::string config;
- // Throw std::invalid_argument if the argument is not a well-formed text
- // type. Otherwise, return nullopt for an unknown text variant.
- //
- LIBBPKG_EXPORT butl::optional<text_type>
- to_text_type (const std::string&); // May throw std::invalid_argument.
+ std::string comment;
- inline std::ostream&
- operator<< (std::ostream& os, text_type t)
+ build_auxiliary () = default;
+ build_auxiliary (std::string en,
+ std::string cf,
+ std::string cm)
+ : environment_name (std::move (en)),
+ config (std::move (cf)),
+ comment (std::move (cm)) {}
+
+ // Parse a package manifest value name in the [*-]build-auxiliary[-*] form
+ // into the pair of the build package configuration name (first) and the
+ // build auxiliary environment name (second), with an unspecified name
+ // represented as an empty string. Return nullopt if the value name
+ // doesn't match this form.
+ //
+ static butl::optional<std::pair<std::string, std::string>>
+ parse_value_name (const std::string&);
+ };
+
+ // Package build configuration. Includes comment and optional overrides for
+ // target build configuration class expressions/constraints, auxiliaries,
+ // custom bot public keys, and notification emails.
+ //
+ // Note that in the package manifest the build bot keys list contains the
+ // public keys data (std::string type). However, for other use cases it may
+ // be convenient to store some other key representations (public key object
+ // pointers represented as key fingerprints, etc; see brep for such a use
+ // case).
+ //
+ template <typename K>
+ class build_package_config_template
{
- return os << to_string (t);
- }
+ public:
+ using email_type = bpkg::email;
+ using key_type = K;
+
+ std::string name;
+
+ // Whitespace separated list of potentially double/single-quoted package
+ // configuration arguments for bpkg-pkg-build command executed by
+ // automated build bots.
+ //
+ std::string arguments;
+
+ std::string comment;
+
+ butl::small_vector<build_class_expr, 1> builds;
+ std::vector<build_constraint> constraints;
+
+ // Note that all entries in this list must have distinct environment names
+ // (with empty name being one of the possibilities).
+ //
+ std::vector<build_auxiliary> auxiliaries;
+
+ std::vector<key_type> bot_keys;
+
+ butl::optional<email_type> email;
+ butl::optional<email_type> warning_email;
+ butl::optional<email_type> error_email;
+
+ build_package_config_template () = default;
+
+ build_package_config_template (std::string n,
+ std::string a,
+ std::string c,
+ butl::small_vector<build_class_expr, 1> bs,
+ std::vector<build_constraint> cs,
+ std::vector<build_auxiliary> as,
+ std::vector<key_type> bks,
+ butl::optional<email_type> e,
+ butl::optional<email_type> we,
+ butl::optional<email_type> ee)
+ : name (move (n)),
+ arguments (move (a)),
+ comment (move (c)),
+ builds (move (bs)),
+ constraints (move (cs)),
+ auxiliaries (move (as)),
+ bot_keys (move (bks)),
+ email (move (e)),
+ warning_email (move (we)),
+ error_email (move (ee)) {}
+
+ // Built incrementally.
+ //
+ explicit
+ build_package_config_template (std::string n): name (move (n)) {}
+
+ // Return the configuration's build class expressions/constraints if they
+ // override the specified common expressions/constraints and return the
+ // latter otherwise (see package_manifest::override() for the override
+ // semantics details).
+ //
+ const butl::small_vector<build_class_expr, 1>&
+ effective_builds (const butl::small_vector<build_class_expr, 1>& common)
+ const noexcept
+ {
+ return !builds.empty () ? builds : common;
+ }
+
+ const std::vector<build_constraint>&
+ effective_constraints (const std::vector<build_constraint>& common) const
+ noexcept
+ {
+ return !builds.empty () || !constraints.empty () ? constraints : common;
+ }
+
+ // Return the configuration's auxiliaries, if specified, and the common
+ // ones otherwise.
+ //
+ const std::vector<build_auxiliary>&
+ effective_auxiliaries (const std::vector<build_auxiliary>& common) const
+ noexcept
+ {
+ return !auxiliaries.empty () ? auxiliaries : common;
+ }
+
+ // Return the configuration's custom bot public keys, if specified, and
+ // the common ones otherwise.
+ //
+ const std::vector<key_type>&
+ effective_bot_keys (const std::vector<key_type>& common) const noexcept
+ {
+ return !bot_keys.empty () ? bot_keys : common;
+ }
+
+ // Return the configuration's build notification emails if they override
+ // the specified common build notification emails and return the latter
+ // otherwise (see package_manifest::override() for the override semantics
+ // details).
+ //
+ const butl::optional<email_type>&
+ effective_email (const butl::optional<email_type>& common) const noexcept
+ {
+ return email || warning_email || error_email ? email : common;
+ }
+
+ const butl::optional<email_type>&
+ effective_warning_email (const butl::optional<email_type>& common) const
+ noexcept
+ {
+ return email || warning_email || error_email ? warning_email : common;
+ }
+
+ const butl::optional<email_type>&
+ effective_error_email (const butl::optional<email_type>& common) const
+ noexcept
+ {
+ return email || warning_email || error_email ? error_email : common;
+ }
+ };
+
+ using build_package_config = build_package_config_template<std::string>;
enum class test_dependency_type
{
@@ -1004,27 +1173,91 @@ namespace bpkg
{
test_dependency_type type;
bool buildtime;
+ butl::optional<std::string> enable;
+ butl::optional<std::string> reflect;
test_dependency () = default;
test_dependency (package_name n,
test_dependency_type t,
bool b,
- butl::optional<version_constraint> c)
- : dependency {std::move (n), std::move (c)}, type (t), buildtime (b) {}
+ butl::optional<version_constraint> c,
+ butl::optional<std::string> e,
+ butl::optional<std::string> r)
+ : dependency {std::move (n), std::move (c)},
+ type (t),
+ buildtime (b),
+ enable (std::move (e)),
+ reflect (std::move (r)) {}
// Parse the test dependency string representation in the
- // `[*] <name> [<version-constraint>]` form. Throw std::invalid_argument
- // if the value is invalid.
+ // `[*] <name> [<version-constraint>] ['?' <enable-condition>] [<reflect-config>]`
+ // form. Throw std::invalid_argument if the value is invalid.
+ //
+ // Verify that the reflect clause, if present, refers to the test
+ // dependency package configuration variable. Note that such variable
+ // value normally signals the dependent package being tested.
//
test_dependency (std::string, test_dependency_type);
- inline std::string
- string () const
- {
- return buildtime
- ? "* " + dependency::string ()
- : dependency::string ();
- }
+ std::string
+ string () const;
+ };
+
+ // Package's buildfile path and content.
+ //
+ struct buildfile
+ {
+ // The path is relative to the package's build/ subdirectory with the
+ // extension stripped.
+ //
+ // For example, for the build/config/common.build file the path will be
+ // config/common.
+ //
+ // Note that the actual file path depends on the project's buildfile
+ // naming scheme and for the config/common example above the actual path
+ // can also be build2/config/common.build2.
+ //
+ butl::path path;
+ std::string content;
+
+ buildfile () = default;
+ buildfile (butl::path p, std::string c)
+ : path (std::move (p)),
+ content (std::move (c)) {}
+ };
+
+ // Binary distribution package information.
+ //
+ // The name is prefixed with the <distribution> id, typically name/version
+ // pair in the <name>[_<version>] form. For example:
+ //
+ // debian-name
+ // debian_10-name
+ // ubuntu_20.04-name
+ //
+ // Currently recognized names:
+ //
+ // <distribution>-name
+ // <distribution>-version
+ // <distribution>-to-downstream-version
+ //
+ // Note that the value format/semantics can be distribution-specific.
+ //
+ struct distribution_name_value
+ {
+ std::string name;
+ std::string value;
+
+ distribution_name_value () = default;
+ distribution_name_value (std::string n, std::string v)
+ : name (std::move (n)),
+ value (std::move (v)) {}
+
+ // Return the name's <distribution> component if the name has the
+ // specified suffix, which is assumed to be valid (-name, etc).
+ //
+ butl::optional<std::string>
+ distribution (const std::string& suffix) const;
};
class LIBBPKG_EXPORT package_manifest
@@ -1037,16 +1270,18 @@ namespace bpkg
package_name name;
version_type version;
butl::optional<std::string> upstream_version;
+ butl::optional<std::string> type; // <name>[, ...]
+ butl::small_vector<language, 1> languages; // <name>[=impl][, ...]
butl::optional<package_name> project;
butl::optional<priority_type> priority;
std::string summary;
-
butl::small_vector<licenses, 1> license_alternatives;
+
butl::small_vector<std::string, 5> topics;
butl::small_vector<std::string, 5> keywords;
- butl::optional<text_file> description;
- butl::optional<std::string> description_type;
- butl::small_vector<text_file, 1> changes;
+ butl::optional<typed_text_file> description;
+ butl::optional<typed_text_file> package_description;
+ butl::small_vector<typed_text_file, 1> changes;
butl::optional<manifest_url> url;
butl::optional<manifest_url> doc_url;
butl::optional<manifest_url> src_url;
@@ -1060,8 +1295,40 @@ namespace bpkg
std::vector<requirement_alternatives> requirements;
butl::small_vector<test_dependency, 1> tests;
+ // Common build classes, constraints, auxiliaries, and custom bot public
+ // keys that apply to all configurations unless overridden.
+ //
+ // Note that all entries in build_auxiliaries must have distinct
+ // environment names (with empty name being one of the possibilities).
+ //
butl::small_vector<build_class_expr, 1> builds;
std::vector<build_constraint> build_constraints;
+ std::vector<build_auxiliary> build_auxiliaries;
+ strings build_bot_keys;
+
+ // Note that the parsing constructor adds the implied (empty) default
+ // configuration at the beginning of the list. Also note that serialize()
+ // writes no values for such a configuration.
+ //
+ butl::small_vector<build_package_config, 1> build_configs; // 1 for default.
+
+ // If true, then this package use the alternative buildfile naming scheme
+ // (build2/, .build2). In the manifest serialization this is encoded as
+ // either *-build or *-build2 value names.
+ //
+ butl::optional<bool> alt_naming;
+
+ butl::optional<std::string> bootstrap_build;
+ butl::optional<std::string> root_build;
+
+ // Additional buildfiles which are potentially included by root.build.
+ //
+ std::vector<buildfile> buildfiles; // Buildfiles content.
+ std::vector<butl::path> buildfile_paths;
+
+ // The binary distributions package information.
+ //
+ std::vector<distribution_name_value> distribution_values;
// The following values are only valid in the manifest list (and only for
// certain repository types).
@@ -1070,19 +1337,45 @@ namespace bpkg
butl::optional<std::string> sha256sum;
butl::optional<std::string> fragment;
- const package_name&
- effective_project () const noexcept {return project ? *project : name;}
+ // Extract the name from optional type, returning either `exe`, `lib`, or
+ // `other`.
+ //
+ // Specifically, if type is present but the name is not recognized, then
+ // return `other`. If type is absent and the package name starts with the
+ // `lib` prefix, then return `lib`. Otherwise, return `exe`.
+ //
+ std::string
+ effective_type () const;
- // Return the description type value if present, text_type::github_mark if
- // the description refers to a file with the .md or .markdown extension
- // and text_type::plain if it refers to a file with the .txt extension or
- // no extension or the description does not come from a file. Depending on
- // the ignore_unknown value either throw std::invalid_argument or return
- // nullopt if the description value or the file extension is unknown.
- // Throw std::logic_error if the description value is nullopt.
+ static std::string
+ effective_type (const butl::optional<std::string>&, const package_name&);
+
+ // Extract sub-options from optional type.
//
- butl::optional<text_type>
- effective_description_type (bool ignore_unknown = false) const;
+ strings
+ effective_type_sub_options () const;
+
+ static strings
+ effective_type_sub_options (const butl::optional<std::string>&);
+
+ // Translate the potentially empty list of languages to a non-empty one.
+ //
+ // Specifically, if the list of languages is not empty, then return it as
+ // is. Otherwise, if the package name has an extension (as in, say,
+ // libbutl.bash), then return it as the language. Otherwise, return `cc`
+ // (unspecified c-common language).
+ //
+ butl::small_vector<language, 1>
+ effective_languages () const;
+
+ static butl::small_vector<language, 1>
+ effective_languages (const butl::small_vector<language, 1>&,
+ const package_name&);
+
+ // Return effective project name.
+ //
+ const package_name&
+ effective_project () const noexcept {return project ? *project : name;}
public:
package_manifest () = default;
@@ -1094,7 +1387,7 @@ namespace bpkg
//
package_manifest (butl::manifest_parser&,
bool ignore_unknown = false,
- bool complete_dependencies = true,
+ bool complete_values = true,
package_manifest_flags =
package_manifest_flags::forbid_location |
package_manifest_flags::forbid_sha256sum |
@@ -1116,7 +1409,7 @@ namespace bpkg
package_manifest (butl::manifest_parser&,
const std::function<translate_function>&,
bool ignore_unknown = false,
- bool complete_depends = true,
+ bool complete_values = true,
package_manifest_flags =
package_manifest_flags::forbid_location |
package_manifest_flags::forbid_sha256sum |
@@ -1131,7 +1424,7 @@ namespace bpkg
package_manifest (const std::string& name,
std::vector<butl::manifest_name_value>&&,
bool ignore_unknown = false,
- bool complete_dependencies = true,
+ bool complete_values = true,
package_manifest_flags =
package_manifest_flags::forbid_location |
package_manifest_flags::forbid_sha256sum |
@@ -1141,7 +1434,7 @@ namespace bpkg
std::vector<butl::manifest_name_value>&&,
const std::function<translate_function>&,
bool ignore_unknown = false,
- bool complete_depends = true,
+ bool complete_values = true,
package_manifest_flags =
package_manifest_flags::forbid_location |
package_manifest_flags::forbid_sha256sum |
@@ -1152,27 +1445,72 @@ namespace bpkg
package_manifest (butl::manifest_parser&,
butl::manifest_name_value start,
bool ignore_unknown,
- bool complete_depends,
+ bool complete_values,
package_manifest_flags);
// Override manifest values with the specified. Throw manifest_parsing if
// any value is invalid, cannot be overridden, or its name is not
// recognized.
//
- // The specified values override the whole groups they belong to,
- // resetting all the group values prior to being applied. Currently, only
- // the following value groups can be overridden: {build-*email} and
- // {builds, build-{include,exclude}}.
- //
- // Note that the build constraints group values are overridden
- // hierarchically so that the build-{include,exclude} overrides don't
- // affect the builds values.
+ // The specified values other than [*-]build-auxiliary[-*] override the
+ // whole groups they belong to, resetting all the group values prior to
+ // being applied. The [*-]build-auxiliary[-*] values only override the
+ // matching values, which are expected to already be present in the
+ // manifest. Currently, only the following value groups/values can be
+ // overridden:
+ //
+ // {build-*email}
+ // {builds, build-{include,exclude}}
+ // {build-bot}
+ // {*-builds, *-build-{include,exclude}}
+ // {*-build-bot}
+ // {*-build-config}
+ // {*-build-*email}
+ //
+ // [*-]build-auxiliary[-*]
+ //
+ // Throw manifest_parsing if the configuration specified by the build
+ // package configuration-specific build constraint, email, auxiliary, or
+ // custom bot public key value override doesn't exists. In contrast, for
+ // the build config override add a new configuration if it doesn't exist
+ // and update the arguments of the existing configuration otherwise. In
+ // the former case, all the potential build constraint, email, auxiliary,
+ // and bot key overrides for such a newly added configuration must follow
+ // the respective *-build-config override.
+ //
+ // Note that the build constraints group values (both common and build
+ // config-specific) are overridden hierarchically so that the
+ // [*-]build-{include,exclude} overrides don't affect the respective
+ // [*-]builds values.
+ //
+ // Also note that the common and build config-specific build constraints
+ // group value overrides are mutually exclusive. If the common build
+ // constraints are overridden, then all the build config-specific
+ // constraints are removed. Otherwise, if some build config-specific
+ // constraints are overridden, then for the remaining configs the build
+ // constraints are reset to `builds: none`.
+ //
+ // Similar to the build constraints groups, the common and build
+ // config-specific custom bot key value overrides are mutually
+ // exclusive. If the common custom bot keys are overridden, then all the
+ // build config-specific custom bot keys are removed. Otherwise, if some
+ // build config-specific custom bot keys are overridden, then for the
+ // remaining configs the custom bot keys are left unchanged.
+ //
+ // Similar to the above, the common and build config-specific build emails
+ // group value overrides are mutually exclusive. If the common build
+ // emails are overridden, then all the build config-specific emails are
+ // reset to nullopt. Otherwise, if some build config-specific emails are
+ // overridden, then for the remaining configs the email is reset to the
+ // empty value and the warning and error emails are reset to nullopt
+ // (which effectively disables email notifications for such
+ // configurations).
//
// If a non-empty source name is specified, then the specified values are
// assumed to also include the line/column information and the possibly
- // thrown manifest_parsing exception will contain the invalid value
+ // thrown manifest_parsing exception will contain the invalid value's
// location information. Otherwise, the exception description will refer
- // to the invalid value name instead.
+ // to the invalid value instead.
//
void
override (const std::vector<butl::manifest_name_value>&,
@@ -1180,6 +1518,13 @@ namespace bpkg
// Validate the overrides without applying them to any manifest.
//
+ // Specifically, validate that the override values can be parsed according
+ // to their name semantics and that the value sequence makes sense (no
+ // mutually exclusive values, etc). Note, however, that the subsequent
+ // applying of the successfully validated overrides to a specific package
+ // manifest may still fail (no build config exists for specified *-builds,
+ // etc).
+ //
static void
validate_overrides (const std::vector<butl::manifest_name_value>&,
const std::string& source_name);
@@ -1205,17 +1550,20 @@ namespace bpkg
// Load the *-file manifest values using the specified load function that
// returns the file contents passing through any exception it may throw.
- // Set the potentially absent description type value to the effective
- // description type. If the effective type is nullopt then assign a
- // synthetic unknown type.
+ // If nullopt is returned, then the respective *-file value is left
+ // unexpanded. Set the potentially absent project description, package
+ // description, and changes type values to their effective types. If an
+ // effective type is nullopt then assign a synthetic unknown type if the
+ // ignore_unknown argument is true and throw manifest_parsing otherwise.
//
// Note that if the returned file contents is empty, load_files() makes
// sure that this is allowed by the value's semantics throwing
// manifest_parsing otherwise. However, the load function may want to
// recognize such cases itself in order to issue more precise diagnostics.
//
- using load_function = std::string (const std::string& name,
- const butl::path& value);
+ using load_function =
+ butl::optional<std::string> (const std::string& name,
+ const butl::path& value);
void
load_files (const std::function<load_function>&,
@@ -1224,13 +1572,10 @@ namespace bpkg
// Create individual package manifest.
//
- inline package_manifest
+ package_manifest
pkg_package_manifest (butl::manifest_parser& p,
bool ignore_unknown = false,
- bool complete_depends = true)
- {
- return package_manifest (p, ignore_unknown, complete_depends);
- }
+ bool complete_values = true);
LIBBPKG_EXPORT package_manifest
dir_package_manifest (butl::manifest_parser&, bool ignore_unknown = false);
@@ -1536,9 +1881,8 @@ namespace bpkg
repository_type,
const repository_location& base);
- repository_location (const repository_location& l,
- const repository_location& base)
- : repository_location (l.url (), l.type (), base) {}
+ repository_location (const repository_location&,
+ const repository_location& base);
// Note that relative locations have no canonical name. Canonical name of
// an empty location is the empty name.
@@ -1556,59 +1900,22 @@ namespace bpkg
empty () const noexcept {return url_.empty ();}
bool
- local () const
- {
- if (empty ())
- throw std::logic_error ("empty location");
-
- return url_.scheme == repository_protocol::file;
- }
+ local () const;
bool
- remote () const
- {
- return !local ();
- }
+ remote () const;
bool
- absolute () const
- {
- if (empty ())
- throw std::logic_error ("empty location");
-
- // Note that in remote locations path is always relative.
- //
- return url_.path->absolute ();
- }
+ absolute () const;
bool
- relative () const
- {
- return local () && url_.path->relative ();
- }
+ relative () const;
repository_type
- type () const
- {
- if (empty ())
- throw std::logic_error ("empty location");
-
- return type_;
- }
+ type () const;
repository_basis
- basis () const
- {
- switch (type ())
- {
- case repository_type::pkg: return repository_basis::archive;
- case repository_type::dir: return repository_basis::directory;
- case repository_type::git: return repository_basis::version_control;
- }
-
- assert (false); // Can't be here.
- return repository_basis::archive;
- }
+ basis () const;
// Note that the URL of an empty location is empty.
//
@@ -1622,69 +1929,30 @@ namespace bpkg
// "directories" it always contains the trailing slash.
//
const butl::path&
- path () const
- {
- if (empty ())
- throw std::logic_error ("empty location");
-
- return *url_.path;
- }
+ path () const;
const std::string&
- host () const
- {
- if (local ())
- throw std::logic_error ("local location");
-
- return url_.authority->host;
- }
+ host () const;
// Value 0 indicated that no port was specified explicitly.
//
std::uint16_t
- port () const
- {
- if (local ())
- throw std::logic_error ("local location");
-
- return url_.authority->port;
- }
+ port () const;
repository_protocol
- proto () const
- {
- if (empty ())
- throw std::logic_error ("empty location");
-
- return url_.scheme;
- }
+ proto () const;
const butl::optional<std::string>&
- fragment () const
- {
- if (relative ())
- throw std::logic_error ("relative filesystem path");
-
- return url_.fragment;
- }
+ fragment () const;
bool
- archive_based () const
- {
- return basis () == repository_basis::archive;
- }
+ archive_based () const;
bool
- directory_based () const
- {
- return basis () == repository_basis::directory;
- }
+ directory_based () const;
bool
- version_control_based () const
- {
- return basis () == repository_basis::version_control;
- }
+ version_control_based () const;
// Return an untyped URL if the correct type can be guessed just from
// the URL. Otherwise, return the typed URL.
@@ -1981,4 +2249,6 @@ namespace bpkg
}
}
+#include <libbpkg/manifest.ixx>
+
#endif // LIBBPKG_MANIFEST_HXX