summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2013-10-28 14:25:58 +0100
committerEelco Dolstra <eelco.dolstra@logicblox.com>2013-10-28 22:45:56 +0100
commit89bd18b3affc6612ad6402c05cc4d80a59efe9b8 (patch)
tree14a313a7bd2d405668f737754756c503bf93a2b2 /lib
parent7cf0e0bda87a1b71aac70d4eaf04aceda3dc3188 (diff)
downloadnixpkgs-89bd18b3affc6612ad6402c05cc4d80a59efe9b8.tar
nixpkgs-89bd18b3affc6612ad6402c05cc4d80a59efe9b8.tar.gz
nixpkgs-89bd18b3affc6612ad6402c05cc4d80a59efe9b8.tar.bz2
nixpkgs-89bd18b3affc6612ad6402c05cc4d80a59efe9b8.tar.lz
nixpkgs-89bd18b3affc6612ad6402c05cc4d80a59efe9b8.tar.xz
nixpkgs-89bd18b3affc6612ad6402c05cc4d80a59efe9b8.tar.zst
nixpkgs-89bd18b3affc6612ad6402c05cc4d80a59efe9b8.zip
Fix manual generation
Diffstat (limited to 'lib')
-rw-r--r--lib/modules.nix35
-rw-r--r--lib/options.nix48
-rw-r--r--lib/types.nix53
3 files changed, 72 insertions, 64 deletions
diff --git a/lib/modules.nix b/lib/modules.nix
index afbfda378f8..f429653d94e 100644
--- a/lib/modules.nix
+++ b/lib/modules.nix
@@ -6,14 +6,16 @@ rec {
   /* Evaluate a set of modules.  The result is a set of two
      attributes: ‘options’: the nested set of all option declarations,
      and ‘config’: the nested set of all option values. */
-  evalModules = modules: args:
+  evalModules = evalModules' [];
+
+  evalModules' = prefix: modules: args:
     let
       args' = args // result;
       closed = closeModules modules args';
       # Note: the list of modules is reversed to maintain backward
       # compatibility with the old module system.  Not sure if this is
       # the most sensible policy.
-      options = mergeModules (reverseList closed);
+      options = mergeModules prefix (reverseList closed);
       config = yieldConfig options;
       yieldConfig = mapAttrs (n: v: if isOption v then v.value else yieldConfig v);
       result = { inherit options config; };
@@ -22,16 +24,15 @@ rec {
   /* Close a set of modules under the ‘imports’ relation. */
   closeModules = modules: args:
     let
-      coerceToModule = n: x:
+      toClosureList = parent: imap (n: x: 
         if isAttrs x || builtins.isFunction x then
-          unifyModuleSyntax "<unknown-file>" "anon-${toString n}" (applyIfFunction x args)
+          unifyModuleSyntax parent "anon-${toString n}" (applyIfFunction x args)
         else
-          unifyModuleSyntax (toString x) (toString x) (applyIfFunction (import x) args);
-      toClosureList = imap (path: coerceToModule path);
+          unifyModuleSyntax (toString x) (toString x) (applyIfFunction (import x) args));
     in
       builtins.genericClosure {
-        startSet = toClosureList modules;
-        operator = m: toClosureList m.imports;
+        startSet = toClosureList unknownModule modules;
+        operator = m: toClosureList m.file m.imports;
       };
 
   /* Massage a module into canonical form, that is, a set consisting
@@ -61,18 +62,18 @@ rec {
      At the same time, for each option declaration, it will merge the
      corresponding option definitions in all machines, returning them
      in the ‘value’ attribute of each option. */
-  mergeModules = modules:
-    mergeModules' [] modules
+  mergeModules = prefix: modules:
+    mergeModules' prefix modules
       (concatMap (m: map (config: { inherit (m) file; inherit config; }) (pushDownProperties m.config)) modules);
 
-  mergeModules' = loc: options: configs:
+  mergeModules' = prefix: options: configs:
     let names = concatMap (m: attrNames m.options) options;
     in listToAttrs (map (name: {
       # We're descending into attribute ‘name’.
       inherit name;
       value =
         let
-          loc' = loc ++ [name];
+          loc = prefix ++ [name];
           # Get all submodules that declare ‘name’.
           decls = concatLists (map (m:
             if hasAttr name m.options
@@ -95,16 +96,16 @@ rec {
             ) configs;
         in
           if nrOptions == length decls then
-            let opt = fixupOptionType loc' (mergeOptionDecls loc' decls);
-            in evalOptionValue loc' opt defns'
+            let opt = fixupOptionType loc (mergeOptionDecls loc decls);
+            in evalOptionValue loc opt defns'
           else if nrOptions != 0 then
             let
               firstOption = findFirst (m: isOption m.options) "" decls;
               firstNonOption = findFirst (m: !isOption m.options) "" decls;
             in
-              throw "The option `${showOption loc'}' in `${firstOption.file}' is a prefix of options in `${firstNonOption.file}'."
+              throw "The option `${showOption loc}' in `${firstOption.file}' is a prefix of options in `${firstNonOption.file}'."
           else
-            mergeModules' loc' decls defns;
+            mergeModules' loc decls defns;
     }) names);
 
   /* Merge multiple option declarations into a single declaration.  In
@@ -128,7 +129,7 @@ rec {
           { declarations = [opt.file] ++ res.declarations;
             options = if opt.options ? options then [(toList opt.options.options ++ res.options)] else [];
           }
-    ) { declarations = []; options = []; } opts;
+    ) { inherit loc; declarations = []; options = []; } opts;
 
   /* Merge all the definitions of an option to produce the final
      config value. */
diff --git a/lib/options.nix b/lib/options.nix
index d94a9fad388..480837fd1cf 100644
--- a/lib/options.nix
+++ b/lib/options.nix
@@ -87,31 +87,28 @@ rec {
 
   # Generate documentation template from the list of option declaration like
   # the set generated with filterOptionSets.
-  optionAttrSetToDocList = attrs:
-    let options = collect isOption attrs; in
-      fold (opt: rest:
-        let
-          docOption = {
-            inherit (opt) name;
-            description = opt.description or (throw "Option ${opt.name}: No description.");
-            declarations = map (x: toString x.source) opt.declarations;
-            #definitions = map (x: toString x.source) opt.definitions;
-            internal = opt.internal or false;
-            visible = opt.visible or true;
-          }
-          // optionalAttrs (opt ? example) { example = scrubOptionValue opt.example; }
-          // optionalAttrs (opt ? default) { default = scrubOptionValue opt.default; }
-          // optionalAttrs (opt ? defaultText) { default = opt.defaultText; };
-
-          subOptions =
-            if opt ? options then
-              optionAttrSetToDocList opt.options
-            else
-              [];
-        in
-          # FIXME: expensive (O(n^2)
-          [ docOption ] ++ subOptions ++ rest
-      ) [] options;
+  optionAttrSetToDocList = optionAttrSetToDocList' [];
+
+  optionAttrSetToDocList' = prefix: options:
+    fold (opt: rest:
+      let
+        docOption = rec {
+          name = showOption opt.loc;
+          description = opt.description or (throw "Option `${name}' has no description.");
+          declarations = filter (x: x != unknownModule) opt.declarations;
+          internal = opt.internal or false;
+          visible = opt.visible or true;
+        }
+        // optionalAttrs (opt ? example) { example = scrubOptionValue opt.example; }
+        // optionalAttrs (opt ? default) { default = scrubOptionValue opt.default; }
+        // optionalAttrs (opt ? defaultText) { default = opt.defaultText; };
+
+        subOptions =
+          let ss = opt.type.getSubOptions opt.loc;
+          in if ss != {} then optionAttrSetToDocList' opt.loc ss else [];
+      in
+        # FIXME: expensive, O(n^2)
+        [ docOption ] ++ subOptions ++ rest) [] (collect isOption options);
 
 
   /* This function recursively removes all derivation attributes from
@@ -135,5 +132,6 @@ rec {
 
   /* Helper functions. */
   showOption = concatStringsSep ".";
+  unknownModule = "<unknown-file>";
 
 }
diff --git a/lib/types.nix b/lib/types.nix
index 7cfd8e606d7..dec9d82d608 100644
--- a/lib/types.nix
+++ b/lib/types.nix
@@ -22,18 +22,18 @@ rec {
   # name (name of the type)
   # check (check the config value)
   # merge (default merge function)
-  # docPath (path concatenated to the option name contained in the option set)
+  # getSubOptions (returns sub-options for manual generation)
   isOptionType = isType "option-type";
   mkOptionType =
     { name
     , check ? (x: true)
     , merge ? mergeDefaultOption
     , merge' ? args: merge
-    , docPath ? lib.id
+    , getSubOptions ? prefix: {}
     }:
 
     { _type = "option-type";
-      inherit name check merge merge' docPath;
+      inherit name check merge merge' getSubOptions;
     };
 
 
@@ -99,14 +99,14 @@ rec {
       name = "list of ${elemType.name}s";
       check = value: isList value && all elemType.check value;
       merge = defs: map (def: elemType.merge [def]) (concatLists defs);
-      docPath = path: elemType.docPath (path + ".*");
+      getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]);
     };
 
     attrsOf = elemType: mkOptionType {
       name = "attribute set of ${elemType.name}s";
       check = x: isAttrs x && all elemType.check (lib.attrValues x);
       merge = lib.zipAttrsWith (name: elemType.merge' { inherit name; });
-      docPath = path: elemType.docPath (path + ".<name>");
+      getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
     };
 
     # List or attribute set of ...
@@ -129,26 +129,27 @@ rec {
           else if isAttrs x then attrOnly.check x
           else false;
         merge = defs: attrOnly.merge (imap convertIfList defs);
-        docPath = path: elemType.docPath (path + ".<name?>");
+        getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]);
       };
 
     uniq = elemType: mkOptionType {
-      inherit (elemType) name check docPath;
+      inherit (elemType) name check;
       merge = list:
         if length list == 1 then
           head list
         else
           throw "Multiple definitions of ${elemType.name}. Only one is allowed for this option.";
+      getSubOptions = elemType.getSubOptions;
     };
 
     none = elemType: mkOptionType {
-      inherit (elemType) name check docPath;
+      inherit (elemType) name check;
       merge = list:
         throw "No definitions are allowed for this option.";
+      getSubOptions = elemType.getSubOptions;
     };
 
     nullOr = elemType: mkOptionType {
-      inherit (elemType) docPath;
       name = "null or ${elemType.name}";
       check = x: builtins.isNull x || elemType.check x;
       merge = defs:
@@ -156,6 +157,7 @@ rec {
         else if any isNull defs then
           throw "Some but not all values are null."
         else elemType.merge defs;
+      getSubOptions = elemType.getSubOptions;
     };
 
     functionTo = elemType: mkOptionType {
@@ -163,19 +165,26 @@ rec {
       check = builtins.isFunction;
       merge = fns:
         args: elemType.merge (map (fn: fn args) fns);
-    };
-
-    submodule = opts: mkOptionType rec {
-      name = "submodule";
-      check = x: isAttrs x || builtins.isFunction x;
-      # FIXME: make error messages include the parent attrpath.
-      merge = merge' {};
-      merge' = args: defs:
-        let
-          coerce = def: if builtins.isFunction def then def else { config = def; };
-          modules = (toList opts) ++ map coerce defs;
-        in (evalModules modules args).config;
-    };
+      getSubOptions = elemType.getSubOptions;
+    };
+
+    submodule = opts:
+      let opts' = toList opts; in
+      mkOptionType rec {
+        name = "submodule";
+        check = x: isAttrs x || builtins.isFunction x;
+        # FIXME: make error messages include the parent attrpath.
+        merge = merge' {};
+        merge' = args: defs:
+          let
+            coerce = def: if builtins.isFunction def then def else { config = def; };
+            modules = opts' ++ map coerce defs;
+          in (evalModules modules args).config;
+        getSubOptions = prefix: (evalModules' prefix opts'
+          # FIXME: hack to get shit to evaluate.
+          { name = ""; }
+        ).options;
+      };
 
     # Obsolete alternative to configOf.  It takes its option
     # declarations from the ‘options’ attribute of containing option