diff --git a/lib/modules.nix b/lib/modules.nix index 7ad72235994..076ffdde246 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -6,16 +6,14 @@ rec { /* Evaluate a set of modules. The result is a set of two attributes: ‘options’: the nested set of all option declarations, and ‘config’: the nested set of all option values. */ - evalModules = evalModules' []; - - evalModules' = prefix: modules: args: + evalModules = { modules, prefix ? [], args ? {}, check ? true }: let args' = args // result; closed = closeModules modules args'; # Note: the list of modules is reversed to maintain backward # compatibility with the old module system. Not sure if this is # the most sensible policy. - options = mergeModules prefix (reverseList closed); + options = mergeModules check prefix (reverseList closed); config = yieldConfig options; yieldConfig = mapAttrs (n: v: if isOption v then v.value else yieldConfig v); result = { inherit options config; }; @@ -52,7 +50,7 @@ rec { { inherit file key; imports = m.require or []; options = {}; - config = m; + config = removeAttrs m ["require"]; }; applyIfFunction = f: arg: if builtins.isFunction f then f arg else f; @@ -62,13 +60,19 @@ rec { At the same time, for each option declaration, it will merge the corresponding option definitions in all machines, returning them in the ‘value’ attribute of each option. */ - mergeModules = prefix: modules: - mergeModules' prefix modules + mergeModules = check: prefix: modules: + mergeModules' check prefix modules (concatMap (m: map (config: { inherit (m) file; inherit config; }) (pushDownProperties m.config)) modules); - mergeModules' = prefix: options: configs: - let names = concatMap (m: attrNames m.options) options; - in listToAttrs (map (name: { + mergeModules' = check: prefix: options: configs: + let + declaredNames = concatMap (m: attrNames m.options) options; + declaredNames' = listToAttrs (map (n: { name = n; value = 1; }) declaredNames); + checkDefinedNames = res: fold (m: res: fold (n: res: + if hasAttr n declaredNames' then res else + throw "The option `${showOption (prefix ++ [n])}' defined in `${m.file}' does not exist." + ) res (attrNames m.config)) res configs; + in (if check then checkDefinedNames else id) (listToAttrs (map (name: { # We're descending into attribute ‘name’. inherit name; value = @@ -105,8 +109,8 @@ rec { in throw "The option `${showOption loc}' in `${firstOption.file}' is a prefix of options in `${firstNonOption.file}'." else - mergeModules' loc decls defns; - }) names); + mergeModules' check loc decls defns; + }) declaredNames)); /* Merge multiple option declarations into a single declaration. In general, there should be only one declaration of each option. diff --git a/lib/types.nix b/lib/types.nix index f459cda73cb..07a6cc69fdc 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -182,11 +182,11 @@ rec { let coerce = def: if builtins.isFunction def then def else { config = def; }; modules = opts' ++ map coerce defs; - in (evalModules' args.prefix modules args).config; - getSubOptions = prefix: (evalModules' prefix opts' - # FIXME: hack to get shit to evaluate. - { name = ""; } - ).options; + in (evalModules { inherit modules args; prefix = args.prefix; }).config; + getSubOptions = prefix: (evalModules + { modules = opts'; inherit prefix; + # FIXME: hack to get shit to evaluate. + args = { name = ""; }; }).options; }; # Obsolete alternative to configOf. It takes its option diff --git a/nixos/lib/eval-config.nix b/nixos/lib/eval-config.nix index 119bba78ff1..5d487b91afb 100644 --- a/nixos/lib/eval-config.nix +++ b/nixos/lib/eval-config.nix @@ -7,19 +7,21 @@ , baseModules ? import ../modules/module-list.nix , extraArgs ? {} , modules +, check ? true }: let extraArgs_ = extraArgs; pkgs_ = pkgs; system_ = system; in rec { - # These are the NixOS modules that constitute the system configuration. - configComponents = modules ++ baseModules; - # Merge the option definitions in all modules, forming the full - # system configuration. It's not checked for undeclared options. + # system configuration. systemModule = - pkgs.lib.evalModules configComponents extraArgs; + pkgs.lib.evalModules { + modules = modules ++ baseModules; + args = extraArgs; + inherit check; + }; config = systemModule.config; @@ -54,6 +56,7 @@ rec { # define nixpkgs.config, so it's pointless to evaluate them. baseModules = [ ../modules/misc/nixpkgs.nix ]; pkgs = import ./nixpkgs.nix { system = system_; config = {}; }; + check = false; }).config.nixpkgs; in { diff --git a/nixos/modules/services/misc/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix index 66d46d9114a..f67afb747e9 100644 --- a/nixos/modules/services/misc/nixos-manual.nix +++ b/nixos/modules/services/misc/nixos-manual.nix @@ -16,13 +16,15 @@ let system.nixosRevision = config.system.nixosRevision; }; + eval = evalModules { + modules = [ versionModule ] ++ baseModules; + args = (removeAttrs extraArgs ["config" "options"]) // { modules = [ ]; }; + }; + manual = import ../../../doc/manual { inherit pkgs; revision = config.system.nixosRevision; - options = (evalModules ([ versionModule ] ++ baseModules) - (removeAttrs extraArgs ["config" "options"]) // { - modules = [ ]; - }).options; + options = eval.options; }; entry = "${manual.manual}/share/doc/nixos/manual.html";