summary refs log tree commit diff
diff options
context:
space:
mode:
authorMaximilian Bosch <maximilian@mbosch.me>2019-12-10 14:31:52 +0100
committerMaximilian Bosch <maximilian@mbosch.me>2019-12-12 14:27:36 +0100
commite0780c5cffa7516ad85b885cae7d0c85aed90267 (patch)
tree41e53b534aa0483a9a95dd4aa63edc708ef84509
parente16df73d3040526fdf5f6a34adae79dedb0387ba (diff)
downloadnixpkgs-e0780c5cffa7516ad85b885cae7d0c85aed90267.tar
nixpkgs-e0780c5cffa7516ad85b885cae7d0c85aed90267.tar.gz
nixpkgs-e0780c5cffa7516ad85b885cae7d0c85aed90267.tar.bz2
nixpkgs-e0780c5cffa7516ad85b885cae7d0c85aed90267.tar.lz
nixpkgs-e0780c5cffa7516ad85b885cae7d0c85aed90267.tar.xz
nixpkgs-e0780c5cffa7516ad85b885cae7d0c85aed90267.tar.zst
nixpkgs-e0780c5cffa7516ad85b885cae7d0c85aed90267.zip
nixos/nixos-option: fix evaluator to render a full submodule entry
When running e.g. `nixos-option users.users.ma27`, the evaluation breaks
since `ma27` is the attribute name in `attrsOf (submodule {})`, but not
a part of the option tree and therefore breaks with the following
errors:

```
error: At 'ma27' in path 'users.users.ma27': Attribute not found
An error occurred while looking for attribute names. Are you sure that 'users.users.ma27' exists?
```

This happens since the option evaluator expects that either the option
exists or the option is a submodule and the "next" token in the
attribute path points to an option (e.g. `users.users.ma27.createHome`).

This patch checks in the `Attribute not found` condition if the attribute-path
actually exists in the config tree. If that's true, a dummy-attrset is created
which contains `{_type = "__nixos-option-submodule-attr";}`, in that case, the
entire entry of the submodule will be displayed.
-rw-r--r--nixos/modules/installer/tools/nixos-option/nixos-option.cc39
1 files changed, 30 insertions, 9 deletions
diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc
index 9b92dc829cd..89f9c88be96 100644
--- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc
+++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc
@@ -106,13 +106,14 @@ struct Context
 {
     Context(EvalState & state, Bindings & autoArgs, Value optionsRoot, Value configRoot)
         : state(state), autoArgs(autoArgs), optionsRoot(optionsRoot), configRoot(configRoot),
-          underscoreType(state.symbols.create("_type"))
+          underscoreType(state.symbols.create("_type")), submoduleAttr(state.symbols.create("__nixos-option-submodule-attr"))
     {}
     EvalState & state;
     Bindings & autoArgs;
     Value optionsRoot;
     Value configRoot;
     Symbol underscoreType;
+    Symbol submoduleAttr;
 };
 
 Value evaluateValue(Context & ctx, Value & v)
@@ -126,26 +127,31 @@ Value evaluateValue(Context & ctx, Value & v)
     return called;
 }
 
-bool isOption(Context & ctx, const Value & v)
+bool isType(Context & ctx, const Value & v, const std::string & type)
 {
     if (v.type != tAttrs) {
         return false;
     }
-    const auto & atualType = v.attrs->find(ctx.underscoreType);
-    if (atualType == v.attrs->end()) {
+    const auto & actualType = v.attrs->find(ctx.underscoreType);
+    if (actualType == v.attrs->end()) {
         return false;
     }
     try {
-        Value evaluatedType = evaluateValue(ctx, *atualType->value);
+        Value evaluatedType = evaluateValue(ctx, *actualType->value);
         if (evaluatedType.type != tString) {
             return false;
         }
-        return static_cast<std::string>(evaluatedType.string.s) == "option";
+        return static_cast<std::string>(evaluatedType.string.s) == type;
     } catch (Error &) {
         return false;
     }
 }
 
+bool isOption(Context & ctx, const Value & v)
+{
+    return isType(ctx, v, "option");
+}
+
 // Add quotes to a component of a path.
 // These are needed for paths like:
 //    fileSystems."/".fsType
@@ -519,11 +525,24 @@ Value findAlongOptionPath(Context & ctx, const std::string & path)
             } else if (v.type != tAttrs) {
                 throw OptionPathError("Value is %s while a set was expected", showType(v));
             } else {
-                const auto & next = v.attrs->find(ctx.state.symbols.create(attr));
+                auto symbol = ctx.state.symbols.create(attr);
+                const auto & next = v.attrs->find(symbol);
                 if (next == v.attrs->end()) {
+                    try {
+                        const auto & value = findAlongAttrPath(ctx.state, path, ctx.autoArgs, ctx.configRoot);
+                        Value &dummyOpt = *ctx.state.allocValue();
+                        ctx.state.mkAttrs(dummyOpt, 1);
+                        Value *type = ctx.state.allocAttr(dummyOpt, ctx.state.symbols.create("_type"));
+                        nix::mkString(*type, ctx.submoduleAttr);
+                        v = dummyOpt;
+                        break;
+                    } catch (Error & e) {
+                        // do nothing
+                    }
                     throw OptionPathError("Attribute not found", attr, path);
+                } else {
+                   v = *next->value;
                 }
-                v = *next->value;
             }
         } catch (OptionPathError & e) {
             throw OptionPathError("At '%s' in path '%s': %s", attr, path, e.msg());
@@ -537,7 +556,9 @@ void printOne(Context & ctx, Out & out, const std::string & path)
     try {
         Value option = findAlongOptionPath(ctx, path);
         option = evaluateValue(ctx, option);
-        if (isOption(ctx, option)) {
+        if (isType(ctx, option, ctx.submoduleAttr)) {
+            printAttr(ctx, out, path, ctx.configRoot);
+        } else if (isOption(ctx, option)) {
             printOption(ctx, out, path, option);
         } else {
             printListing(out, option);