diff options
Diffstat (limited to 'mod/build-config.cxx')
-rw-r--r-- | mod/build-config.cxx | 122 |
1 files changed, 109 insertions, 13 deletions
diff --git a/mod/build-config.cxx b/mod/build-config.cxx index e838a59..5d3f46b 100644 --- a/mod/build-config.cxx +++ b/mod/build-config.cxx @@ -6,9 +6,10 @@ #include <map> #include <sstream> +#include <algorithm> // find() #include <libbutl/sha256.mxx> -#include <libbutl/utility.mxx> // throw_generic_error() +#include <libbutl/utility.mxx> // throw_generic_error(), alpha(), etc. #include <libbutl/openssl.mxx> #include <libbutl/filesystem.mxx> @@ -150,21 +151,116 @@ namespace brep } bool - match (const string& config_pattern, - const optional<string>& target_pattern, - const build_config& c) + exclude (const build_class_exprs& exprs, + const build_constraints& constrs, + const build_config& cfg, + string* reason) { - return path_match (config_pattern, c.name) && - (!target_pattern || path_match (*target_pattern, c.target.string ())); - } + // Save the first sentence of the reason, lower-case the first letter if + // the beginning looks like a word (the second character is the + // lower-case letter or space). + // + auto sanitize = [] (const string& reason) + { + string r (reason.substr (0, reason.find ('.'))); - bool - exclude (const build_package& p, const build_config& c) - { - for (const auto& bc: p.constraints) + char c; + size_t n (r.size ()); + + if (n > 0 && + alpha (c = r[0]) && + c == ucase (c) && + (n == 1 || (alpha (c = r[1]) && c == lcase (c)) || c == ' ')) + r[0] = lcase (r[0]); + + return r; + }; + + bool r (false); + + // First, match the configuration against the package underlying build + // class set and expressions. + // + // Determine the underlying class set. Note that in the future we can + // potentially extend the underlying set with the special classes. + // + build_class_expr ucs ( + !exprs.empty () && !exprs.front ().underlying_classes.empty () + ? exprs.front () + : build_class_expr ("default", "Default")); + + // Transform the combined package build configuration class expression, + // making the underlying class set a starting set for the original + // expression and a restricting set, simultaneously. For example, for the + // expression: + // + // default legacy : -msvc + // + // the resulting expression will be: + // + // +default +legacy -msvc &( +default +legacy ) + // + // + build_class_exprs es; + es.emplace_back (ucs.underlying_classes, '+', ucs.comment); + es.insert (es.end (), exprs.begin (), exprs.end ()); + es.emplace_back (ucs.underlying_classes, '&', ucs.comment); + + // We will use a comment of the first encountered excluding expression + // (changing the result from true to false) or non-including one (leaving + // the false result) as an exclusion reason. + // + for (const build_class_expr& e: es) + { + bool pr (r); + e.match (cfg.classes, r); + + if (reason != nullptr) + { + // Reset the reason which, if saved, makes no sense anymore. + // + if (r) + { + reason->clear (); + } + else if (reason->empty () && + // + // Exclusion. + // + (pr || + // + // Non-inclusion. Make sure that the build class expression + // is empty or starts with an addition (+...). + // + e.expr.empty () || + e.expr.front ().operation == '+')) + { + *reason = sanitize (e.comment); + } + } + } + + if (!r) + return true; + + // Now check if the configuration is excluded/included via the patterns. + // + const string& cn (cfg.name); + string tg (cfg.target.string ()); + + for (const build_constraint& c: constrs) { - if (match (bc.config, bc.target, c)) - return bc.exclusion; + if (path_match (c.config, cn) && + (!c.target || path_match (*c.target, tg))) + { + if (!c.exclusion) + return false; + + if (reason != nullptr) + *reason = sanitize (c.comment); + + return true; + } } return false; |