Skip to content

Instantly share code, notes, and snippets.

@lheckemann
Created November 6, 2017 08:53
Show Gist options
  • Save lheckemann/2f29187c786286c90e32e29c6769bfa3 to your computer and use it in GitHub Desktop.
Save lheckemann/2f29187c786286c90e32e29c6769bfa3 to your computer and use it in GitHub Desktop.
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