summary refs log tree commit diff
diff options
context:
space:
mode:
authorChuck <chuck@intelligence.org>2019-12-12 09:39:09 -0800
committerMaximilian Bosch <maximilian@mbosch.me>2019-12-19 15:00:43 +0100
commit09ac7cb55ff97dcef07d9ddd37ccb08be2a8dad1 (patch)
tree561562a3c68cdc4424df857d4a6b462d9468b0ac
parente0780c5cffa7516ad85b885cae7d0c85aed90267 (diff)
downloadnixpkgs-09ac7cb55ff97dcef07d9ddd37ccb08be2a8dad1.tar
nixpkgs-09ac7cb55ff97dcef07d9ddd37ccb08be2a8dad1.tar.gz
nixpkgs-09ac7cb55ff97dcef07d9ddd37ccb08be2a8dad1.tar.bz2
nixpkgs-09ac7cb55ff97dcef07d9ddd37ccb08be2a8dad1.tar.lz
nixpkgs-09ac7cb55ff97dcef07d9ddd37ccb08be2a8dad1.tar.xz
nixpkgs-09ac7cb55ff97dcef07d9ddd37ccb08be2a8dad1.tar.zst
nixpkgs-09ac7cb55ff97dcef07d9ddd37ccb08be2a8dad1.zip
nixos/nixos-option: Show values inside aggregate options uniformly
1. This makes aggregates of submodules (including the very important
"nixos-option users.users.<username>" case) behave the same way as any
other you-need-to-keep-typing-to-get-to-an-option-leaf (eg:
"nixos-option environment").

Before e0780c5:

  $ nixos-option users.users.root
  error: At 'root' in path 'users.users.root': Attribute not found
  An error occurred while looking for attribute names. Are you sure that 'users.users.root' exists?

After e0780c5 but before this change, this query just printed out a raw
thing, which is behavior that belongs in "nix eval", "nix-instantiate
--eval", or "nix repl <<<":

  $ nixos-option users.users.root
  {
    _module = {
      args = { name = "root"; };
      check = true;
    };
    createHome = false;
    cryptHomeLuks = null;
    description = "System administrator";
    ...

After this change:

  $ nixos-option users.users.root
  This attribute set contains:
  createHome
  cryptHomeLuks
  description
  extraGroups
  group
  hashedPassword
  ...

2. For aggregates of other types (not submodules), print out the option
that contains them rather than printing an error message.

Before:

  $ nixos-option environment.shellAliases.l
  error: At 'l' in path 'environment.shellAliases.l': Attribute not found
  An error occurred while looking for attribute names. Are you sure that 'environment.shellAliases.l' exists?

After:

  $ nixos-option environment.shellAliases.l
  Note: showing environment.shellAliases instead of environment.shellAliases.l
  Value:
  {
    l = "ls -alh";
    ll = "ls -l";
    ls = "ls --color=tty";
  }
  ...
-rw-r--r--nixos/modules/installer/tools/nixos-option/nixos-option.cc68
1 files changed, 32 insertions, 36 deletions
diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc
index 89f9c88be96..5aa3c766d10 100644
--- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc
+++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc
@@ -106,14 +106,13 @@ struct Context
 {
     Context(EvalState & state, Bindings & autoArgs, Value optionsRoot, Value configRoot)
         : state(state), autoArgs(autoArgs), optionsRoot(optionsRoot), configRoot(configRoot),
-          underscoreType(state.symbols.create("_type")), submoduleAttr(state.symbols.create("__nixos-option-submodule-attr"))
+          underscoreType(state.symbols.create("_type"))
     {}
     EvalState & state;
     Bindings & autoArgs;
     Value optionsRoot;
     Value configRoot;
     Symbol underscoreType;
-    Symbol submoduleAttr;
 };
 
 Value evaluateValue(Context & ctx, Value & v)
@@ -127,7 +126,7 @@ Value evaluateValue(Context & ctx, Value & v)
     return called;
 }
 
-bool isType(Context & ctx, const Value & v, const std::string & type)
+bool isOption(Context & ctx, const Value & v)
 {
     if (v.type != tAttrs) {
         return false;
@@ -141,17 +140,12 @@ bool isType(Context & ctx, const Value & v, const std::string & type)
         if (evaluatedType.type != tString) {
             return false;
         }
-        return static_cast<std::string>(evaluatedType.string.s) == type;
+        return static_cast<std::string>(evaluatedType.string.s) == "option";
     } 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
@@ -300,9 +294,11 @@ void printAttrs(Context & ctx, Out & out, Value & v, const std::string & path)
     Out attrsOut(out, "{", "}", v.attrs->size());
     for (const auto & a : v.attrs->lexicographicOrder()) {
         std::string name = a->name;
-        attrsOut << name << " = ";
-        printValue(ctx, attrsOut, *a->value, appendPath(path, name));
-        attrsOut << ";" << Out::sep;
+        if (!forbiddenRecursionName(name)) {
+            attrsOut << name << " = ";
+            printValue(ctx, attrsOut, *a->value, appendPath(path, name));
+            attrsOut << ";" << Out::sep;
+        }
     }
 }
 
@@ -503,10 +499,16 @@ Value getSubOptions(Context & ctx, Value & option)
 
 // Carefully walk an option path, looking for sub-options when a path walks past
 // an option value.
-Value findAlongOptionPath(Context & ctx, const std::string & path)
+struct FindAlongOptionPathRet
+{
+    Value option;
+    std::string path;
+};
+FindAlongOptionPathRet findAlongOptionPath(Context & ctx, const std::string & path)
 {
     Strings tokens = parseAttrPath(path);
     Value v = ctx.optionsRoot;
+    std::string processedPath;
     for (auto i = tokens.begin(); i != tokens.end(); i++) {
         const auto & attr = *i;
         try {
@@ -518,48 +520,42 @@ Value findAlongOptionPath(Context & ctx, const std::string & path)
             if (isOption(ctx, v) && optionTypeIs(ctx, v, "submodule")) {
                 v = getSubOptions(ctx, v);
             }
-            if (isOption(ctx, v) && isAggregateOptionType(ctx, v) && !lastAttribute) {
-                v = getSubOptions(ctx, v);
+            if (isOption(ctx, v) && isAggregateOptionType(ctx, v)) {
+                auto subOptions = getSubOptions(ctx, v);
+                if (lastAttribute && subOptions.attrs->empty()) {
+                    break;
+                }
+                v = subOptions;
                 // Note that we've consumed attr, but didn't actually use it.  This is the path component that's looked
                 // up in the list or attribute set that doesn't name an option -- the "root" in "users.users.root.name".
             } else if (v.type != tAttrs) {
                 throw OptionPathError("Value is %s while a set was expected", showType(v));
             } else {
-                auto symbol = ctx.state.symbols.create(attr);
-                const auto & next = v.attrs->find(symbol);
+                const auto & next = v.attrs->find(ctx.state.symbols.create(attr));
                 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;
             }
+            processedPath = appendPath(processedPath, attr);
         } catch (OptionPathError & e) {
             throw OptionPathError("At '%s' in path '%s': %s", attr, path, e.msg());
         }
     }
-    return v;
+    return {v, processedPath};
 }
 
 void printOne(Context & ctx, Out & out, const std::string & path)
 {
     try {
-        Value option = findAlongOptionPath(ctx, path);
+        auto result = findAlongOptionPath(ctx, path);
+        Value & option = result.option;
         option = evaluateValue(ctx, option);
-        if (isType(ctx, option, ctx.submoduleAttr)) {
-            printAttr(ctx, out, path, ctx.configRoot);
-        } else if (isOption(ctx, option)) {
-            printOption(ctx, out, path, option);
+        if (path != result.path) {
+            out << "Note: showing " << result.path << " instead of " << path << "\n";
+        }
+        if (isOption(ctx, option)) {
+            printOption(ctx, out, result.path, option);
         } else {
             printListing(out, option);
         }