diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2022-05-22 14:56:49 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2022-05-22 14:56:49 +0200 |
commit | 0347acdf4c96c2d78d173c84adae99187887be62 (patch) | |
tree | b622acb6e1419deecbec3d17a2243f5cb3f7cb78 | |
parent | 026c827b978761bf0cb618ff9429df8508cd3190 (diff) |
Add support for variable patterns in config.config.disfigure
-rw-r--r-- | libbuild2/config/init.cxx | 121 | ||||
-rw-r--r-- | libbuild2/variable.cxx | 8 | ||||
-rw-r--r-- | libbuild2/variable.hxx | 3 |
3 files changed, 127 insertions, 5 deletions
diff --git a/libbuild2/config/init.cxx b/libbuild2/config/init.cxx index 73c9d37..e921657 100644 --- a/libbuild2/config/init.cxx +++ b/libbuild2/config/init.cxx @@ -261,6 +261,21 @@ namespace build2 // implementation undefined them after loading config.build). See also // config.config.unload. // + // Besides names, variables can also be specified as patterns in the + // config.<prefix>.(*|**)[<suffix>] form where `*` matches single + // component names (i.e., `foo` but not `foo.bar`), and `**` matches + // single and multi-component names. Currently only single wildcard (`*` + // or `**`) is supported. Additionally, a pattern in the + // config.<prefix>(*|**) form (i.e., without `.` after <prefix>) matches + // config.<prefix>.(*|**) plus config.<prefix> itself (but not + // config.<prefix>foo). + // + // For example, to disfigure all the project configuration variables + // (while preserving all the module configuration variables; note + // quoting to prevent pattern expansion): + // + // b config.config.disfigure="'config.hello**'" + // // Note that this variable is not saved in config.build and is expected // to always be specified as a command line override. // @@ -477,16 +492,112 @@ namespace build2 // Undefine variables specified with config.config.disfigure. // - if (const strings* vs = cast_null<strings> (rs[c_d])) + if (const strings* ns = cast_null<strings> (rs[c_d])) { - for (const string& v: *vs) + auto p (rs.vars.lookup_namespace ("config")); + + for (auto i (p.first); i != p.second; ) { - // An unknown variable can't possibly be defined. + const variable& var (i->first); + + // This can be one of the overrides (__override, __prefix, etc), + // which we skip. // - if (const variable* var = vp.find (v)) + if (!var.override ()) { - rs.vars.erase (*var); // Undefine. + bool m (false); + + for (const string& n: *ns) + { + if (n.compare (0, 7, "config.") != 0) + fail << "config.* variable expected in " + << "config.config.disfigure instead of '" << n << "'"; + + size_t p (n.find ('*')); + + if (p == string::npos) + { + if ((m = var.name == n)) + break; + } + else + { + // Pattern in one of these forms: + // + // config.<prefix>.(*|**)[<suffix>] + // config.<prefix>(*|**) + // + // BTW, an alternative way to handle this would be to + // translate it to a path and use our path_match() machinery, + // similar to how we do it for build config include/exclude. + // Perhaps one day when/if we decide to support multiple + // wildcards. + // + if (p == 7) + fail << "config.<prefix>* pattern expected in " + << "config.config.disfigure instead of '" << n << "'"; + + bool r (n[p + 1] == '*'); // Recursive. + + size_t pe; // Prefix end/size. + if (n[p - 1] != '.') + { + // Second form should have no suffix. + // + if (p + (r ? 2 : 1) != n.size ()) + fail << "config.<prefix>(*|**) pattern expected in " + << "config.config.disfigure instead of '" << n << "'"; + + // Match just <prefix>. + // + if ((m = n.compare (0, p, var.name) == 0)) + break; + + pe = p; + } + else + pe = p - 1; + + // Match <prefix> followed by `.`. + // + if (n.compare (0, pe, var.name, 0, pe) != 0 || + var.name[pe] != '.') + continue; + + // Match suffix. + // + size_t sb (p + (r ? 2 : 1)); // Suffix begin. + size_t sn (n.size () - sb); // Suffix size. + + size_t te; // Stem end. + if (sn == 0) // No suffix. + te = var.name.size (); + else + { + if (var.name.size () < pe + 1 + sn) // Too short. + continue; + + te = var.name.size () - sn; + + if (n.compare (sb, sn, var.name, te, sn) != 0) + continue; + } + + // Match stem. + // + if ((m = r || var.name.find ('.', pe + 1) >= te)) + break; + } + } + + if (m) + { + i = rs.vars.erase (i); // Undefine. + continue; + } } + + ++i; } } diff --git a/libbuild2/variable.cxx b/libbuild2/variable.cxx index 8a063f7..0f2a3de 100644 --- a/libbuild2/variable.cxx +++ b/libbuild2/variable.cxx @@ -1797,6 +1797,14 @@ namespace build2 return m_.erase (var) != 0; } + variable_map::const_iterator variable_map:: + erase (const_iterator i) + { + assert (!global_ || ctx->phase == run_phase::load); + + return const_iterator (m_.erase (i), *this); + } + // variable_pattern_map // variable_map& variable_pattern_map:: diff --git a/libbuild2/variable.hxx b/libbuild2/variable.hxx index 2bfab05..15e0074 100644 --- a/libbuild2/variable.hxx +++ b/libbuild2/variable.hxx @@ -1627,6 +1627,9 @@ namespace build2 erase (const variable&); const_iterator + erase (const_iterator); + + const_iterator begin () const {return const_iterator (m_.begin (), *this);} const_iterator |