Check for undeclared options

This commit is contained in:
Eelco Dolstra 2013-10-28 15:48:20 +01:00
parent c263b5b284
commit f4a418761b
4 changed files with 35 additions and 26 deletions

View File

@ -6,16 +6,14 @@ rec {
/* Evaluate a set of modules. The result is a set of two /* Evaluate a set of modules. The result is a set of two
attributes: options: the nested set of all option declarations, attributes: options: the nested set of all option declarations,
and config: the nested set of all option values. */ and config: the nested set of all option values. */
evalModules = evalModules' []; evalModules = { modules, prefix ? [], args ? {}, check ? true }:
evalModules' = prefix: modules: args:
let let
args' = args // result; args' = args // result;
closed = closeModules modules args'; closed = closeModules modules args';
# Note: the list of modules is reversed to maintain backward # Note: the list of modules is reversed to maintain backward
# compatibility with the old module system. Not sure if this is # compatibility with the old module system. Not sure if this is
# the most sensible policy. # the most sensible policy.
options = mergeModules prefix (reverseList closed); options = mergeModules check prefix (reverseList closed);
config = yieldConfig options; config = yieldConfig options;
yieldConfig = mapAttrs (n: v: if isOption v then v.value else yieldConfig v); yieldConfig = mapAttrs (n: v: if isOption v then v.value else yieldConfig v);
result = { inherit options config; }; result = { inherit options config; };
@ -52,7 +50,7 @@ rec {
{ inherit file key; { inherit file key;
imports = m.require or []; imports = m.require or [];
options = {}; options = {};
config = m; config = removeAttrs m ["require"];
}; };
applyIfFunction = f: arg: if builtins.isFunction f then f arg else f; 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 At the same time, for each option declaration, it will merge the
corresponding option definitions in all machines, returning them corresponding option definitions in all machines, returning them
in the value attribute of each option. */ in the value attribute of each option. */
mergeModules = prefix: modules: mergeModules = check: prefix: modules:
mergeModules' prefix modules mergeModules' check prefix modules
(concatMap (m: map (config: { inherit (m) file; inherit config; }) (pushDownProperties m.config)) modules); (concatMap (m: map (config: { inherit (m) file; inherit config; }) (pushDownProperties m.config)) modules);
mergeModules' = prefix: options: configs: mergeModules' = check: prefix: options: configs:
let names = concatMap (m: attrNames m.options) options; let
in listToAttrs (map (name: { 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. # We're descending into attribute name.
inherit name; inherit name;
value = value =
@ -105,8 +109,8 @@ rec {
in in
throw "The option `${showOption loc}' in `${firstOption.file}' is a prefix of options in `${firstNonOption.file}'." throw "The option `${showOption loc}' in `${firstOption.file}' is a prefix of options in `${firstNonOption.file}'."
else else
mergeModules' loc decls defns; mergeModules' check loc decls defns;
}) names); }) declaredNames));
/* Merge multiple option declarations into a single declaration. In /* Merge multiple option declarations into a single declaration. In
general, there should be only one declaration of each option. general, there should be only one declaration of each option.

View File

@ -182,11 +182,11 @@ rec {
let let
coerce = def: if builtins.isFunction def then def else { config = def; }; coerce = def: if builtins.isFunction def then def else { config = def; };
modules = opts' ++ map coerce defs; modules = opts' ++ map coerce defs;
in (evalModules' args.prefix modules args).config; in (evalModules { inherit modules args; prefix = args.prefix; }).config;
getSubOptions = prefix: (evalModules' prefix opts' getSubOptions = prefix: (evalModules
# FIXME: hack to get shit to evaluate. { modules = opts'; inherit prefix;
{ name = ""; } # FIXME: hack to get shit to evaluate.
).options; args = { name = ""; }; }).options;
}; };
# Obsolete alternative to configOf. It takes its option # Obsolete alternative to configOf. It takes its option

View File

@ -7,19 +7,21 @@
, baseModules ? import ../modules/module-list.nix , baseModules ? import ../modules/module-list.nix
, extraArgs ? {} , extraArgs ? {}
, modules , modules
, check ? true
}: }:
let extraArgs_ = extraArgs; pkgs_ = pkgs; system_ = system; in let extraArgs_ = extraArgs; pkgs_ = pkgs; system_ = system; in
rec { rec {
# These are the NixOS modules that constitute the system configuration.
configComponents = modules ++ baseModules;
# Merge the option definitions in all modules, forming the full # Merge the option definitions in all modules, forming the full
# system configuration. It's not checked for undeclared options. # system configuration.
systemModule = systemModule =
pkgs.lib.evalModules configComponents extraArgs; pkgs.lib.evalModules {
modules = modules ++ baseModules;
args = extraArgs;
inherit check;
};
config = systemModule.config; config = systemModule.config;
@ -54,6 +56,7 @@ rec {
# define nixpkgs.config, so it's pointless to evaluate them. # define nixpkgs.config, so it's pointless to evaluate them.
baseModules = [ ../modules/misc/nixpkgs.nix ]; baseModules = [ ../modules/misc/nixpkgs.nix ];
pkgs = import ./nixpkgs.nix { system = system_; config = {}; }; pkgs = import ./nixpkgs.nix { system = system_; config = {}; };
check = false;
}).config.nixpkgs; }).config.nixpkgs;
in in
{ {

View File

@ -16,13 +16,15 @@ let
system.nixosRevision = config.system.nixosRevision; system.nixosRevision = config.system.nixosRevision;
}; };
eval = evalModules {
modules = [ versionModule ] ++ baseModules;
args = (removeAttrs extraArgs ["config" "options"]) // { modules = [ ]; };
};
manual = import ../../../doc/manual { manual = import ../../../doc/manual {
inherit pkgs; inherit pkgs;
revision = config.system.nixosRevision; revision = config.system.nixosRevision;
options = (evalModules ([ versionModule ] ++ baseModules) options = eval.options;
(removeAttrs extraArgs ["config" "options"]) // {
modules = [ ];
}).options;
}; };
entry = "${manual.manual}/share/doc/nixos/manual.html"; entry = "${manual.manual}/share/doc/nixos/manual.html";