aboutsummaryrefslogtreecommitdiff
path: root/mod/build-config.cxx
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2022-10-28 23:21:29 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2022-11-23 19:20:35 +0300
commit03c931e54e618221b69cfcd3dfb462e50ecad780 (patch)
treee9fa949151f518f0fdfb05db473fc538f20310ff /mod/build-config.cxx
parent5bf2dd09110f257acc730eab71301e1dede1c710 (diff)
Add support for package build configurations
Diffstat (limited to 'mod/build-config.cxx')
-rw-r--r--mod/build-config.cxx255
1 files changed, 0 insertions, 255 deletions
diff --git a/mod/build-config.cxx b/mod/build-config.cxx
deleted file mode 100644
index 8fbbf99..0000000
--- a/mod/build-config.cxx
+++ /dev/null
@@ -1,255 +0,0 @@
-// file : mod/build-config-module.cxx -*- C++ -*-
-// license : MIT; see accompanying LICENSE file
-
-#include <mod/build-config.hxx>
-
-#include <libbutl/utility.hxx> // alpha(), etc.
-#include <libbutl/path-pattern.hxx>
-
-namespace brep
-{
- using namespace std;
- using namespace butl;
- using namespace bpkg;
- using namespace bbot;
-
- // The default underlying class set expressions (see below).
- //
- static const build_class_expr default_ucs_expr (
- {"default"}, '+', "Default.");
-
- static const build_class_expr all_ucs_expr (
- {"all"}, '+', "All.");
-
- bool
- exclude (const small_vector<build_class_expr, 1>& exprs,
- const vector<build_constraint>& constrs,
- const build_config& cfg,
- const map<string, string>& class_inheritance_map,
- string* reason,
- bool default_all_ucs)
- {
- // Save the first sentence of the reason, lower-case the first letter if
- // the beginning looks like a word (all subsequent characters until a
- // whitespace are lower-case letters).
- //
- auto sanitize = [] (const string& reason)
- {
- string r (reason.substr (0, reason.find ('.')));
-
- char c (r[0]); // Can be '\0'.
- if (alpha (c) && c == ucase (c))
- {
- bool word (true);
-
- for (size_t i (1);
- i != r.size () && (c = r[i]) != ' ' && c != '\t' && c != '\n';
- ++i)
- {
- // Is not a word if contains a non-letter or an upper-case letter.
- //
- if (!alpha (c) || c == ucase (c))
- {
- word = false;
- break;
- }
- }
-
- if (word)
- r[0] = lcase (r[0]);
- }
-
- return r;
- };
-
- // First, match the configuration against the package underlying build
- // class set and expressions.
- //
- bool m (false);
-
- // Match the configuration against an expression, updating the match
- // result.
- //
- // 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.
- //
- auto match = [&cfg, &m, reason, &sanitize, &class_inheritance_map]
- (const build_class_expr& e)
- {
- bool pm (m);
- e.match (cfg.classes, class_inheritance_map, m);
-
- if (reason != nullptr)
- {
- // Reset the reason which, if saved, makes no sense anymore.
- //
- if (m)
- {
- reason->clear ();
- }
- else if (reason->empty () &&
- //
- // Exclusion.
- //
- (pm ||
- //
- // 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);
- }
- }
- };
-
- // Determine the underlying class set. Note that in the future we can
- // potentially extend the underlying set with special classes.
- //
- const build_class_expr* ucs (
- !exprs.empty () && !exprs.front ().underlying_classes.empty ()
- ? &exprs.front ()
- : nullptr);
-
- // Note that the combined package build configuration class expression can
- // be represented as the underlying class set used as a starting set for
- // the original expressions and a restricting set, simultaneously. For
- // example, for the expression:
- //
- // default legacy : -msvc
- //
- // the resulting expression will be:
- //
- // +( +default +legacy ) -msvc &( +default +legacy )
- //
- // Let's, however, optimize it a bit based on the following facts:
- //
- // - If the underlying class set expression (+default +legacy in the above
- // example) evaluates to false, then the resulting expression also
- // evaluates to false due to the trailing '&' operation. Thus, we don't
- // need to evaluate further if that's the case.
- //
- // - On the other hand, if the underlying class set expression evaluates
- // to true, then we don't need to apply the trailing '&' operation as it
- // cannot affect the result.
- //
- const build_class_expr& ucs_expr (
- ucs != nullptr ? build_class_expr (ucs->underlying_classes,
- '+',
- ucs->comment) :
- default_all_ucs ? all_ucs_expr :
- default_ucs_expr);
-
- match (ucs_expr);
-
- if (m)
- {
- for (const build_class_expr& e: exprs)
- match (e);
- }
-
- // Exclude the configuration if it doesn't match the compound expression.
- //
- if (!m)
- return true;
-
- // Now check if the configuration is excluded/included via the patterns.
- //
- // To implement matching of absent name components with wildcard-only
- // pattern components we are going to convert names to paths (see
- // dash_components_to_path() for details).
- //
- // And if any of the build-{include,exclude} values (which is legal) or
- // the build configuration name/target (illegal) are invalid paths, then
- // we assume no match.
- //
- if (!constrs.empty ())
- try
- {
- path cn (dash_components_to_path (cfg.name));
- path tg (dash_components_to_path (cfg.target.string ()));
-
- for (const build_constraint& c: constrs)
- {
- if (path_match (cn,
- dash_components_to_path (c.config),
- dir_path () /* start */,
- path_match_flags::match_absent) &&
- (!c.target ||
- path_match (tg,
- dash_components_to_path (*c.target),
- dir_path () /* start */,
- path_match_flags::match_absent)))
- {
- if (!c.exclusion)
- return false;
-
- if (reason != nullptr)
- *reason = sanitize (c.comment);
-
- return true;
- }
- }
- }
- catch (const invalid_path&) {}
-
- return false;
- }
-
- path
- dash_components_to_path (const string& pattern)
- {
- string r;
- size_t nstar (0);
- for (const path_pattern_term& pt: path_pattern_iterator (pattern))
- {
- switch (pt.type)
- {
- case path_pattern_term_type::star:
- {
- // Replace ** with */**/* and skip all the remaining stars that may
- // follow in this sequence.
- //
- if (nstar == 0)
- r += "*";
- else if (nstar == 1)
- r += "/**/*"; // The first star is already copied.
-
- break;
- }
- case path_pattern_term_type::literal:
- {
- // Replace '-' with '/' and fall through otherwise.
- //
- if (get_literal (pt) == '-')
- {
- r += '/';
- break;
- }
- }
- // Fall through.
- default:
- {
- r.append (pt.begin, pt.end); // Copy the pattern term as is.
- }
- }
-
- nstar = pt.star () ? nstar + 1 : 0;
- }
-
- // Append the trailing slash to match the resulting paths as directories.
- // This is required for the trailing /* we could append to match absent
- // directory path components (see path_match_flags::match_absent for
- // details).
- //
- // Note that valid dash components may not contain a trailing dash.
- // Anyway, any extra trailing slashes will be ignored by the path
- // constructor.
- //
- r += '/';
-
- return path (move (r));
- }
-}