summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorNicolas Pierron <nicolas.b.pierron@gmail.com>2014-08-29 16:42:44 +0200
committerNicolas Pierron <nicolas.b.pierron@gmail.com>2014-09-07 19:03:20 +0200
commitb5f0cc3cdaa70673a6229f01dc1104a272120b59 (patch)
tree3d8265afd59d41e1252a0547824877fc36a96fa9 /lib
parentbb944b4dc80e7b2a22ac8e76355e7bf80aec6636 (diff)
downloadnixpkgs-b5f0cc3cdaa70673a6229f01dc1104a272120b59.tar
nixpkgs-b5f0cc3cdaa70673a6229f01dc1104a272120b59.tar.gz
nixpkgs-b5f0cc3cdaa70673a6229f01dc1104a272120b59.tar.bz2
nixpkgs-b5f0cc3cdaa70673a6229f01dc1104a272120b59.tar.lz
nixpkgs-b5f0cc3cdaa70673a6229f01dc1104a272120b59.tar.xz
nixpkgs-b5f0cc3cdaa70673a6229f01dc1104a272120b59.tar.zst
nixpkgs-b5f0cc3cdaa70673a6229f01dc1104a272120b59.zip
Merge options having the submodule type.
Now we should be able to have multiple declaration of the same option as
long as all declarations have the same type.  If the type has a sub module,
then it is merged with the submodules of other declarations, as done with
option sets.

In addition, the file of the option declaration is passed into the
submodule, such as the documentation can display it correctly.
Diffstat (limited to 'lib')
-rw-r--r--lib/modules.nix21
-rw-r--r--lib/types.nix21
2 files changed, 35 insertions, 7 deletions
diff --git a/lib/modules.nix b/lib/modules.nix
index 31134c66276..1d428311cd1 100644
--- a/lib/modules.nix
+++ b/lib/modules.nix
@@ -144,7 +144,8 @@ rec {
          opt.options ? example && res ? example ||
          opt.options ? description && res ? description ||
          opt.options ? apply && res ? apply ||
-         opt.options ? type && res ? type
+         # Accept to merge options which have identical types.
+         opt.options ? type && res ? type && opt.options.type.name != res.type.name
       then
         throw "The option `${showOption loc}' in `${opt.file}' is already declared in ${showFiles res.declarations}."
       else
@@ -155,12 +156,16 @@ rec {
              current option declaration as the file use for the submodule.  If the
              submodule defines any filename, then we ignore the enclosing option file. */
           options' = toList opt.options.options;
+          addModuleFile = m:
+            if isFunction m then args: { _file = opt.file; } // (m args)
+            else { _file = opt.file; } // m;
           coerceOption = file: opt:
             if isFunction opt then args: { _file = file; } // (opt args)
-            else args: { _file = file; options = opt; };
+            else { _file = file; options = opt; };
+          getSubModules = opt.options.type.getSubModules or null;
           submodules =
-            if opt.options ? options
-            then map (coerceOption opt.file) options' ++ res.options
+            if getSubModules != null then map addModuleFile getSubModules ++ res.options
+            else if opt.options ? options then map (coerceOption opt.file) options' ++ res.options
             else res.options;
         in opt.options // res //
           { declarations = [opt.file] ++ res.declarations;
@@ -292,7 +297,8 @@ rec {
     in sort compare defs';
 
   /* Hack for backward compatibility: convert options of type
-     optionSet to configOf.  FIXME: remove eventually. */
+     optionSet to options of type submodule.  FIXME: remove
+     eventually. */
   fixupOptionType = loc: opt:
     let
       options = opt.options or
@@ -305,7 +311,10 @@ rec {
         else if tp.name == "list of option sets" then types.listOf (types.submodule options)
         else if tp.name == "null or option set" then types.nullOr (types.submodule options)
         else tp;
-    in opt // { type = f (opt.type or types.unspecified); };
+    in
+      if opt.type.getSubModules or null == null
+      then opt // { type = f (opt.type or types.unspecified); }
+      else opt // { type = opt.type.substSubModules opt.options; options = []; };
 
 
   /* Properties. */
diff --git a/lib/types.nix b/lib/types.nix
index 0e2b6515e16..783e07cdc72 100644
--- a/lib/types.nix
+++ b/lib/types.nix
@@ -33,9 +33,14 @@ rec {
     , # Return a flat list of sub-options.  Used to generate
       # documentation.
       getSubOptions ? prefix: {}
+    , # List of modules if any, or null if none.
+      getSubModules ? null
+    , # Function for building the same option type  with a different list of
+      # modules.
+      substSubModules ? m: null
     }:
     { _type = "option-type";
-      inherit name check merge getSubOptions;
+      inherit name check merge getSubOptions getSubModules substSubModules;
     };
 
 
@@ -110,6 +115,8 @@ rec {
           elemType.merge (loc ++ ["[${toString n}-${toString m}]"])
             [{ inherit (def) file; value = def'; }]) def.value) defs);
       getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]);
+      getSubModules = elemType.getSubModules;
+      substSubModules = m: listOf (elemType.substSubModules m);
     };
 
     attrsOf = elemType: mkOptionType {
@@ -121,6 +128,8 @@ rec {
           (map (def: listToAttrs (mapAttrsToList (n: def':
             { name = n; value = { inherit (def) file; value = def'; }; }) def.value)) defs);
       getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
+      getSubModules = elemType.getSubModules;
+      substSubModules = m: attrsOf (elemType.substSubModules m);
     };
 
     # List or attribute set of ...
@@ -147,12 +156,16 @@ rec {
           else false;
         merge = loc: defs: attrOnly.merge loc (imap convertIfList defs);
         getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]);
+        getSubModules = elemType.getSubModules;
+        substSubModules = m: loaOf (elemType.substSubModules m);
       };
 
     uniq = elemType: mkOptionType {
       inherit (elemType) name check;
       merge = mergeOneOption;
       getSubOptions = elemType.getSubOptions;
+      getSubModules = elemType.getSubModules;
+      substSubModules = m: uniq (elemType.substSubModules m);
     };
 
     nullOr = elemType: mkOptionType {
@@ -165,6 +178,8 @@ rec {
           throw "The option `${showOption loc}' is defined both null and not null, in ${showFiles (getFiles defs)}."
         else elemType.merge loc defs;
       getSubOptions = elemType.getSubOptions;
+      getSubModules = elemType.getSubModules;
+      substSubModules = m: nullOr (elemType.substSubModules m);
     };
 
     functionTo = elemType: mkOptionType {
@@ -173,6 +188,8 @@ rec {
       merge = loc: defs:
         fnArgs: elemType.merge loc (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs);
       getSubOptions = elemType.getSubOptions;
+      getSubModules = elemType.getSubModules;
+      substSubModules = m: functionTo (elemType.substSubModules m);
     };
 
     submodule = opts:
@@ -192,6 +209,8 @@ rec {
           { modules = opts'; inherit prefix;
             # FIXME: hack to get shit to evaluate.
             args = { name = ""; }; }).options;
+        getSubModules = opts';
+        substSubModules = m: submodule m;
       };
 
     enum = values: mkOptionType {