From 53234fea9cd628d5c69c3a4c8a7eba32a05c166c Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 11 May 2022 09:07:01 +0200 Subject: Add $config.origin() function This function can be used to query the origin of a configuration variable value. The result is one of `undefined`, `default`, `buildfile`, or `override`. --- libbuild2/config/functions.cxx | 70 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'libbuild2/config/functions.cxx') diff --git a/libbuild2/config/functions.cxx b/libbuild2/config/functions.cxx index 3d35a01..3e1b8a3 100644 --- a/libbuild2/config/functions.cxx +++ b/libbuild2/config/functions.cxx @@ -21,6 +21,76 @@ namespace build2 { function_family f (m, "config"); + // $config.origin() + // + // Return the origin of the specified configuration variable value. + // Possible result values and their semantics are as follows: + // + // undefined + // The variable is undefined. + // + // default + // The variable has the default value from the config directive (or + // as specified by a module). + // + // buildfile + // The variable has the value from a buildfile, normally config.build + // but could also be from file(s) specified with config.config.load. + // + // override + // The variable has the command line override value. Note that if + // the override happens to be append/prepend, then the value could + // incorporate the original value. + // + // Note that the variable must be specified as a name and not as an + // expansion (i.e., without $). + // + // Note that this function is not pure. + // + f.insert (".origin", false) += [] (const scope* s, names name) + { + if (s == nullptr) + fail << "config.origin() called out of scope" << endf; + + // Only look in the root scope since that's the only config.* + // variables we generally consider. + // + s = s->root_scope (); + + if (s == nullptr) + fail << "config.origin() called out of project" << endf; + + string n (convert (move (name))); + + // Make sure this is a config.* variable. This could matter since we + // reply on the semantics of value::extra. We could also detect + // special variables like config.booted, some config.config.*, etc., + // (see config_save() for details) but that seems harmless. + // + if (n.compare (0, 7, "config.") != 0) + fail << "non-config.* variable passed to config.origin()" << endf; + + const variable* var (s->ctx.var_pool.find (n)); + + if (var == nullptr) + return "undefined"; + + pair org (s->lookup_original (*var)); + pair ovr (var->overrides == nullptr + ? org + : s->lookup_override (*var, org)); + + if (!ovr.first.defined ()) + return "undefined"; + + if (org.first != ovr.first) + return "override"; + + return org.first->extra ? "default" : "buildfile"; + }; + + // $config.save() + // // Return the configuration file contents as a string, similar to the // config.config.save variable functionality. // -- cgit v1.1