summary refs log tree commit diff
path: root/lib/modules.nix
diff options
context:
space:
mode:
authorSymphorien Gibol <symphorien+git@xlumurb.eu>2018-08-14 01:01:08 +0200
committerSymphorien Gibol <symphorien+git@xlumurb.eu>2018-08-27 17:11:58 +0200
commit526d604670a456e59a3d20b657d864f85bb52839 (patch)
treefd287618013d8f0ba3a2caf2a6f898f0eff9bb92 /lib/modules.nix
parent6afd19e699c1505938d54312b522562fd75c8062 (diff)
downloadnixpkgs-526d604670a456e59a3d20b657d864f85bb52839.tar
nixpkgs-526d604670a456e59a3d20b657d864f85bb52839.tar.gz
nixpkgs-526d604670a456e59a3d20b657d864f85bb52839.tar.bz2
nixpkgs-526d604670a456e59a3d20b657d864f85bb52839.tar.lz
nixpkgs-526d604670a456e59a3d20b657d864f85bb52839.tar.xz
nixpkgs-526d604670a456e59a3d20b657d864f85bb52839.tar.zst
nixpkgs-526d604670a456e59a3d20b657d864f85bb52839.zip
module system: rework module merging
The asymptotic complexity is now much lower.
Diffstat (limited to 'lib/modules.nix')
-rw-r--r--lib/modules.nix66
1 files changed, 45 insertions, 21 deletions
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