summary refs log tree commit diff
diff options
context:
space:
mode:
authorSilvan Mosberger <infinisil@icloud.com>2018-08-30 20:08:45 +0200
committerGitHub <noreply@github.com>2018-08-30 20:08:45 +0200
commit911369605163f633433f9769d6c1373b3d855c46 (patch)
treedb7e4a37f30d66ece806f5c3debd5d660c177a6b
parent4caab41c1b4b57d9d971a1c1e5c4da35648615d4 (diff)
parent526d604670a456e59a3d20b657d864f85bb52839 (diff)
downloadnixpkgs-911369605163f633433f9769d6c1373b3d855c46.tar
nixpkgs-911369605163f633433f9769d6c1373b3d855c46.tar.gz
nixpkgs-911369605163f633433f9769d6c1373b3d855c46.tar.bz2
nixpkgs-911369605163f633433f9769d6c1373b3d855c46.tar.lz
nixpkgs-911369605163f633433f9769d6c1373b3d855c46.tar.xz
nixpkgs-911369605163f633433f9769d6c1373b3d855c46.tar.zst
nixpkgs-911369605163f633433f9769d6c1373b3d855c46.zip
Merge pull request #45038 from symphorien/optopt
module system: rework module merging
-rw-r--r--lib/attrsets.nix2
-rw-r--r--lib/modules.nix66
2 files changed, 46 insertions, 22 deletions
diff --git a/lib/attrsets.nix b/lib/attrsets.nix
index cda13ee43ee..1e4142562fa 100644
--- a/lib/attrsets.nix
+++ b/lib/attrsets.nix
@@ -145,7 +145,7 @@ rec {
   foldAttrs = op: nul: list_of_attrs:
     fold (n: a:
         fold (name: o:
-          o // (listToAttrs [{inherit name; value = op n.${name} (a.${name} or nul); }])
+          o // { ${name} = op n.${name} (a.${name} or nul); }
         ) a (attrNames n)
     ) {} list_of_attrs;
 
diff --git a/lib/modules.nix b/lib/modules.nix
index a443d5ec5d1..5fb83a4a538 100644
--- a/lib/modules.nix
+++ b/lib/modules.nix
@@ -192,29 +192,53 @@ rec {
       (concatMap (m: map (config: { inherit (m) file; inherit config; }) (pushDownProperties m.config)) modules);
 
   mergeModules' = prefix: options: configs:
-    listToAttrs (map (name: {
+    let
+     /* byName is like foldAttrs, but will look for attributes to merge in the
+        specified attribute name.
+
+        byName "foo" (module: value: ["module.hidden=${module.hidden},value=${value}"])
+        [
+          {
+            hidden="baz";
+            foo={qux="bar"; gla="flop";};
+          }
+          {
+            hidden="fli";
+            foo={qux="gne"; gli="flip";};
+          }
+        ]
+        ===>
+        {
+          gla = [ "module.hidden=baz,value=flop" ];
+          gli = [ "module.hidden=fli,value=flip" ];
+          qux = [ "module.hidden=baz,value=bar" "module.hidden=fli,value=gne" ];
+        }
+      */
+      byName = attr: f: modules: foldl' (acc: module:
+        foldl' (inner: name:
+          inner // { ${name} = (acc.${name} or []) ++ (f module module.${attr}.${name}); }
+          ) acc (attrNames module.${attr})
+        ) {} modules;
+      # an attrset 'name' => list of submodules that declare ‘name’.
+      declsByName = byName "options"
+        (module: option: [{ inherit (module) file; options = option; }])
+        options;
+      # an attrset 'name' => list of submodules that define ‘name’.
+      defnsByName = byName "config" (module: value:
+        map (config: { inherit (module) file; inherit config; }) (pushDownProperties value)
+        ) configs;
+      # extract the definitions for each loc
+      defnsByName' = byName "config"
+        (module: value: [{ inherit (module) file; inherit value; }])
+        configs;
+    in
+    (flip mapAttrs declsByName (name: decls:
       # We're descending into attribute ‘name’.
-      inherit name;
-      value =
         let
           loc = prefix ++ [name];
-          # Get all submodules that declare ‘name’.
-          decls = concatMap (m:
-            if m.options ? ${name}
-              then [ { inherit (m) file; options = m.options.${name}; } ]
-              else []
-            ) options;
-          # Get all submodules that define ‘name’.
-          defns = concatMap (m:
-            if m.config ? ${name}
-              then map (config: { inherit (m) file; inherit config; })
-                (pushDownProperties m.config.${name})
-              else []
-            ) configs;
+          defns = defnsByName.${name} or [];
+          defns' = defnsByName'.${name} or [];
           nrOptions = count (m: isOption m.options) decls;
-          # Extract the definitions for this loc
-          defns' = map (m: { inherit (m) file; value = m.config.${name}; })
-            (filter (m: m.config ? ${name}) configs);
         in
           if nrOptions == length decls then
             let opt = fixupOptionType loc (mergeOptionDecls loc decls);
@@ -226,8 +250,8 @@ rec {
             in
               throw "The option `${showOption loc}' in `${firstOption.file}' is a prefix of options in `${firstNonOption.file}'."
           else
-            mergeModules' loc decls defns;
-    }) (concatMap (m: attrNames m.options) options))
+            mergeModules' loc decls defns
+      ))
     // { _definedNames = map (m: { inherit (m) file; names = attrNames m.config; }) configs; };
 
   /* Merge multiple option declarations into a single declaration.  In