aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2022-05-11 09:07:01 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2022-05-11 09:07:01 +0200
commit53234fea9cd628d5c69c3a4c8a7eba32a05c166c (patch)
treeafb5f21ae42773f499114c65a705e86a4a234f51
parent96f113c40d4934a98aed30a64851feec891a688a (diff)
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`.
-rw-r--r--libbuild2/config/functions.cxx70
1 files changed, 70 insertions, 0 deletions
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<string> (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<lookup, size_t> org (s->lookup_original (*var));
+ pair<lookup, size_t> 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.
//