Merge pull request #6794 from nbp/module-system-tweaks
Module system improvements
This commit is contained in:
commit
889f72bad4
170
lib/modules.nix
170
lib/modules.nix
@ -9,25 +9,69 @@ 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 = { modules, prefix ? [], args ? {}, check ? true }:
|
!!! Please think twice before adding to this argument list! The more
|
||||||
|
that is specified here instead of in the modules themselves the harder
|
||||||
|
it is to transparently move a set of modules to be a submodule of another
|
||||||
|
config (as the proper arguments need to be replicated at each call to
|
||||||
|
evalModules) and the less declarative the module set is. */
|
||||||
|
evalModules = { modules
|
||||||
|
, prefix ? []
|
||||||
|
, # 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
|
let
|
||||||
args' = args // { lib = import ./.; } // result;
|
# This internal module declare internal options under the `_module'
|
||||||
closed = closeModules modules args';
|
# 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.uniq types.bool;
|
||||||
|
internal = true;
|
||||||
|
default = check;
|
||||||
|
description = "Whether to check whether all option definitions have matching declarations.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
_module.args = args;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
closed = closeModules (modules ++ [ internalModule ]) { inherit config options; lib = import ./.; };
|
||||||
|
|
||||||
# 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 prefix (reverseList closed);
|
||||||
|
|
||||||
# Traverse options and extract the option values into the final
|
# Traverse options and extract the option values into the final
|
||||||
# config set. At the same time, check whether all option
|
# config set. At the same time, check whether all option
|
||||||
# definitions have matching declarations.
|
# 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;
|
config = yieldConfig prefix options;
|
||||||
yieldConfig = prefix: set:
|
yieldConfig = prefix: set:
|
||||||
let res = removeAttrs (mapAttrs (n: v:
|
let res = removeAttrs (mapAttrs (n: v:
|
||||||
if isOption v then v.value
|
if isOption v then v.value
|
||||||
else yieldConfig (prefix ++ [n]) v) set) ["_definedNames"];
|
else yieldConfig (prefix ++ [n]) v) set) ["_definedNames"];
|
||||||
in
|
in
|
||||||
if check && set ? _definedNames then
|
if options._module.check.value && set ? _definedNames then
|
||||||
fold (m: res:
|
fold (m: res:
|
||||||
fold (name: res:
|
fold (name: res:
|
||||||
if set ? ${name} then res else throw "The option `${showOption (prefix ++ [name])}' defined in `${m.file}' does not exist.")
|
if set ? ${name} then res else throw "The option `${showOption (prefix ++ [name])}' defined in `${m.file}' does not exist.")
|
||||||
@ -43,7 +87,7 @@ rec {
|
|||||||
let
|
let
|
||||||
toClosureList = file: parentKey: imap (n: x:
|
toClosureList = file: parentKey: imap (n: x:
|
||||||
if isAttrs x || isFunction x then
|
if isAttrs x || isFunction x then
|
||||||
unifyModuleSyntax file "${parentKey}:anon-${toString n}" (applyIfFunction x args)
|
unifyModuleSyntax file "${parentKey}:anon-${toString n}" (unpackSubmodule applyIfFunction x args)
|
||||||
else
|
else
|
||||||
unifyModuleSyntax (toString x) (toString x) (applyIfFunction (import x) args));
|
unifyModuleSyntax (toString x) (toString x) (applyIfFunction (import x) args));
|
||||||
in
|
in
|
||||||
@ -74,7 +118,39 @@ rec {
|
|||||||
config = removeAttrs m ["key" "_file" "require" "imports"];
|
config = removeAttrs m ["key" "_file" "require" "imports"];
|
||||||
};
|
};
|
||||||
|
|
||||||
applyIfFunction = f: arg: if isFunction f then f arg else f;
|
applyIfFunction = f: arg@{ config, options, lib }: if isFunction f then
|
||||||
|
let
|
||||||
|
# Module arguments are resolved in a strict manner when attribute set
|
||||||
|
# deconstruction is used. As the arguments are now defined with the
|
||||||
|
# config._module.args option, the strictness used on the attribute
|
||||||
|
# set argument would cause an infinite loop, if the result of the
|
||||||
|
# option is given as argument.
|
||||||
|
#
|
||||||
|
# To work-around the strictness issue on the deconstruction of the
|
||||||
|
# attributes set argument, we create a new attribute set which is
|
||||||
|
# constructed to satisfy the expected set of attributes. Thus calling
|
||||||
|
# a module will resolve strictly the attributes used as argument but
|
||||||
|
# not their values. The values are forwarding the result of the
|
||||||
|
# evaluation of the option.
|
||||||
|
requiredArgs = builtins.attrNames (builtins.functionArgs f);
|
||||||
|
extraArgs = builtins.listToAttrs (map (name: {
|
||||||
|
inherit name;
|
||||||
|
value = config._module.args.${name};
|
||||||
|
}) requiredArgs);
|
||||||
|
in f (extraArgs // arg)
|
||||||
|
else
|
||||||
|
f;
|
||||||
|
|
||||||
|
/* We have to pack and unpack submodules. We cannot wrap the expected
|
||||||
|
result of the function as we would no longer be able to list the arguments
|
||||||
|
of the submodule. (see applyIfFunction) */
|
||||||
|
unpackSubmodule = unpack: m: args:
|
||||||
|
if isType "submodule" m then
|
||||||
|
{ _file = m.file; } // (unpack m.submodule args)
|
||||||
|
else unpack m args;
|
||||||
|
|
||||||
|
packSubmodule = file: m:
|
||||||
|
{ _type = "submodule"; file = file; submodule = m; };
|
||||||
|
|
||||||
/* Merge a list of modules. This will recurse over the option
|
/* Merge a list of modules. This will recurse over the option
|
||||||
declarations in all modules, combining them into a single set.
|
declarations in all modules, combining them into a single set.
|
||||||
@ -106,12 +182,9 @@ rec {
|
|||||||
else []
|
else []
|
||||||
) configs);
|
) configs);
|
||||||
nrOptions = count (m: isOption m.options) decls;
|
nrOptions = count (m: isOption m.options) decls;
|
||||||
# Process mkMerge and mkIf properties.
|
# Extract the definitions for this loc
|
||||||
defns' = concatMap (m:
|
defns' = map (m: { inherit (m) file; value = m.config.${name}; })
|
||||||
if m.config ? ${name}
|
(filter (m: m.config ? ${name}) configs);
|
||||||
then map (m': { inherit (m) file; value = m'; }) (dischargeProperties m.config.${name})
|
|
||||||
else []
|
|
||||||
) configs;
|
|
||||||
in
|
in
|
||||||
if nrOptions == length decls then
|
if nrOptions == length decls then
|
||||||
let opt = fixupOptionType loc (mergeOptionDecls loc decls);
|
let opt = fixupOptionType loc (mergeOptionDecls loc decls);
|
||||||
@ -156,15 +229,12 @@ rec {
|
|||||||
current option declaration as the file use for the submodule. If the
|
current option declaration as the file use for the submodule. If the
|
||||||
submodule defines any filename, then we ignore the enclosing option file. */
|
submodule defines any filename, then we ignore the enclosing option file. */
|
||||||
options' = toList opt.options.options;
|
options' = toList opt.options.options;
|
||||||
addModuleFile = m:
|
|
||||||
if isFunction m then args: { _file = opt.file; } // (m args)
|
|
||||||
else { _file = opt.file; } // m;
|
|
||||||
coerceOption = file: opt:
|
coerceOption = file: opt:
|
||||||
if isFunction opt then args: { _file = file; } // (opt args)
|
if isFunction opt then packSubmodule file opt
|
||||||
else { _file = file; options = opt; };
|
else packSubmodule file { options = opt; };
|
||||||
getSubModules = opt.options.type.getSubModules or null;
|
getSubModules = opt.options.type.getSubModules or null;
|
||||||
submodules =
|
submodules =
|
||||||
if getSubModules != null then map addModuleFile getSubModules ++ res.options
|
if getSubModules != null then map (packSubmodule opt.file) getSubModules ++ res.options
|
||||||
else if opt.options ? options then map (coerceOption opt.file) options' ++ res.options
|
else if opt.options ? options then map (coerceOption opt.file) options' ++ res.options
|
||||||
else res.options;
|
else res.options;
|
||||||
in opt.options // res //
|
in opt.options // res //
|
||||||
@ -177,27 +247,17 @@ rec {
|
|||||||
config value. */
|
config value. */
|
||||||
evalOptionValue = loc: opt: defs:
|
evalOptionValue = loc: opt: defs:
|
||||||
let
|
let
|
||||||
# Process mkOverride properties, adding in the default
|
# Add in the default value for this option, if any.
|
||||||
# value specified in the option declaration (if any).
|
defs' = (optional (opt ? default)
|
||||||
defsFinal' = filterOverrides
|
{ file = head opt.declarations; value = mkOptionDefault opt.default; }) ++ defs;
|
||||||
((if opt ? default then [{ file = head opt.declarations; value = mkOptionDefault opt.default; }] else []) ++ defs);
|
|
||||||
# Sort mkOrder properties.
|
# Handle properties, check types, and merge everything together
|
||||||
defsFinal =
|
inherit (mergeDefinitions loc opt.type defs') isDefined defsFinal mergedValue;
|
||||||
# Avoid sorting if we don't have to.
|
|
||||||
if any (def: def.value._type or "" == "order") defsFinal'
|
|
||||||
then sortProperties defsFinal'
|
|
||||||
else defsFinal';
|
|
||||||
files = map (def: def.file) defsFinal;
|
files = map (def: def.file) defsFinal;
|
||||||
# Type-check the remaining definitions, and merge them if
|
|
||||||
# possible.
|
|
||||||
merged =
|
merged =
|
||||||
if defsFinal == [] then
|
if isDefined then mergedValue
|
||||||
throw "The option `${showOption loc}' is used but not defined."
|
else throw "The option `${showOption loc}' is used but not defined.";
|
||||||
else
|
|
||||||
fold (def: res:
|
|
||||||
if opt.type.check def.value then res
|
|
||||||
else throw "The option value `${showOption loc}' in `${def.file}' is not a ${opt.type.name}.")
|
|
||||||
(opt.type.merge loc defsFinal) defsFinal;
|
|
||||||
# Finally, apply the ‘apply’ function to the merged
|
# Finally, apply the ‘apply’ function to the merged
|
||||||
# value. This allows options to yield a value computed
|
# value. This allows options to yield a value computed
|
||||||
# from the definitions.
|
# from the definitions.
|
||||||
@ -205,8 +265,40 @@ rec {
|
|||||||
in opt //
|
in opt //
|
||||||
{ value = addErrorContext "while evaluating the option `${showOption loc}':" value;
|
{ value = addErrorContext "while evaluating the option `${showOption loc}':" value;
|
||||||
definitions = map (def: def.value) defsFinal;
|
definitions = map (def: def.value) defsFinal;
|
||||||
|
inherit isDefined files;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Merge definitions of a value of a given type
|
||||||
|
mergeDefinitions = loc: type: defs: rec {
|
||||||
|
defsFinal =
|
||||||
|
let
|
||||||
|
# Process mkMerge and mkIf properties
|
||||||
|
processIfAndMerge = defs: concatMap (m:
|
||||||
|
map (value: { inherit (m) file; inherit value; }) (dischargeProperties m.value)
|
||||||
|
) defs;
|
||||||
|
|
||||||
|
# Process mkOverride properties
|
||||||
|
processOverride = defs: filterOverrides defs;
|
||||||
|
|
||||||
|
# Sort mkOrder properties
|
||||||
|
processOrder = defs:
|
||||||
|
# Avoid sorting if we don't have to.
|
||||||
|
if any (def: def.value._type or "" == "order") defs
|
||||||
|
then sortProperties defs
|
||||||
|
else defs;
|
||||||
|
in
|
||||||
|
processOrder (processOverride (processIfAndMerge defs));
|
||||||
|
|
||||||
|
# Type-check the remaining definitions, and merge them
|
||||||
|
mergedValue = fold (def: res:
|
||||||
|
if type.check def.value then res
|
||||||
|
else throw "The option value `${showOption loc}' in `${def.file}' is not a ${type.name}.")
|
||||||
|
(type.merge loc defsFinal) defsFinal;
|
||||||
|
|
||||||
isDefined = defsFinal != [];
|
isDefined = defsFinal != [];
|
||||||
inherit files;
|
optionalValue =
|
||||||
|
if isDefined then { value = mergedValue; }
|
||||||
|
else {};
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Given a config set, expand mkMerge properties, and push down the
|
/* Given a config set, expand mkMerge properties, and push down the
|
||||||
|
@ -57,13 +57,17 @@ checkConfigError() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Check boolean option.
|
||||||
checkConfigOutput "false" config.enable ./declare-enable.nix
|
checkConfigOutput "false" config.enable ./declare-enable.nix
|
||||||
checkConfigError 'The option .* defined in .* does not exist.' config.enable ./define-enable.nix
|
checkConfigError 'The option .* defined in .* does not exist.' config.enable ./define-enable.nix
|
||||||
|
|
||||||
|
# Check mkForce without submodules.
|
||||||
set -- config.enable ./declare-enable.nix ./define-enable.nix
|
set -- config.enable ./declare-enable.nix ./define-enable.nix
|
||||||
checkConfigOutput "true" "$@"
|
checkConfigOutput "true" "$@"
|
||||||
checkConfigOutput "false" "$@" ./define-force-enable.nix
|
checkConfigOutput "false" "$@" ./define-force-enable.nix
|
||||||
checkConfigOutput "false" "$@" ./define-enable-force.nix
|
checkConfigOutput "false" "$@" ./define-enable-force.nix
|
||||||
|
|
||||||
|
# Check mkForce with option and submodules.
|
||||||
checkConfigError 'attribute .*foo.* .* not found' config.loaOfSub.foo.enable ./declare-loaOfSub-any-enable.nix
|
checkConfigError 'attribute .*foo.* .* not found' config.loaOfSub.foo.enable ./declare-loaOfSub-any-enable.nix
|
||||||
checkConfigOutput 'false' config.loaOfSub.foo.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix
|
checkConfigOutput 'false' config.loaOfSub.foo.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix
|
||||||
set -- config.loaOfSub.foo.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo-enable.nix
|
set -- config.loaOfSub.foo.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo-enable.nix
|
||||||
@ -73,6 +77,7 @@ checkConfigOutput 'false' "$@" ./define-loaOfSub-force-foo-enable.nix
|
|||||||
checkConfigOutput 'false' "$@" ./define-loaOfSub-foo-force-enable.nix
|
checkConfigOutput 'false' "$@" ./define-loaOfSub-foo-force-enable.nix
|
||||||
checkConfigOutput 'false' "$@" ./define-loaOfSub-foo-enable-force.nix
|
checkConfigOutput 'false' "$@" ./define-loaOfSub-foo-enable-force.nix
|
||||||
|
|
||||||
|
# Check overriding effect of mkForce on submodule definitions.
|
||||||
checkConfigError 'attribute .*bar.* .* not found' config.loaOfSub.bar.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix
|
checkConfigError 'attribute .*bar.* .* not found' config.loaOfSub.bar.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix
|
||||||
checkConfigOutput 'false' config.loaOfSub.bar.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix ./define-loaOfSub-bar.nix
|
checkConfigOutput 'false' config.loaOfSub.bar.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix ./define-loaOfSub-bar.nix
|
||||||
set -- config.loaOfSub.bar.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix ./define-loaOfSub-bar-enable.nix
|
set -- config.loaOfSub.bar.enable ./declare-loaOfSub-any-enable.nix ./define-loaOfSub-foo.nix ./define-loaOfSub-bar-enable.nix
|
||||||
@ -82,6 +87,26 @@ checkConfigError 'attribute .*bar.* .* not found' "$@" ./define-loaOfSub-force-f
|
|||||||
checkConfigOutput 'true' "$@" ./define-loaOfSub-foo-force-enable.nix
|
checkConfigOutput 'true' "$@" ./define-loaOfSub-foo-force-enable.nix
|
||||||
checkConfigOutput 'true' "$@" ./define-loaOfSub-foo-enable-force.nix
|
checkConfigOutput 'true' "$@" ./define-loaOfSub-foo-enable-force.nix
|
||||||
|
|
||||||
|
# Check mkIf with submodules.
|
||||||
|
checkConfigError 'attribute .*foo.* .* not found' config.loaOfSub.foo.enable ./declare-enable.nix ./declare-loaOfSub-any-enable.nix
|
||||||
|
set -- config.loaOfSub.foo.enable ./declare-enable.nix ./declare-loaOfSub-any-enable.nix
|
||||||
|
checkConfigError 'attribute .*foo.* .* not found' "$@" ./define-if-loaOfSub-foo-enable.nix
|
||||||
|
checkConfigError 'attribute .*foo.* .* not found' "$@" ./define-loaOfSub-if-foo-enable.nix
|
||||||
|
checkConfigError 'attribute .*foo.* .* not found' "$@" ./define-loaOfSub-foo-if-enable.nix
|
||||||
|
checkConfigOutput 'false' "$@" ./define-loaOfSub-foo-enable-if.nix
|
||||||
|
checkConfigOutput 'true' "$@" ./define-enable.nix ./define-if-loaOfSub-foo-enable.nix
|
||||||
|
checkConfigOutput 'true' "$@" ./define-enable.nix ./define-loaOfSub-if-foo-enable.nix
|
||||||
|
checkConfigOutput 'true' "$@" ./define-enable.nix ./define-loaOfSub-foo-if-enable.nix
|
||||||
|
checkConfigOutput 'true' "$@" ./define-enable.nix ./define-loaOfSub-foo-enable-if.nix
|
||||||
|
|
||||||
|
# Check _module.args.
|
||||||
|
checkConfigOutput "true" config.enable ./declare-enable.nix ./custom-arg-define-enable.nix
|
||||||
|
|
||||||
|
# Check _module.check.
|
||||||
|
set -- config.enable ./declare-enable.nix ./define-enable.nix ./define-loaOfSub-foo.nix
|
||||||
|
checkConfigError 'The option .* defined in .* does not exist.' "$@"
|
||||||
|
checkConfigOutput "true" "$@" ./define-module-check.nix
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
====== module tests ======
|
====== module tests ======
|
||||||
$pass Pass
|
$pass Pass
|
||||||
|
8
lib/tests/modules/custom-arg-define-enable.nix
Normal file
8
lib/tests/modules/custom-arg-define-enable.nix
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{ lib, custom, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
config = {
|
||||||
|
_module.args.custom = true;
|
||||||
|
enable = custom;
|
||||||
|
};
|
||||||
|
}
|
5
lib/tests/modules/define-if-loaOfSub-foo-enable.nix
Normal file
5
lib/tests/modules/define-if-loaOfSub-foo-enable.nix
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
lib.mkIf config.enable {
|
||||||
|
loaOfSub.foo.enable = true;
|
||||||
|
}
|
5
lib/tests/modules/define-loaOfSub-foo-enable-if.nix
Normal file
5
lib/tests/modules/define-loaOfSub-foo-enable-if.nix
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
loaOfSub.foo.enable = lib.mkIf config.enable true;
|
||||||
|
}
|
7
lib/tests/modules/define-loaOfSub-foo-if-enable.nix
Normal file
7
lib/tests/modules/define-loaOfSub-foo-if-enable.nix
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
loaOfSub.foo = lib.mkIf config.enable {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
}
|
7
lib/tests/modules/define-loaOfSub-if-foo-enable.nix
Normal file
7
lib/tests/modules/define-loaOfSub-if-foo-enable.nix
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
loaOfSub = lib.mkIf config.enable {
|
||||||
|
foo.enable = true;
|
||||||
|
};
|
||||||
|
}
|
3
lib/tests/modules/define-module-check.nix
Normal file
3
lib/tests/modules/define-module-check.nix
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
_module.check = false;
|
||||||
|
}
|
@ -6,6 +6,7 @@ with import ./attrsets.nix;
|
|||||||
with import ./options.nix;
|
with import ./options.nix;
|
||||||
with import ./trivial.nix;
|
with import ./trivial.nix;
|
||||||
with import ./strings.nix;
|
with import ./strings.nix;
|
||||||
|
with {inherit (import ./modules.nix) mergeDefinitions; };
|
||||||
|
|
||||||
rec {
|
rec {
|
||||||
|
|
||||||
@ -109,11 +110,15 @@ rec {
|
|||||||
|
|
||||||
listOf = elemType: mkOptionType {
|
listOf = elemType: mkOptionType {
|
||||||
name = "list of ${elemType.name}s";
|
name = "list of ${elemType.name}s";
|
||||||
check = value: isList value && all elemType.check value;
|
check = isList;
|
||||||
merge = loc: defs:
|
merge = loc: defs:
|
||||||
concatLists (imap (n: def: imap (m: def':
|
map (x: x.value) (filter (x: x ? value) (concatLists (imap (n: def: imap (m: def':
|
||||||
elemType.merge (loc ++ ["[${toString n}-${toString m}]"])
|
(mergeDefinitions
|
||||||
[{ inherit (def) file; value = def'; }]) def.value) defs);
|
(loc ++ ["[definition ${toString n}-entry ${toString m}]"])
|
||||||
|
elemType
|
||||||
|
[{ inherit (def) file; value = def'; }]
|
||||||
|
).optionalValue
|
||||||
|
) def.value) defs)));
|
||||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]);
|
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]);
|
||||||
getSubModules = elemType.getSubModules;
|
getSubModules = elemType.getSubModules;
|
||||||
substSubModules = m: listOf (elemType.substSubModules m);
|
substSubModules = m: listOf (elemType.substSubModules m);
|
||||||
@ -121,12 +126,14 @@ rec {
|
|||||||
|
|
||||||
attrsOf = elemType: mkOptionType {
|
attrsOf = elemType: mkOptionType {
|
||||||
name = "attribute set of ${elemType.name}s";
|
name = "attribute set of ${elemType.name}s";
|
||||||
check = x: isAttrs x && all elemType.check (attrValues x);
|
check = isAttrs;
|
||||||
merge = loc: defs:
|
merge = loc: defs:
|
||||||
zipAttrsWith (name: elemType.merge (loc ++ [name]))
|
mapAttrs (n: v: v.value) (filterAttrs (n: v: v ? value) (zipAttrsWith (name: defs:
|
||||||
|
(mergeDefinitions (loc ++ [name]) elemType defs).optionalValue
|
||||||
|
)
|
||||||
# Push down position info.
|
# Push down position info.
|
||||||
(map (def: listToAttrs (mapAttrsToList (n: def':
|
(map (def: listToAttrs (mapAttrsToList (n: def':
|
||||||
{ name = n; value = { inherit (def) file; value = def'; }; }) def.value)) defs);
|
{ name = n; value = { inherit (def) file; value = def'; }; }) def.value)) defs)));
|
||||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
|
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
|
||||||
getSubModules = elemType.getSubModules;
|
getSubModules = elemType.getSubModules;
|
||||||
substSubModules = m: attrsOf (elemType.substSubModules m);
|
substSubModules = m: attrsOf (elemType.substSubModules m);
|
||||||
@ -150,10 +157,7 @@ rec {
|
|||||||
attrOnly = attrsOf elemType;
|
attrOnly = attrsOf elemType;
|
||||||
in mkOptionType {
|
in mkOptionType {
|
||||||
name = "list or attribute set of ${elemType.name}s";
|
name = "list or attribute set of ${elemType.name}s";
|
||||||
check = x:
|
check = x: isList x || isAttrs x;
|
||||||
if isList x then listOnly.check x
|
|
||||||
else if isAttrs x then attrOnly.check x
|
|
||||||
else false;
|
|
||||||
merge = loc: defs: attrOnly.merge loc (imap convertIfList defs);
|
merge = loc: defs: attrOnly.merge loc (imap convertIfList defs);
|
||||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]);
|
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]);
|
||||||
getSubModules = elemType.getSubModules;
|
getSubModules = elemType.getSubModules;
|
||||||
@ -194,7 +198,11 @@ rec {
|
|||||||
let
|
let
|
||||||
coerce = def: if isFunction def then def else { config = def; };
|
coerce = def: if isFunction def then def else { config = def; };
|
||||||
modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs;
|
modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs;
|
||||||
in (evalModules { inherit modules; args.name = last loc; prefix = loc; }).config;
|
in (evalModules {
|
||||||
|
inherit modules;
|
||||||
|
args.name = last loc;
|
||||||
|
prefix = loc;
|
||||||
|
}).config;
|
||||||
getSubOptions = prefix: (evalModules
|
getSubOptions = prefix: (evalModules
|
||||||
{ modules = opts'; inherit prefix;
|
{ modules = opts'; inherit prefix;
|
||||||
# FIXME: hack to get shit to evaluate.
|
# FIXME: hack to get shit to evaluate.
|
||||||
|
@ -2,27 +2,51 @@
|
|||||||
# configuration object (`config') from which we can retrieve option
|
# configuration object (`config') from which we can retrieve option
|
||||||
# values.
|
# values.
|
||||||
|
|
||||||
{ system ? builtins.currentSystem
|
# !!! Please think twice before adding to this argument list!
|
||||||
, pkgs ? null
|
# Ideally eval-config.nix would be an extremely thin wrapper
|
||||||
, baseModules ? import ../modules/module-list.nix
|
# around lib.evalModules, so that modular systems that have nixos configs
|
||||||
, extraArgs ? {}
|
# as subcomponents (e.g. the container feature, or nixops if network
|
||||||
|
# expressions are ever made modular at the top level) can just use
|
||||||
|
# types.submodule instead of using eval-config.nix
|
||||||
|
{ # !!! system can be set modularly, would be nice to remove
|
||||||
|
system ? builtins.currentSystem
|
||||||
|
, # !!! is this argument needed any more? The pkgs argument can
|
||||||
|
# be set modularly anyway.
|
||||||
|
pkgs ? null
|
||||||
|
, # !!! what do we gain by making this configurable?
|
||||||
|
baseModules ? import ../modules/module-list.nix
|
||||||
|
, # !!! See comment about args in lib/modules.nix
|
||||||
|
extraArgs ? {}
|
||||||
, modules
|
, modules
|
||||||
, check ? true
|
, # !!! See comment about check in lib/modules.nix
|
||||||
|
check ? true
|
||||||
, prefix ? []
|
, prefix ? []
|
||||||
|
, lib ? import ../../lib
|
||||||
}:
|
}:
|
||||||
|
|
||||||
let extraArgs_ = extraArgs; pkgs_ = pkgs; system_ = system;
|
let extraArgs_ = extraArgs; pkgs_ = pkgs; system_ = system;
|
||||||
extraModules = let e = builtins.getEnv "NIXOS_EXTRA_MODULE_PATH";
|
extraModules = let e = builtins.getEnv "NIXOS_EXTRA_MODULE_PATH";
|
||||||
in if e == "" then [] else [(import (builtins.toPath e))];
|
in if e == "" then [] else [(import (builtins.toPath e))];
|
||||||
|
in
|
||||||
|
|
||||||
|
let
|
||||||
|
pkgsModule = rec {
|
||||||
|
_file = ./eval-config.nix;
|
||||||
|
key = _file;
|
||||||
|
config = {
|
||||||
|
nixpkgs.system = lib.mkDefault system_;
|
||||||
|
_module.args.pkgs = lib.mkIf (pkgs_ != null) (lib.mkForce pkgs_);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
in rec {
|
in rec {
|
||||||
|
|
||||||
# Merge the option definitions in all modules, forming the full
|
# Merge the option definitions in all modules, forming the full
|
||||||
# system configuration.
|
# system configuration.
|
||||||
inherit (pkgs.lib.evalModules {
|
inherit (lib.evalModules {
|
||||||
inherit prefix;
|
inherit prefix check;
|
||||||
modules = modules ++ extraModules ++ baseModules;
|
modules = modules ++ extraModules ++ baseModules ++ [ pkgsModule ];
|
||||||
args = extraArgs;
|
args = extraArgs;
|
||||||
check = check && options.environment.checkConfigurationOptions.value;
|
|
||||||
}) config options;
|
}) config options;
|
||||||
|
|
||||||
# These are the extra arguments passed to every module. In
|
# These are the extra arguments passed to every module. In
|
||||||
@ -33,40 +57,8 @@ in rec {
|
|||||||
# the 64-bit package anyway. However, it would be cleaner to respect
|
# the 64-bit package anyway. However, it would be cleaner to respect
|
||||||
# nixpkgs.config here.
|
# nixpkgs.config here.
|
||||||
extraArgs = extraArgs_ // {
|
extraArgs = extraArgs_ // {
|
||||||
inherit pkgs modules baseModules;
|
inherit modules baseModules;
|
||||||
modulesPath = ../modules;
|
|
||||||
pkgs_i686 = import ./nixpkgs.nix { system = "i686-linux"; config.allowUnfree = true; };
|
|
||||||
utils = import ./utils.nix pkgs;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Import Nixpkgs, allowing the NixOS option nixpkgs.config to
|
inherit (config._module.args) pkgs;
|
||||||
# specify the Nixpkgs configuration (e.g., to set package options
|
|
||||||
# such as firefox.enableGeckoMediaPlayer, or to apply global
|
|
||||||
# overrides such as changing GCC throughout the system), and the
|
|
||||||
# option nixpkgs.system to override the platform type. This is
|
|
||||||
# tricky, because we have to prevent an infinite recursion: "pkgs"
|
|
||||||
# is passed as an argument to NixOS modules, but the value of "pkgs"
|
|
||||||
# depends on config.nixpkgs.config, which we get from the modules.
|
|
||||||
# So we call ourselves here with "pkgs" explicitly set to an
|
|
||||||
# instance that doesn't depend on nixpkgs.config.
|
|
||||||
pkgs =
|
|
||||||
if pkgs_ != null
|
|
||||||
then pkgs_
|
|
||||||
else import ./nixpkgs.nix (
|
|
||||||
let
|
|
||||||
system = if nixpkgsOptions.system != "" then nixpkgsOptions.system else system_;
|
|
||||||
nixpkgsOptions = (import ./eval-config.nix {
|
|
||||||
inherit system extraArgs modules prefix;
|
|
||||||
# For efficiency, leave out most NixOS modules; they don't
|
|
||||||
# define nixpkgs.config, so it's pointless to evaluate them.
|
|
||||||
baseModules = [ ../modules/misc/nixpkgs.nix ../modules/config/no-x-libs.nix ];
|
|
||||||
pkgs = import ./nixpkgs.nix { system = system_; config = {}; };
|
|
||||||
check = false;
|
|
||||||
}).config.nixpkgs;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
inherit system;
|
|
||||||
inherit (nixpkgsOptions) config;
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{ config, pkgs, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
with pkgs.lib;
|
with lib;
|
||||||
|
|
||||||
let fcBool = x: if x then "<bool>true</bool>" else "<bool>false</bool>";
|
let fcBool = x: if x then "<bool>true</bool>" else "<bool>false</bool>";
|
||||||
in
|
in
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
{ lib, ... }:
|
|
||||||
|
|
||||||
with lib;
|
|
||||||
|
|
||||||
{
|
|
||||||
options = {
|
|
||||||
environment.checkConfigurationOptions = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
|
||||||
description = ''
|
|
||||||
Whether to check the validity of the entire configuration.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
14
nixos/modules/misc/extra-arguments.nix
Normal file
14
nixos/modules/misc/extra-arguments.nix
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{ lib, pkgs, config, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
_module.args = {
|
||||||
|
modulesPath = ../.;
|
||||||
|
|
||||||
|
pkgs_i686 = import ../../lib/nixpkgs.nix {
|
||||||
|
system = "i686-linux";
|
||||||
|
config.allowUnfree = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
utils = import ../../lib/utils.nix pkgs;
|
||||||
|
};
|
||||||
|
}
|
@ -60,6 +60,7 @@ in
|
|||||||
|
|
||||||
nixpkgs.system = mkOption {
|
nixpkgs.system = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
|
default = builtins.currentSystem;
|
||||||
description = ''
|
description = ''
|
||||||
Specifies the Nix platform type for which NixOS should be built.
|
Specifies the Nix platform type for which NixOS should be built.
|
||||||
If unset, it defaults to the platform type of your host system.
|
If unset, it defaults to the platform type of your host system.
|
||||||
@ -71,6 +72,10 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
nixpkgs.system = mkDefault pkgs.stdenv.system;
|
_module.args.pkgs = import ../../lib/nixpkgs.nix {
|
||||||
|
system = config.nixpkgs.system;
|
||||||
|
|
||||||
|
inherit (config.nixpkgs) config;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -44,8 +44,8 @@
|
|||||||
./installer/tools/nixos-checkout.nix
|
./installer/tools/nixos-checkout.nix
|
||||||
./installer/tools/tools.nix
|
./installer/tools/tools.nix
|
||||||
./misc/assertions.nix
|
./misc/assertions.nix
|
||||||
./misc/check-config.nix
|
|
||||||
./misc/crashdump.nix
|
./misc/crashdump.nix
|
||||||
|
./misc/extra-arguments.nix
|
||||||
./misc/ids.nix
|
./misc/ids.nix
|
||||||
./misc/lib.nix
|
./misc/lib.nix
|
||||||
./misc/locate.nix
|
./misc/locate.nix
|
||||||
|
@ -135,6 +135,8 @@ in zipModules ([]
|
|||||||
|
|
||||||
++ obsolete [ "services" "mysql55" ] [ "services" "mysql" ]
|
++ obsolete [ "services" "mysql55" ] [ "services" "mysql" ]
|
||||||
|
|
||||||
|
++ obsolete [ "environment" "checkConfigurationOptions" ] [ "_module" "check" ]
|
||||||
|
|
||||||
# XBMC
|
# XBMC
|
||||||
++ obsolete [ "services" "xserver" "windowManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ]
|
++ obsolete [ "services" "xserver" "windowManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ]
|
||||||
++ obsolete [ "services" "xserver" "desktopManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ]
|
++ obsolete [ "services" "xserver" "desktopManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ]
|
||||||
|
@ -6,8 +6,9 @@
|
|||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
|
parentConfig = config;
|
||||||
|
|
||||||
pamOpts = args: {
|
pamOpts = { config, name, ... }: let cfg = config; in let config = parentConfig; in {
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
|
|
||||||
@ -180,8 +181,8 @@ let
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
config = let cfg = args.config; in {
|
config = {
|
||||||
name = mkDefault args.name;
|
name = mkDefault name;
|
||||||
setLoginUid = mkDefault cfg.startSession;
|
setLoginUid = mkDefault cfg.startSession;
|
||||||
limits = mkDefault config.security.pam.loginLimits;
|
limits = mkDefault config.security.pam.loginLimits;
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# of the virtual consoles. The latter is useful for the installation
|
# of the virtual consoles. The latter is useful for the installation
|
||||||
# CD.
|
# CD.
|
||||||
|
|
||||||
{ config, lib, pkgs, baseModules, ... } @ extraArgs:
|
{ config, lib, pkgs, baseModules, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ let
|
|||||||
|
|
||||||
eval = evalModules {
|
eval = evalModules {
|
||||||
modules = [ versionModule ] ++ baseModules;
|
modules = [ versionModule ] ++ baseModules;
|
||||||
args = (removeAttrs extraArgs ["config" "options"]) // { modules = [ ]; };
|
args = (config._module.args) // { modules = [ ]; };
|
||||||
};
|
};
|
||||||
|
|
||||||
manual = import ../../../doc/manual {
|
manual = import ../../../doc/manual {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{ config, lib, pkgs, utils, ... }:
|
{ config, lib, pkgs, utils, ... }:
|
||||||
|
|
||||||
with lib;
|
|
||||||
with utils;
|
with utils;
|
||||||
|
with lib;
|
||||||
with import ./systemd-unit-options.nix { inherit config lib; };
|
with import ./systemd-unit-options.nix { inherit config lib; };
|
||||||
|
|
||||||
let
|
let
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
{ config, pkgs, modulesPath, ... }:
|
|
||||||
|
|
||||||
{
|
{
|
||||||
imports = [ "${modulesPath}/virtualisation/amazon-image.nix" ];
|
imports = [ ./amazon-image.nix ];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user