49 showDeclPrefix = loc: decl: prefix:
50 " - option(s) with prefix `${showOption (loc ++ [prefix])}' in module `${decl._file}'";
51 showRawDecls = loc: decls:
56 (showDeclPrefix loc decl)
57 (attrNames decl.options)
67 Evaluate a set of modules. The result is a set with the attributes:
69 ‘options’: The nested set of all option declarations,
71 ‘config’: The nested set of all option values.
73 ‘type’: A module system type representing the module set as a submodule,
74 to be extended by configuration from the containing module set.
76 This is also available as the module argument ‘moduleType’.
78 ‘extendModules’: A function similar to ‘evalModules’ but building on top
79 of the module set. Its arguments, ‘modules’ and ‘specialArgs’ are
80 added to the existing values.
82 Using ‘extendModules’ a few times has no performance impact as long
83 as you only reference the final ‘options’ and ‘config’.
84 If you do reference multiple ‘config’ (or ‘options’) from before and
85 after ‘extendModules’, performance is the same as with multiple
86 ‘evalModules’ invocations, because the new modules' ability to
87 override existing configuration fundamentally requires a new
88 fixpoint to be constructed.
90 This is also available as a module argument.
92 ‘_module’: A portion of the configuration tree which is elided from
93 ‘config’. It contains some values that are mostly internal to the
94 module system implementation.
96 !!! Please think twice before adding to this argument list! The more
97 that is specified here instead of in the modules themselves the harder
98 it is to transparently move a set of modules to be a submodule of another
99 config (as the proper arguments need to be replicated at each call to
100 evalModules) and the less declarative the module set is. */
101 evalModules = evalModulesArgs@
104 , # This should only be used for special arguments that need to be evaluated
105 # when resolving module structure (like in imports). For everything else,
106 # there's _module.args. If specialArgs.modulesPath is defined it will be
107 # used as the base path for disabledModules.
109 , # This would be remove in the future, Prefer _module.args option instead.
111 , # This would be remove in the future, Prefer _module.check option instead.
116 lib.warnIf (evalModulesArgs?args) "The args argument to evalModules is deprecated. Please set config._module.args instead."
117 lib.warnIf (evalModulesArgs?check) "The check argument to evalModules is deprecated. Please set config._module.check instead."
121 optional (evalModulesArgs?args) {
126 ++ optional (evalModulesArgs?check) {
128 _module.check = mkDefault check;
131 regularModules = modules ++ legacyModules;
133 # This internal module declare internal options under the `_module'
134 # attribute. These options are fragile, as they are used by the
135 # module system to change the interpretation of modules.
137 # When extended with extendModules or moduleType, a fresh instance of
138 # this module is used, to avoid conflicts and allow chaining of
140 internalModule = rec {
141 _file = "lib/modules.nix";
146 _module.args = mkOption {
147 # Because things like `mkIf` are entirely useless for
148 # `_module.args` (because there's no way modules can check which
149 # arguments were passed), we'll use `lazyAttrsOf` which drops
150 # support for that, in turn it's lazy in its values. This means e.g.
151 # a `_module.args.pkgs = import (fetchTarball { ... }) {}` won't
152 # start a download when `pkgs` wasn't evaluated.
153 type = types.lazyAttrsOf types.raw;
154 # Only render documentation once at the root of the option tree,
155 # not for all individual submodules.
156 # Allow merging option decls to make this internal regardless.
158 then null # unset => visible
159 else "internal"} = true;
160 # TODO: Change the type of this option to a submodule with a
161 # freeformType, so that individual arguments can be documented
163 description = lib.mdDoc ''
164 Additional arguments passed to each module in addition to ones
165 like `lib`, `config`,
166 and `pkgs`, `modulesPath`.
168 This option is also available to all submodules. Submodules do not
169 inherit args from their parent module, nor do they provide args to
170 their parent module or sibling submodules. The sole exception to
171 this is the argument `name` which is provided by
172 parent modules to a submodule and contains the attribute name
173 the submodule is bound to, or a unique generated name if it is
174 not bound to an attribute.
176 Some arguments are already passed by default, of which the
177 following *cannot* be changed with this option:
178 - {var}`lib`: The nixpkgs library.
179 - {var}`config`: The results of all options after merging the values from all modules together.
180 - {var}`options`: The options declared in all modules.
181 - {var}`specialArgs`: The `specialArgs` argument passed to `evalModules`.
182 - All attributes of {var}`specialArgs`
184 Whereas option values can generally depend on other option values
185 thanks to laziness, this does not apply to `imports`, which
186 must be computed statically before anything else.
188 For this reason, callers of the module system can provide `specialArgs`
189 which are available during import resolution.
191 For NixOS, `specialArgs` includes
192 {var}`modulesPath`, which allows you to import
193 extra modules from the nixpkgs package tree without having to
194 somehow make the module aware of the location of the
195 `nixpkgs` or NixOS directories.
197 { modulesPath, ... }: {
199 (modulesPath + "/profiles/minimal.nix")
204 For NixOS, the default value for this option includes at least this argument:
205 - {var}`pkgs`: The nixpkgs package set according to
206 the {option}`nixpkgs.pkgs` option.
210 _module.check = mkOption {
214 description = lib.mdDoc "Whether to check whether all option definitions have matching declarations.";
217 _module.freeformType = mkOption {
218 type = types.nullOr types.optionType;
221 description = lib.mdDoc ''
222 If set, merge all definitions that don't have an associated option
223 together using this type. The result then gets combined with the
224 values of all declared options to produce the final `
227 If this is `null`, definitions without an option
228 will throw an error unless {option}`_module.check` is
233 _module.specialArgs = mkOption {
236 description = lib.mdDoc ''
237 Externally provided module arguments that can't be modified from
238 within a configuration, but can be used in module imports.
245 inherit extendModules;
248 _module.specialArgs = specialArgs;
253 let collected = collectModules
254 (specialArgs.modulesPath or "")
255 (regularModules ++ [ internalModule ])
256 ({ inherit lib options config specialArgs; } // specialArgs);
257 in mergeModules prefix (reverseList collected);
259 options = merged.matchedOptions;
264 # For definitions that have an associated option
265 declaredConfig = mapAttrsRecursiveCond (v: ! isOption v) (_: v: v.value) options;
267 # If freeformType is set, this is for definitions that don't have an associated option
272 value = setAttrByPath def.prefix def.value;
273 }) merged.unmatchedDefns;
274 in if defs == [] then {}
275 else declaredConfig._module.freeformType.merge prefix defs;
277 in if declaredConfig._module.freeformType == null then declaredConfig
278 # Because all definitions that had an associated option ended in
279 # declaredConfig, freeformConfig can only contain the non-option
280 # paths, meaning recursiveUpdate will never override any value
281 else recursiveUpdate freeformConfig declaredConfig;
284 if config._module.check && config._module.freeformType == null && merged.unmatchedDefns != [] then
286 firstDef = head merged.unmatchedDefns;
287 baseMsg = "The option `${showOption (prefix ++ firstDef.prefix)}' does not exist. Definition values:${showDefs [ firstDef ]}";
289 if attrNames options == [ "_module" ]
292 optionName = showOption prefix;
298 It seems as if you're trying to declare an option by placing it into `config' rather than `options'!
304 However there are no options defined in `${showOption prefix}'. Are you sure you've
305 declared your options properly? This can happen if you e.g. declared your options in `types.submodule'
306 under `config' rather than `options'.
311 checked = builtins.seq checkUnmatched;
313 extendModules = extendArgs@{
318 evalModules (evalModulesArgs // {
319 modules = regularModules ++ modules;
320 specialArgs = evalModulesArgs.specialArgs or {} // specialArgs;
321 prefix = extendArgs.prefix or evalModulesArgs.prefix or [];
324 type = lib.types.submoduleWith {
325 inherit modules specialArgs;
328 result = withWarnings {
329 options = checked options;
330 config = checked (removeAttrs config [ "_module" ]);
331 _module = checked (config._module);
332 inherit extendModules type;
336 # collectModules :: (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]
338 # Collects all modules recursively through `import` statements, filtering out
339 # all modules in disabledModules.
342 # Like unifyModuleSyntax, but also imports paths and calls functions if necessary
343 loadModule = args: fallbackFile: fallbackKey: m:
344 if isFunction m || isAttrs m then
345 unifyModuleSyntax fallbackFile fallbackKey (applyModuleArgsIfFunction fallbackKey m args)
346 else if isList m then
347 let defs = [{ file = fallbackFile; value = m; }]; in
348 throw "Module imports can't be nested lists. Perhaps you meant to remove one level of lists? Definitions: ${showDefs defs}"
349 else unifyModuleSyntax (toString m) (toString m) (applyModuleArgsIfFunction (toString m) (import m) args);
352 Collects all modules recursively into the form
355 disabled = [ <list of disabled modules> ];
356 # All modules of the main module list
360 module = <module for key1>;
361 # All modules imported by the module for key1
365 module = <module for key1-1>;
366 # All modules imported by the module for key1-1
376 collectStructuredModules =
378 collectResults = modules: {
379 disabled = concatLists (catAttrs "disabled" modules);
382 in parentFile: parentKey: initialModules: args: collectResults (imap1 (n: x:
384 module = loadModule args parentFile "${parentKey}:anon-${toString n}" x;
385 collectedImports = collectStructuredModules module._file module.key module.imports args;
389 modules = collectedImports.modules;
390 disabled = module.disabledModules ++ collectedImports.disabled;
393 # filterModules :: String -> { disabled, modules } -> [ Module ]
395 # Filters a structure as emitted by collectStructuredModules by removing all disabled
396 # modules recursively. It returns the final list of unique-by-key modules
397 filterModules = modulesPath: { disabled, modules }:
399 moduleKey = m: if isString m && (builtins.substring 0 1 m != "/")
400 then toString modulesPath + "/" + m
402 disabledKeys = map moduleKey disabled;
403 keyFilter = filter (attrs: ! elem attrs.key disabledKeys);
404 in map (attrs: attrs.module) (builtins.genericClosure {
405 startSet = keyFilter modules;
406 operator = attrs: keyFilter attrs.modules;
409 in modulesPath: initialModules: args:
410 filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args);
412 /* Wrap a module with a default location for reporting errors. */
413 setDefaultModuleLocation = file: m:
414 { _file = file; imports = [ m ]; };
416 /* Massage a module into canonical form, that is, a set consisting
417 of ‘options’, ‘config’ and ‘imports’ attributes. */
418 unifyModuleSyntax = file: key: m:
420 addMeta = config: if m ? meta
421 then mkMerge [ config { meta = m.meta; } ]
423 addFreeformType = config: if m ? freeformType
424 then mkMerge [ config { _module.freeformType = m.freeformType; } ]
427 if m ? config || m ? options then
428 let badAttrs = removeAttrs m ["_file" "key" "disabledModules" "imports" "options" "config" "meta" "freeformType"]; in
429 if badAttrs != {} then
430 throw "Module `${key}' has an unsupported attribute `${head (attrNames badAttrs)}'. This is caused by introducing a top-level `config' or `options' attribute. Add configuration attributes immediately on the top level instead, or move all of them (namely: ${toString (attrNames badAttrs)}) into the explicit `config' attribute."
432 { _file = toString m._file or file;
433 key = toString m.key or key;
434 disabledModules = m.disabledModules or [];
435 imports = m.imports or [];
436 options = m.options or {};
437 config = addFreeformType (addMeta (m.config or {}));
441 lib.throwIfNot (isAttrs m) "module ${file} (${key}) does not look like a module."
442 { _file = toString m._file or file;
443 key = toString m.key or key;
444 disabledModules = m.disabledModules or [];
445 imports = m.require or [] ++ m.imports or [];
447 config = addFreeformType (removeAttrs m ["_file" "key" "disabledModules" "require" "imports" "freeformType"]);
450 applyModuleArgsIfFunction = key: f: args@{ config, options, lib, ... }: if isFunction f then
452 # Module arguments are resolved in a strict manner when attribute set
453 # deconstruction is used. As the arguments are now defined with the
454 # config._module.args option, the strictness used on the attribute
455 # set argument would cause an infinite loop, if the result of the
456 # option is given as argument.
458 # To work-around the strictness issue on the deconstruction of the
459 # attributes set argument, we create a new attribute set which is
460 # constructed to satisfy the expected set of attributes. Thus calling
461 # a module will resolve strictly the attributes used as argument but
462 # not their values. The values are forwarding the result of the
463 # evaluation of the option.
464 context = name: ''while evaluating the module argument `${name}' in "${key}":'';
465 extraArgs = builtins.mapAttrs (name: _:
466 builtins.addErrorContext (context name)
467 (args.${name} or config._module.args.${name})
468 ) (lib.functionArgs f);
470 # Note: we append in the opposite order such that we can add an error
471 # context on the explicited arguments of "args" too. This update
472 # operator is used to make the "args@{ ... }: with args.lib;" notation
474 in f (args // extraArgs)
478 /* Merge a list of modules. This will recurse over the option
479 declarations in all modules, combining them into a single set.
480 At the same time, for each option declaration, it will merge the
481 corresponding option definitions in all machines, returning them
482 in the ‘value’ attribute of each option.
484 This returns a set like
486 # A recursive set of options along with their final values
488 foo = { _type = "option"; value = "option value of foo"; ... };
489 bar.baz = { _type = "option"; value = "option value of bar.baz"; ... };
492 # A list of definitions that weren't matched by any option
494 { file = "file.nix"; prefix = [ "qux" ]; value = "qux"; }
499 mergeModules = prefix: modules:
500 mergeModules' prefix modules
501 (concatMap (m: map (config: { file = m._file; inherit config; }) (pushDownProperties m.config)) modules);
503 mergeModules' = prefix: options: configs:
505 /* byName is like foldAttrs, but will look for attributes to merge in the
506 specified attribute name.
508 byName "foo" (module: value: ["module.hidden=${module.hidden},value=${value}"])
512 foo={qux="bar"; gla="flop";};
516 foo={qux="gne"; gli="flip";};
521 gla = [ "module.hidden=baz,value=flop" ];
522 gli = [ "module.hidden=fli,value=flip" ];
523 qux = [ "module.hidden=baz,value=bar" "module.hidden=fli,value=gne" ];
526 byName = attr: f: modules:
527 zipAttrsWith (n: concatLists)
528 (map (module: let subtree = module.${attr}; in
529 if !(builtins.isAttrs subtree) then
531 You're trying to declare a value of type `${builtins.typeOf subtree}'
532 rather than an attribute-set for the option
533 `${builtins.concatStringsSep "." prefix}'!
535 This usually happens if `${builtins.concatStringsSep "." prefix}' has option
536 definitions inside that are not matched. Please check how to properly define
537 this option by e.g. referring to `man 5 configuration.nix'!
540 mapAttrs (n: f module) subtree
542 # an attrset 'name' => list of submodules that declare ‘name’.
543 declsByName = byName "options" (module: option:
544 [{ inherit (module) _file; options = option; }]
546 # an attrset 'name' => list of submodules that define ‘name’.
547 defnsByName = byName "config" (module: value:
548 map (config: { inherit (module) file; inherit config; }) (pushDownProperties value)
550 # extract the definitions for each loc
551 defnsByName' = byName "config" (module: value:
552 [{ inherit (module) file; inherit value; }]
555 # Convert an option tree decl to a submodule option decl
556 optionTreeToOption = decl:
557 if isOption decl.options
561 type = types.submoduleWith {
562 modules = [ { options = decl.options; } ];
563 # `null` is not intended for use by modules. It is an internal
564 # value that means "whatever the user has declared elsewhere".
565 # This might become obsolete with https://github.com/NixOS/nixpkgs/issues/162398
566 shorthandOnlyDefinesConfig = null;
571 resultsByName = mapAttrs (name: decls:
572 # We're descending into attribute ‘name’.
574 loc = prefix ++ [name];
575 defns = defnsByName.${name} or [];
576 defns' = defnsByName'.${name} or [];
577 optionDecls = filter (m: isOption m.options) decls;
579 if length optionDecls == length decls then
580 let opt = fixupOptionType loc (mergeOptionDecls loc decls);
582 matchedOptions = evalOptionValue loc opt defns';
585 else if optionDecls != [] then
586 if all (x: x.options.type.name == "submodule") optionDecls
587 # Raw options can only be merged into submodules. Merging into
588 # attrsets might be nice, but ambiguous. Suppose we have
589 # attrset as a `attrsOf submodule`. User declares option
590 # attrset.foo.bar, this could mean:
591 # a. option `bar` is only available in `attrset.foo`
592 # b. option `foo.bar` is available in all `attrset.*`
593 # c. reject and require "<name>" as a reminder that it behaves like (b).
594 # d. magically combine (a) and (c).
595 # All of the above are merely syntax sugar though.
597 let opt = fixupOptionType loc (mergeOptionDecls loc (map optionTreeToOption decls));
599 matchedOptions = evalOptionValue loc opt defns';
604 nonOptions = filter (m: !isOption m.options) decls;
606 throw "The option `${showOption loc}' in module `${(lib.head optionDecls)._file}' would be a parent of the following options, but its type `${(lib.head optionDecls).options.type.description or "<no description>"}' does not support nested options.\n${
607 showRawDecls loc nonOptions
610 mergeModules' loc decls defns) declsByName;
612 matchedOptions = mapAttrs (n: v: v.matchedOptions) resultsByName;
614 # an attrset 'name' => list of unmatched definitions for 'name'
615 unmatchedDefnsByName =
616 # Propagate all unmatched definitions from nested option sets
617 mapAttrs (n: v: v.unmatchedDefns) resultsByName
618 # Plus the definitions for the current prefix that don't have a matching option
619 // removeAttrs defnsByName' (attrNames matchedOptions);
621 inherit matchedOptions;
623 # Transforms unmatchedDefnsByName into a list of definitions
627 # When no config values exist, there can be no unmatched config, so
628 # we short circuit and avoid evaluating more _options_ than necessary.
631 concatLists (mapAttrsToList (name: defs:
633 # Set this so we know when the definition first left unmatched territory
634 prefix = [name] ++ (def.prefix or []);
636 ) unmatchedDefnsByName);
639 /* Merge multiple option declarations into a single declaration. In
640 general, there should be only one declaration of each option.
641 The exception is the ‘options’ attribute, which specifies
642 sub-options. These can be specified multiple times to allow one
643 module to add sub-options to an option declared somewhere else
644 (e.g. multiple modules define sub-options for ‘fileSystems’).
646 'loc' is the list of attribute names where the option is located.
648 'opts' is a list of modules. Each module has an options attribute which
649 correspond to the definition of 'loc' in 'opt.file'. */
654 t' = opt.options.type;
655 mergedType = t.typeMerge t'.functor;
656 typesMergeable = mergedType != null;
657 typeSet = if (bothHave "type") && typesMergeable
658 then { type = mergedType; }
660 bothHave = k: opt.options ? ${k} && res ? ${k};
662 if bothHave "default" ||
663 bothHave "example" ||
664 bothHave "description" ||
666 (bothHave "type" && (! typesMergeable))
668 throw "The option `${showOption loc}' in `${opt._file}' is already declared in ${showFiles res.declarations}."
671 getSubModules = opt.options.type.getSubModules or null;
673 if getSubModules != null then map (setDefaultModuleLocation opt._file) getSubModules ++ res.options
675 in opt.options // res //
676 { declarations = res.declarations ++ [opt._file];
677 options = submodules;
679 ) { inherit loc; declarations = []; options = []; } opts;
681 /* Merge all the definitions of an option to produce the final
683 evalOptionValue = loc: opt: defs:
685 # Add in the default value for this option, if any.
687 (optional (opt ? default)
688 { file = head opt.declarations; value = mkOptionDefault opt.default; }) ++ defs;
690 # Handle properties, check types, and merge everything together.
692 if opt.readOnly or false && length defs' > 1 then
694 # For a better error message, evaluate all readOnly definitions as
695 # if they were the only definition.
696 separateDefs = map (def: def // {
697 value = (mergeDefinitions loc opt.type [ def ]).mergedValue;
699 in throw "The option `${showOption loc}' is read-only, but it's set multiple times. Definition values:${showDefs separateDefs}"
701 mergeDefinitions loc opt.type defs';
703 # Apply the 'apply' function to the merged value. This allows options to
704 # yield a value computed from the definitions
705 value = if opt ? apply then opt.apply res.mergedValue else res.mergedValue;
708 warnIf (opt.type.deprecationMessage != null)
709 "The type `types.${opt.type.name}' of option `${showOption loc}' defined in ${showFiles opt.declarations} is deprecated. ${opt.type.deprecationMessage}";
711 in warnDeprecation opt //
712 { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
713 inherit (res.defsFinal') highestPrio;
714 definitions = map (def: def.value) res.defsFinal;
715 files = map (def: def.file) res.defsFinal;
716 definitionsWithLocations = res.defsFinal;
717 inherit (res) isDefined;
718 # This allows options to be correctly displayed using `${options.path.to.it}`
719 __toString = _: showOption loc;
722 # Merge definitions of a value of a given type.
723 mergeDefinitions = loc: type: defs: rec {
726 # Process mkMerge and mkIf properties.
727 defs' = concatMap (m:
728 map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))
731 # Process mkOverride properties.
732 defs'' = filterOverrides' defs';
734 # Sort mkOrder properties.
736 # Avoid sorting if we don't have to.
737 if any (def: def.value._type or "" == "order") defs''.values
738 then sortProperties defs''.values
742 inherit (defs'') highestPrio;
744 defsFinal = defsFinal'.values;
746 # Type-check the remaining definitions, and merge them. Or throw if no definitions.
749 if all (def: type.check def.value) defsFinal then type.merge loc defsFinal
750 else let allInvalid = filter (def: ! type.check def.value) defsFinal;
751 in throw "A definition for option `${showOption loc}' is not of type `${type.description}'. Definition values:${showDefs allInvalid}"
753 # (nixos-option detects this specific error message and gives it special
754 # handling. If changed here, please change it there too.)
755 throw "The option `${showOption loc}' is used but not defined.";
757 isDefined = defsFinal != [];
760 if isDefined then { value = mergedValue; }
764 /* Given a config set, expand mkMerge properties, and push down the
765 other properties into the children. The result is a list of
766 config sets that do not have properties at top-level. For
769 mkMerge [ { boot = set1; } (mkIf cond { boot = set2; services = set3; }) ]
773 [ { boot = set1; } { boot = mkIf cond set2; services = mkIf cond set3; } ].
775 This transform is the critical step that allows mkIf conditions
776 to refer to the full configuration without creating an infinite
779 pushDownProperties = cfg:
780 if cfg._type or "" == "merge" then
781 concatMap pushDownProperties cfg.contents
782 else if cfg._type or "" == "if" then
783 map (mapAttrs (n: v: mkIf cfg.condition v)) (pushDownProperties cfg.content)
784 else if cfg._type or "" == "override" then
785 map (mapAttrs (n: v: mkOverride cfg.priority v)) (pushDownProperties cfg.content)
786 else # FIXME: handle mkOrder?
789 /* Given a config value, expand mkMerge properties, and discharge
790 any mkIf conditions. That is, this is the place where mkIf
791 conditions are actually evaluated. The result is a list of
792 config values. For example, ‘mkIf false x’ yields ‘[]’,
793 ‘mkIf true x’ yields ‘[x]’, and
795 mkMerge [ 1 (mkIf true 2) (mkIf true (mkIf false 3)) ]
799 dischargeProperties = def:
800 if def._type or "" == "merge" then
801 concatMap dischargeProperties def.contents
802 else if def._type or "" == "if" then
803 if isBool def.condition then
804 if def.condition then
805 dischargeProperties def.content
809 throw "‘mkIf’ called with a non-Boolean condition"
813 /* Given a list of config values, process the mkOverride properties,
814 that is, return the values that have the highest (that is,
815 numerically lowest) priority, and strip the mkOverride
816 properties. For example,
818 [ { file = "/1"; value = mkOverride 10 "a"; }
819 { file = "/2"; value = mkOverride 20 "b"; }
820 { file = "/3"; value = "z"; }
821 { file = "/4"; value = mkOverride 10 "d"; }
826 [ { file = "/1"; value = "a"; }
827 { file = "/4"; value = "d"; }
830 Note that "z" has the default priority 100.
832 filterOverrides = defs: (filterOverrides' defs).values;
834 filterOverrides' = defs:
836 getPrio = def: if def.value._type or "" == "override" then def.value.priority else defaultPriority;
837 highestPrio = foldl' (prio: def: min (getPrio def) prio) 9999 defs;
838 strip = def: if def.value._type or "" == "override" then def // { value = def.value.content; } else def;
840 values = concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs;
844 /* Sort a list of properties. The sort priority of a property is
845 1000 by default, but can be overridden by wrapping the property
847 sortProperties = defs:
850 if def.value._type or "" == "order"
851 then def // { value = def.value.content; inherit (def.value) priority; }
853 defs' = map strip defs;
854 compare = a: b: (a.priority or 1000) < (b.priority or 1000);
855 in sort compare defs';
857 # This calls substSubModules, whose entire purpose is only to ensure that
858 # option declarations in submodules have accurate position information.
859 # TODO: Merge this into mergeOptionDecls
860 fixupOptionType = loc: opt:
861 if opt.type.getSubModules or null == null
862 then opt // { type = opt.type or types.unspecified; }
863 else opt // { type = opt.type.substSubModules opt.options; options = []; };
868 mkIf = condition: content:
870 inherit condition content;
873 mkAssert = assertion: message: content:
875 (if assertion then true else throw "\nFailed assertion: ${message}")
883 mkOverride = priority: content:
884 { _type = "override";
885 inherit priority content;
888 mkOptionDefault = mkOverride 1500; # priority of option defaults
889 mkDefault = mkOverride 1000; # used in config sections of non-user modules to set a default
890 mkImageMediaOverride = mkOverride 60; # image media profiles can be derived by inclusion into host config, hence needing to override host config, but do allow user to mkForce
891 mkForce = mkOverride 50;
892 mkVMOverride = mkOverride 10; # used by ‘nixos-rebuild build-vm’
894 mkFixStrictness = lib.warn "lib.mkFixStrictness has no effect and will be removed. It returns its argument unmodified, so you can just remove any calls." id;
896 mkOrder = priority: content:
898 inherit priority content;
901 mkBefore = mkOrder 500;
902 mkAfter = mkOrder 1500;
904 # The default priority for things that don't have a priority specified.
905 defaultPriority = 100;
907 # Convenient property used to transfer all definitions and their
908 # properties from one option to another. This property is useful for
909 # renaming options, and also for including properties from another module
910 # system, including sub-modules.
912 # { config, options, ... }:
915 # # 'bar' might not always be defined in the current module-set.
916 # config.foo.enable = mkAliasDefinitions (options.bar.enable or {});
918 # # 'barbaz' has to be defined in the current module-set.
919 # config.foobar.paths = mkAliasDefinitions options.barbaz.paths;
922 # Note, this is different than taking the value of the option and using it
923 # as a definition, as the new definition will not keep the mkOverride /
924 # mkDefault properties of the previous option.
926 mkAliasDefinitions = mkAliasAndWrapDefinitions id;
927 mkAliasAndWrapDefinitions = wrap: option:
928 mkAliasIfDef option (wrap (mkMerge option.definitions));
930 # Similar to mkAliasAndWrapDefinitions but copies over the priority from the
933 # If a priority is not set, it assumes a priority of defaultPriority.
934 mkAliasAndWrapDefsWithPriority = wrap: option:
936 prio = option.highestPrio or defaultPriority;
937 defsWithPrio = map (mkOverride prio) option.definitions;
938 in mkAliasIfDef option (wrap (mkMerge defsWithPrio));
940 mkAliasIfDef = option:
941 mkIf (isOption option && option.isDefined);
944 fixMergeModules = modules: args: evalModules { inherit modules args; check = false; };
947 /* Return a module that causes a warning to be shown if the
948 specified option is defined. For example,
950 mkRemovedOptionModule [ "boot" "loader" "grub" "bootDevice" ] "<replacement instructions>"
952 causes a assertion if the user defines boot.loader.grub.bootDevice.
954 replacementInstructions is a string that provides instructions on
955 how to achieve the same functionality without the removed option,
956 or alternatively a reasoning why the functionality is not needed.
957 replacementInstructions SHOULD be provided!
959 mkRemovedOptionModule = optionName: replacementInstructions:
961 { options = setAttrByPath optionName (mkOption {
963 apply = x: throw "The option `${showOption optionName}' can no longer be used since it's been removed. ${replacementInstructions}";
966 let opt = getAttrFromPath optionName options; in [{
967 assertion = !opt.isDefined;
969 The option definition `${showOption optionName}' in ${showFiles opt.files} no longer has any effect; please remove it.
970 ${replacementInstructions}
975 /* Return a module that causes a warning to be shown if the
976 specified "from" option is defined; the defined value is however
977 forwarded to the "to" option. This can be used to rename options
978 while providing backward compatibility. For example,
980 mkRenamedOptionModule [ "boot" "copyKernels" ] [ "boot" "loader" "grub" "copyKernels" ]
982 forwards any definitions of boot.copyKernels to
983 boot.loader.grub.copyKernels while printing a warning.
985 This also copies over the priority from the aliased option to the
988 mkRenamedOptionModule = from: to: doRename {
992 use = builtins.trace "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
995 mkRenamedOptionModuleWith = {
996 /* Old option path as list of strings. */
998 /* New option path as list of strings. */
1002 Release number of the first release that contains the rename, ignoring backports.
1003 Set it to the upcoming release, matching the nixpkgs/.version file.
1010 warn = lib.isInOldestRelease sinceRelease;
1011 use = lib.warnIf (lib.isInOldestRelease sinceRelease)
1012 "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
1015 /* Return a module that causes a warning to be shown if any of the "from"
1016 option is defined; the defined values can be used in the "mergeFn" to set
1018 This function can be used to merge multiple options into one that has a
1021 "mergeFn" takes the module "config" as a parameter and must return a value
1022 of "to" option type.
1024 mkMergedOptionModule
1029 let value = p: getAttrFromPath p config;
1031 if (value [ "a" "b" "c" ]) == true then "foo"
1032 else if (value [ "d" "e" "f" ]) == true then "bar"
1035 - options.a.b.c is a removed boolean option
1036 - options.d.e.f is a removed boolean option
1037 - options.x.y.z is a new str option that combines a.b.c and d.e.f
1040 This show a warning if any a.b.c or d.e.f is set, and set the value of
1041 x.y.z to the result of the merge function
1043 mkMergedOptionModule = from: to: mergeFn:
1044 { config, options, ... }:
1046 options = foldl' recursiveUpdate {} (map (path: setAttrByPath path (mkOption {
1048 # To use the value in mergeFn without triggering errors
1049 default = "_mkMergedOptionModule";
1053 warnings = filter (x: x != "") (map (f:
1054 let val = getAttrFromPath f config;
1055 opt = getAttrFromPath f options;
1058 (val != "_mkMergedOptionModule")
1059 "The option `${showOption f}' defined in ${showFiles opt.files} has been changed to `${showOption to}' that has a different type. Please read `${showOption to}' documentation and update your configuration accordingly."
1061 } // setAttrByPath to (mkMerge
1063 (any (f: (getAttrFromPath f config) != "_mkMergedOptionModule") from)
1067 /* Single "from" version of mkMergedOptionModule.
1068 Return a module that causes a warning to be shown if the "from" option is
1069 defined; the defined value can be used in the "mergeFn" to set the "to"
1071 This function can be used to change an option into another that has a
1074 "mergeFn" takes the module "config" as a parameter and must return a value of
1077 mkChangedOptionModule [ "a" "b" "c" ] [ "x" "y" "z" ]
1079 let value = getAttrFromPath [ "a" "b" "c" ] config;
1081 if value > 100 then "high"
1084 - options.a.b.c is a removed int option
1085 - options.x.y.z is a new str option that supersedes a.b.c
1087 This show a warning if a.b.c is set, and set the value of x.y.z to the
1088 result of the change function
1090 mkChangedOptionModule = from: to: changeFn:
1091 mkMergedOptionModule [ from ] to changeFn;
1093 /* Like ‘mkRenamedOptionModule’, but doesn't show a warning. */
1094 mkAliasOptionModule = from: to: doRename {
1101 /* mkDerivedConfig : Option a -> (a -> Definition b) -> Definition b
1103 Create config definitions with the same priority as the definition of another option.
1104 This should be used for option definitions where one option sets the value of another as a convenience.
1105 For instance a config file could be set with a `text` or `source` option, where text translates to a `source`
1106 value using `mkDerivedConfig options.text (pkgs.writeText "filename.conf")`.
1108 It takes care of setting the right priority using `mkOverride`.
1110 # TODO: make the module system error message include information about `opt` in
1111 # error messages about conflicts. E.g. introduce a variation of `mkOverride` which
1112 # adds extra location context to the definition object. This will allow context to be added
1113 # to all messages that report option locations "this value was derived from <full option name>
1114 # which was defined in <locations>". It can provide a trace of options that contributed
1116 mkDerivedConfig = opt: f:
1118 (opt.highestPrio or defaultPriority)
1121 doRename = { from, to, visible, warn, use, withPriority ? true }:
1122 { config, options, ... }:
1124 fromOpt = getAttrFromPath from options;
1125 toOf = attrByPath to
1126 (abort "Renaming error: option `${showOption to}' does not exist.");
1127 toType = let opt = attrByPath to {} options; in opt.type or (types.submodule {});
1130 options = setAttrByPath from (mkOption {
1132 description = lib.mdDoc "Alias of {option}`${showOption to}`.";
1133 apply = x: use (toOf config);
1134 } // optionalAttrs (toType != null) {
1138 (optionalAttrs (options ? warnings) {
1139 warnings = optional (warn && fromOpt.isDefined)
1140 "The option `${showOption from}' defined in ${showFiles fromOpt.files} has been renamed to `${showOption to}'.";
1143 then mkAliasAndWrapDefsWithPriority (setAttrByPath to) fromOpt
1144 else mkAliasAndWrapDefinitions (setAttrByPath to) fromOpt)
1148 /* Use this function to import a JSON file as NixOS configuration.
1150 modules.importJSON :: path -> attrs
1152 importJSON = file: {
1154 config = lib.importJSON file;
1157 /* Use this function to import a TOML file as NixOS configuration.
1159 modules.importTOML :: path -> attrs
1161 importTOML = file: {
1163 config = lib.importTOML file;