Created
November 6, 2017 08:53
-
-
Save lheckemann/2f29187c786286c90e32e29c6769bfa3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let | |
pkgs = import <nixpkgs> {}; | |
inherit (pkgs) lib; | |
evalModules = with lib; { modules | |
, prefix ? [] | |
, # This should only be used for special arguments that need to be evaluated | |
# when resolving module structure (like in imports). For everything else, | |
# there's _module.args. If specialArgs.modulesPath is defined it will be | |
# used as the base path for disabledModules. | |
specialArgs ? {} | |
, # This would be remove in the future, Prefer _module.args option instead. | |
args ? {} | |
, # This would be remove in the future, Prefer _module.check option instead. | |
check ? true | |
}: | |
let | |
# This internal module declare internal options under the `_module' | |
# attribute. These options are fragile, as they are used by the | |
# module system to change the interpretation of modules. | |
internalModule = rec { | |
_file = ./modules.nix; | |
key = _file; | |
options = { | |
_module.args = mkOption { | |
type = types.attrsOf types.unspecified; | |
internal = true; | |
description = "Arguments passed to each module."; | |
}; | |
_module.check = mkOption { | |
type = types.bool; | |
internal = true; | |
default = check; | |
description = "Whether to check whether all option definitions have matching declarations."; | |
}; | |
}; | |
config = { | |
_module.args = args; | |
}; | |
}; | |
closed = lib.closeModules (modules ++ [ internalModule ]) ({ inherit | |
config options lib; } // specialArgs); | |
options = mergeModules prefix (reverseList (filterModules (specialArgs.modulesPath or "") closed)); | |
# Traverse options and extract the option values into the final | |
# config set. At the same time, check whether all option | |
# definitions have matching declarations. | |
# !!! _module.check's value can't depend on any other config values | |
# without an infinite recursion. One way around this is to make the | |
# 'config' passed around to the modules be unconditionally unchecked, | |
# and only do the check in 'result'. | |
config = yieldConfig prefix options; | |
yieldConfig = prefix: set: | |
let res = removeAttrs (mapAttrs (n: v: | |
if isOption v then v.value | |
else yieldConfig (prefix ++ [n]) v) set) ["_definedNames"]; | |
in | |
if options._module.check.value && set ? _definedNames then | |
foldl' (res: m: | |
foldl' (res: name: | |
if set ? ${name} then res else throw "The option `${showOption (prefix ++ [name])}' defined in `${m.file}' does not exist.") | |
res m.names) | |
res set._definedNames | |
else | |
res; | |
result = { inherit options config; }; | |
in closed; | |
in map (x: x.key) (evalModules { | |
prefix = []; | |
check = true; | |
modules = import <nixpkgs/nixos/modules/module-list.nix>; | |
args = {}; | |
specialArgs = { modulesPath = <nixpkgs/nixos/modules>; }; | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment