49 isConvertibleWithToString
52 showDeclPrefix = loc: decl: prefix:
53 " - option(s) with prefix `${showOption (loc ++ [prefix])}' in module `${decl._file}'";
54 showRawDecls = loc: decls:
59 (showDeclPrefix loc decl)
60 (attrNames decl.options)
65 /* See https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules
66 or file://./../doc/module-system/module-system.chapter.md
68 !!! Please think twice before adding to this argument list! The more
69 that is specified here instead of in the modules themselves the harder
70 it is to transparently move a set of modules to be a submodule of another
71 config (as the proper arguments need to be replicated at each call to
72 evalModules) and the less declarative the module set is. */
73 evalModules = evalModulesArgs@
76 , # This should only be used for special arguments that need to be evaluated
77 # when resolving module structure (like in imports). For everything else,
78 # there's _module.args. If specialArgs.modulesPath is defined it will be
79 # used as the base path for disabledModules.
82 # A nominal type for modules. When set and non-null, this adds a check to
83 # make sure that only compatible modules are imported.
84 # This would be remove in the future, Prefer _module.args option instead.
87 , # This would be remove in the future, Prefer _module.check option instead.
92 lib.warnIf (evalModulesArgs?args) "The args argument to evalModules is deprecated. Please set config._module.args instead."
93 lib.warnIf (evalModulesArgs?check) "The check argument to evalModules is deprecated. Please set config._module.check instead."
97 optional (evalModulesArgs?args) {
102 ++ optional (evalModulesArgs?check) {
104 _module.check = mkDefault check;
107 regularModules = modules ++ legacyModules;
109 # This internal module declare internal options under the `_module'
110 # attribute. These options are fragile, as they are used by the
111 # module system to change the interpretation of modules.
113 # When extended with extendModules or moduleType, a fresh instance of
114 # this module is used, to avoid conflicts and allow chaining of
116 internalModule = rec {
117 _file = "lib/modules.nix";
122 _module.args = mkOption {
123 # Because things like `mkIf` are entirely useless for
124 # `_module.args` (because there's no way modules can check which
125 # arguments were passed), we'll use `lazyAttrsOf` which drops
126 # support for that, in turn it's lazy in its values. This means e.g.
127 # a `_module.args.pkgs = import (fetchTarball { ... }) {}` won't
128 # start a download when `pkgs` wasn't evaluated.
129 type = types.lazyAttrsOf types.raw;
130 # Only render documentation once at the root of the option tree,
131 # not for all individual submodules.
132 # Allow merging option decls to make this internal regardless.
134 then null # unset => visible
135 else "internal"} = true;
136 # TODO: Change the type of this option to a submodule with a
137 # freeformType, so that individual arguments can be documented
139 description = lib.mdDoc ''
140 Additional arguments passed to each module in addition to ones
141 like `lib`, `config`,
142 and `pkgs`, `modulesPath`.
144 This option is also available to all submodules. Submodules do not
145 inherit args from their parent module, nor do they provide args to
146 their parent module or sibling submodules. The sole exception to
147 this is the argument `name` which is provided by
148 parent modules to a submodule and contains the attribute name
149 the submodule is bound to, or a unique generated name if it is
150 not bound to an attribute.
152 Some arguments are already passed by default, of which the
153 following *cannot* be changed with this option:
154 - {var}`lib`: The nixpkgs library.
155 - {var}`config`: The results of all options after merging the values from all modules together.
156 - {var}`options`: The options declared in all modules.
157 - {var}`specialArgs`: The `specialArgs` argument passed to `evalModules`.
158 - All attributes of {var}`specialArgs`
160 Whereas option values can generally depend on other option values
161 thanks to laziness, this does not apply to `imports`, which
162 must be computed statically before anything else.
164 For this reason, callers of the module system can provide `specialArgs`
165 which are available during import resolution.
167 For NixOS, `specialArgs` includes
168 {var}`modulesPath`, which allows you to import
169 extra modules from the nixpkgs package tree without having to
170 somehow make the module aware of the location of the
171 `nixpkgs` or NixOS directories.
173 { modulesPath, ... }: {
175 (modulesPath + "/profiles/minimal.nix")
180 For NixOS, the default value for this option includes at least this argument:
181 - {var}`pkgs`: The nixpkgs package set according to
182 the {option}`nixpkgs.pkgs` option.
186 _module.check = mkOption {
190 description = lib.mdDoc "Whether to check whether all option definitions have matching declarations.";
193 _module.freeformType = mkOption {
194 type = types.nullOr types.optionType;
197 description = lib.mdDoc ''
198 If set, merge all definitions that don't have an associated option
199 together using this type. The result then gets combined with the
200 values of all declared options to produce the final `
203 If this is `null`, definitions without an option
204 will throw an error unless {option}`_module.check` is
209 _module.specialArgs = mkOption {
212 description = lib.mdDoc ''
213 Externally provided module arguments that can't be modified from
214 within a configuration, but can be used in module imports.
221 inherit extendModules;
224 _module.specialArgs = specialArgs;
229 let collected = collectModules
231 (specialArgs.modulesPath or "")
232 (regularModules ++ [ internalModule ])
233 ({ inherit lib options config specialArgs; } // specialArgs);
234 in mergeModules prefix (reverseList collected);
236 options = merged.matchedOptions;
241 # For definitions that have an associated option
242 declaredConfig = mapAttrsRecursiveCond (v: ! isOption v) (_: v: v.value) options;
244 # If freeformType is set, this is for definitions that don't have an associated option
249 value = setAttrByPath def.prefix def.value;
250 }) merged.unmatchedDefns;
251 in if defs == [] then {}
252 else declaredConfig._module.freeformType.merge prefix defs;
254 in if declaredConfig._module.freeformType == null then declaredConfig
255 # Because all definitions that had an associated option ended in
256 # declaredConfig, freeformConfig can only contain the non-option
257 # paths, meaning recursiveUpdate will never override any value
258 else recursiveUpdate freeformConfig declaredConfig;
261 if config._module.check && config._module.freeformType == null && merged.unmatchedDefns != [] then
263 firstDef = head merged.unmatchedDefns;
266 optText = showOption (prefix ++ firstDef.prefix);
268 builtins.addErrorContext
269 "while evaluating the error message for definitions for `${optText}', which is an option that does not exist"
270 (builtins.addErrorContext
271 "while evaluating a definition from `${firstDef.file}'"
272 ( showDefs [ firstDef ])
275 "The option `${optText}' does not exist. Definition values:${defText}";
277 if attrNames options == [ "_module" ]
280 optionName = showOption prefix;
286 It seems as if you're trying to declare an option by placing it into `config' rather than `options'!
292 However there are no options defined in `${showOption prefix}'. Are you sure you've
293 declared your options properly? This can happen if you e.g. declared your options in `types.submodule'
294 under `config' rather than `options'.
299 checked = builtins.seq checkUnmatched;
301 extendModules = extendArgs@{
306 evalModules (evalModulesArgs // {
308 modules = regularModules ++ modules;
309 specialArgs = evalModulesArgs.specialArgs or {} // specialArgs;
310 prefix = extendArgs.prefix or evalModulesArgs.prefix or [];
313 type = lib.types.submoduleWith {
314 inherit modules specialArgs class;
317 result = withWarnings {
318 _type = "configuration";
319 options = checked options;
320 config = checked (removeAttrs config [ "_module" ]);
321 _module = checked (config._module);
322 inherit extendModules type;
327 # collectModules :: (class: String) -> (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]
329 # Collects all modules recursively through `import` statements, filtering out
330 # all modules in disabledModules.
331 collectModules = class: let
333 # Like unifyModuleSyntax, but also imports paths and calls functions if necessary
334 loadModule = args: fallbackFile: fallbackKey: m:
336 unifyModuleSyntax fallbackFile fallbackKey (applyModuleArgs fallbackKey m args)
337 else if isAttrs m then
338 if m._type or "module" == "module" then
339 unifyModuleSyntax fallbackFile fallbackKey m
340 else if m._type == "if" || m._type == "override" then
341 loadModule args fallbackFile fallbackKey { config = m; }
344 "Could not load a value as a module, because it is of type ${lib.strings.escapeNixString m._type}"
345 + lib.optionalString (fallbackFile != unknownModule) ", in file ${toString fallbackFile}."
346 + lib.optionalString (m._type == "configuration") " If you do intend to import this configuration, please only import the modules that make up the configuration. You may have to create a `let` binding, file or attribute to give yourself access to the relevant modules.\nWhile loading a configuration into the module system is a very sensible idea, it can not be done cleanly in practice."
347 # Extended explanation: That's because a finalized configuration is more than just a set of modules. For instance, it has its own `specialArgs` that, by the nature of `specialArgs` can't be loaded through `imports` or the the `modules` argument. So instead, we have to ask you to extract the relevant modules and use those instead. This way, we keep the module system comparatively simple, and hopefully avoid a bad surprise down the line.
349 else if isList m then
350 let defs = [{ file = fallbackFile; value = m; }]; in
351 throw "Module imports can't be nested lists. Perhaps you meant to remove one level of lists? Definitions: ${showDefs defs}"
352 else unifyModuleSyntax (toString m) (toString m) (applyModuleArgsIfFunction (toString m) (import m) args);
358 if m._class != null -> m._class == class
361 throw "The module ${m._file or m.key} was imported into ${class} instead of ${m._class}."
366 Collects all modules recursively into the form
369 disabled = [ <list of disabled modules> ];
370 # All modules of the main module list
374 module = <module for key1>;
375 # All modules imported by the module for key1
379 module = <module for key1-1>;
380 # All modules imported by the module for key1-1
390 collectStructuredModules =
392 collectResults = modules: {
393 disabled = concatLists (catAttrs "disabled" modules);
396 in parentFile: parentKey: initialModules: args: collectResults (imap1 (n: x:
398 module = checkModule (loadModule args parentFile "${parentKey}:anon-${toString n}" x);
399 collectedImports = collectStructuredModules module._file module.key module.imports args;
403 modules = collectedImports.modules;
404 disabled = (if module.disabledModules != [] then [{ file = module._file; disabled = module.disabledModules; }] else []) ++ collectedImports.disabled;
407 # filterModules :: String -> { disabled, modules } -> [ Module ]
409 # Filters a structure as emitted by collectStructuredModules by removing all disabled
410 # modules recursively. It returns the final list of unique-by-key modules
411 filterModules = modulesPath: { disabled, modules }:
416 if builtins.substring 0 1 m == "/"
418 else toString modulesPath + "/" + m
420 else if isConvertibleWithToString m
422 if m?key && m.key != toString m
424 throw "Module `${file}` contains a disabledModules item that is an attribute set that can be converted to a string (${toString m}) but also has a `.key` attribute (${m.key}) with a different value. This makes it ambiguous which module should be disabled."
433 then throw "Module `${file}` contains a disabledModules item that is an attribute set, presumably a module, that does not have a `key` attribute. This means that the module system doesn't have any means to identify the module that should be disabled. Make sure that you've put the correct value in disabledModules: a string path relative to modulesPath, a path value, or an attribute set with a `key` attribute."
434 else throw "Each disabledModules item must be a path, string, or a attribute set with a key attribute, or a value supported by toString. However, one of the disabledModules items in `${toString file}` is none of that, but is of type ${builtins.typeOf m}.";
436 disabledKeys = concatMap ({ file, disabled }: map (moduleKey file) disabled) disabled;
437 keyFilter = filter (attrs: ! elem attrs.key disabledKeys);
438 in map (attrs: attrs.module) (builtins.genericClosure {
439 startSet = keyFilter modules;
440 operator = attrs: keyFilter attrs.modules;
443 in modulesPath: initialModules: args:
444 filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args);
446 /* Wrap a module with a default location for reporting errors. */
447 setDefaultModuleLocation = file: m:
448 { _file = file; imports = [ m ]; };
450 /* Massage a module into canonical form, that is, a set consisting
451 of ‘options’, ‘config’ and ‘imports’ attributes. */
452 unifyModuleSyntax = file: key: m:
454 addMeta = config: if m ? meta
455 then mkMerge [ config { meta = m.meta; } ]
457 addFreeformType = config: if m ? freeformType
458 then mkMerge [ config { _module.freeformType = m.freeformType; } ]
461 if m ? config || m ? options then
462 let badAttrs = removeAttrs m ["_class" "_file" "key" "disabledModules" "imports" "options" "config" "meta" "freeformType"]; in
463 if badAttrs != {} then
464 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."
466 { _file = toString m._file or file;
467 _class = m._class or null;
468 key = toString m.key or key;
469 disabledModules = m.disabledModules or [];
470 imports = m.imports or [];
471 options = m.options or {};
472 config = addFreeformType (addMeta (m.config or {}));
476 lib.throwIfNot (isAttrs m) "module ${file} (${key}) does not look like a module."
477 { _file = toString m._file or file;
478 _class = m._class or null;
479 key = toString m.key or key;
480 disabledModules = m.disabledModules or [];
481 imports = m.require or [] ++ m.imports or [];
483 config = addFreeformType (removeAttrs m ["_class" "_file" "key" "disabledModules" "require" "imports" "freeformType"]);
486 applyModuleArgsIfFunction = key: f: args@{ config, options, lib, ... }:
487 if isFunction f then applyModuleArgs key f args else f;
489 applyModuleArgs = key: f: args@{ config, options, lib, ... }:
491 # Module arguments are resolved in a strict manner when attribute set
492 # deconstruction is used. As the arguments are now defined with the
493 # config._module.args option, the strictness used on the attribute
494 # set argument would cause an infinite loop, if the result of the
495 # option is given as argument.
497 # To work-around the strictness issue on the deconstruction of the
498 # attributes set argument, we create a new attribute set which is
499 # constructed to satisfy the expected set of attributes. Thus calling
500 # a module will resolve strictly the attributes used as argument but
501 # not their values. The values are forwarding the result of the
502 # evaluation of the option.
503 context = name: ''while evaluating the module argument `${name}' in "${key}":'';
504 extraArgs = builtins.mapAttrs (name: _:
505 builtins.addErrorContext (context name)
506 (args.${name} or config._module.args.${name})
507 ) (lib.functionArgs f);
509 # Note: we append in the opposite order such that we can add an error
510 # context on the explicit arguments of "args" too. This update
511 # operator is used to make the "args@{ ... }: with args.lib;" notation
513 in f (args // extraArgs);
515 /* Merge a list of modules. This will recurse over the option
516 declarations in all modules, combining them into a single set.
517 At the same time, for each option declaration, it will merge the
518 corresponding option definitions in all machines, returning them
519 in the ‘value’ attribute of each option.
521 This returns a set like
523 # A recursive set of options along with their final values
525 foo = { _type = "option"; value = "option value of foo"; ... };
526 bar.baz = { _type = "option"; value = "option value of bar.baz"; ... };
529 # A list of definitions that weren't matched by any option
531 { file = "file.nix"; prefix = [ "qux" ]; value = "qux"; }
536 mergeModules = prefix: modules:
537 mergeModules' prefix modules
538 (concatMap (m: map (config: { file = m._file; inherit config; }) (pushDownProperties m.config)) modules);
540 mergeModules' = prefix: modules: configs:
542 # an attrset 'name' => list of submodules that declare ‘name’.
547 (module: let subtree = module.options; in
548 if !(builtins.isAttrs subtree) then
550 An option declaration for `${builtins.concatStringsSep "." prefix}' has type
551 `${builtins.typeOf subtree}' rather than an attribute set.
552 Did you mean to define this outside of `options'?
557 [{ inherit (module) _file; pos = builtins.unsafeGetAttrPos n subtree; options = option; }]
563 # The root of any module definition must be an attrset.
568 # TODO: I have my doubts that this error would occur when option definitions are not matched.
569 # The implementation of this check used to be tied to a superficially similar check for
570 # options, so maybe that's why this is here.
571 isAttrs c.config || throw ''
572 In module `${c.file}', you're trying to define a value of type `${builtins.typeOf c.config}'
573 rather than an attribute set for the option
574 `${builtins.concatStringsSep "." prefix}'!
576 This usually happens if `${builtins.concatStringsSep "." prefix}' has option
577 definitions inside that are not matched. Please check how to properly define
578 this option by e.g. referring to `man 5 configuration.nix'!
584 # an attrset 'name' => list of submodules that define ‘name’.
585 pushedDownDefinitionsByName =
592 map (config: { inherit (module) file; inherit config; }) (pushDownProperties value)
597 # extract the definitions for each loc
598 rawDefinitionsByName =
605 [{ inherit (module) file; inherit value; }]
611 # Convert an option tree decl to a submodule option decl
612 optionTreeToOption = decl:
613 if isOption decl.options
617 type = types.submoduleWith {
618 modules = [ { options = decl.options; } ];
619 # `null` is not intended for use by modules. It is an internal
620 # value that means "whatever the user has declared elsewhere".
621 # This might become obsolete with https://github.com/NixOS/nixpkgs/issues/162398
622 shorthandOnlyDefinesConfig = null;
627 resultsByName = mapAttrs (name: decls:
628 # We're descending into attribute ‘name’.
630 loc = prefix ++ [name];
631 defns = pushedDownDefinitionsByName.${name} or [];
632 defns' = rawDefinitionsByName.${name} or [];
635 && (m.options._type == "option"
636 || throwDeclarationTypeError loc m.options._type m._file
641 if length optionDecls == length decls then
642 let opt = fixupOptionType loc (mergeOptionDecls loc decls);
644 matchedOptions = evalOptionValue loc opt defns';
647 else if optionDecls != [] then
648 if all (x: x.options.type.name or null == "submodule") optionDecls
649 # Raw options can only be merged into submodules. Merging into
650 # attrsets might be nice, but ambiguous. Suppose we have
651 # attrset as a `attrsOf submodule`. User declares option
652 # attrset.foo.bar, this could mean:
653 # a. option `bar` is only available in `attrset.foo`
654 # b. option `foo.bar` is available in all `attrset.*`
655 # c. reject and require "<name>" as a reminder that it behaves like (b).
656 # d. magically combine (a) and (c).
657 # All of the above are merely syntax sugar though.
659 let opt = fixupOptionType loc (mergeOptionDecls loc (map optionTreeToOption decls));
661 matchedOptions = evalOptionValue loc opt defns';
666 nonOptions = filter (m: !isOption m.options) decls;
668 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${
669 showRawDecls loc nonOptions
672 mergeModules' loc decls defns) declsByName;
674 matchedOptions = mapAttrs (n: v: v.matchedOptions) resultsByName;
676 # an attrset 'name' => list of unmatched definitions for 'name'
677 unmatchedDefnsByName =
678 # Propagate all unmatched definitions from nested option sets
679 mapAttrs (n: v: v.unmatchedDefns) resultsByName
680 # Plus the definitions for the current prefix that don't have a matching option
681 // removeAttrs rawDefinitionsByName (attrNames matchedOptions);
683 inherit matchedOptions;
685 # Transforms unmatchedDefnsByName into a list of definitions
689 # When no config values exist, there can be no unmatched config, so
690 # we short circuit and avoid evaluating more _options_ than necessary.
693 concatLists (mapAttrsToList (name: defs:
695 # Set this so we know when the definition first left unmatched territory
696 prefix = [name] ++ (def.prefix or []);
698 ) unmatchedDefnsByName);
701 throwDeclarationTypeError = loc: actualTag: file:
703 name = lib.strings.escapeNixIdentifier (lib.lists.last loc);
704 path = showOption loc;
708 "In module ${file}: expected an option declaration at option path `${path}` but got an attribute set with type ${actualTag}"
709 ] ++ optional (actualTag == "option-type") ''
710 When declaring an option, you must wrap the type in a `mkOption` call. It should look somewhat like:
712 ${name} = lib.mkOption {
714 type = <the type you wrote for ${name}>;
719 # Ideally we'd know the exact syntax they used, but short of that,
720 # we can only reliably repeat the last. However, we repeat the
721 # full path in a non-misleading way here, in case they overlook
722 # the start of the message. Examples attract attention.
723 comment = optionalString (depth > 1) "\n # ${showOption loc}";
725 throw (concatStringsSep "\n\n" paragraphs);
727 /* Merge multiple option declarations into a single declaration. In
728 general, there should be only one declaration of each option.
729 The exception is the ‘options’ attribute, which specifies
730 sub-options. These can be specified multiple times to allow one
731 module to add sub-options to an option declared somewhere else
732 (e.g. multiple modules define sub-options for ‘fileSystems’).
734 'loc' is the list of attribute names where the option is located.
736 'opts' is a list of modules. Each module has an options attribute which
737 correspond to the definition of 'loc' in 'opt.file'. */
742 t' = opt.options.type;
743 mergedType = t.typeMerge t'.functor;
744 typesMergeable = mergedType != null;
745 typeSet = if (bothHave "type") && typesMergeable
746 then { type = mergedType; }
748 bothHave = k: opt.options ? ${k} && res ? ${k};
750 if bothHave "default" ||
751 bothHave "example" ||
752 bothHave "description" ||
754 (bothHave "type" && (! typesMergeable))
756 throw "The option `${showOption loc}' in `${opt._file}' is already declared in ${showFiles res.declarations}."
759 getSubModules = opt.options.type.getSubModules or null;
761 if getSubModules != null then map (setDefaultModuleLocation opt._file) getSubModules ++ res.options
763 in opt.options // res //
764 { declarations = res.declarations ++ [opt._file];
765 # In the case of modules that are generated dynamically, we won't
766 # have exact declaration lines; fall back to just the file being
768 declarationPositions = res.declarationPositions
769 ++ (if opt.pos != null
771 else [{ file = opt._file; line = null; column = null; }]);
772 options = submodules;
774 ) { inherit loc; declarations = []; declarationPositions = []; options = []; } opts;
776 /* Merge all the definitions of an option to produce the final
778 evalOptionValue = loc: opt: defs:
780 # Add in the default value for this option, if any.
782 (optional (opt ? default)
783 { file = head opt.declarations; value = mkOptionDefault opt.default; }) ++ defs;
785 # Handle properties, check types, and merge everything together.
787 if opt.readOnly or false && length defs' > 1 then
789 # For a better error message, evaluate all readOnly definitions as
790 # if they were the only definition.
791 separateDefs = map (def: def // {
792 value = (mergeDefinitions loc opt.type [ def ]).mergedValue;
794 in throw "The option `${showOption loc}' is read-only, but it's set multiple times. Definition values:${showDefs separateDefs}"
796 mergeDefinitions loc opt.type defs';
798 # Apply the 'apply' function to the merged value. This allows options to
799 # yield a value computed from the definitions
800 value = if opt ? apply then opt.apply res.mergedValue else res.mergedValue;
803 warnIf (opt.type.deprecationMessage != null)
804 "The type `types.${opt.type.name}' of option `${showOption loc}' defined in ${showFiles opt.declarations} is deprecated. ${opt.type.deprecationMessage}";
806 in warnDeprecation opt //
807 { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
808 inherit (res.defsFinal') highestPrio;
809 definitions = map (def: def.value) res.defsFinal;
810 files = map (def: def.file) res.defsFinal;
811 definitionsWithLocations = res.defsFinal;
812 inherit (res) isDefined;
813 # This allows options to be correctly displayed using `${options.path.to.it}`
814 __toString = _: showOption loc;
817 # Merge definitions of a value of a given type.
818 mergeDefinitions = loc: type: defs: rec {
821 # Process mkMerge and mkIf properties.
822 defs' = concatMap (m:
823 map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))
826 # Process mkOverride properties.
827 defs'' = filterOverrides' defs';
829 # Sort mkOrder properties.
831 # Avoid sorting if we don't have to.
832 if any (def: def.value._type or "" == "order") defs''.values
833 then sortProperties defs''.values
837 inherit (defs'') highestPrio;
839 defsFinal = defsFinal'.values;
841 # Type-check the remaining definitions, and merge them. Or throw if no definitions.
844 if all (def: type.check def.value) defsFinal then type.merge loc defsFinal
845 else let allInvalid = filter (def: ! type.check def.value) defsFinal;
846 in throw "A definition for option `${showOption loc}' is not of type `${type.description}'. Definition values:${showDefs allInvalid}"
848 # (nixos-option detects this specific error message and gives it special
849 # handling. If changed here, please change it there too.)
850 throw "The option `${showOption loc}' is used but not defined.";
852 isDefined = defsFinal != [];
855 if isDefined then { value = mergedValue; }
859 /* Given a config set, expand mkMerge properties, and push down the
860 other properties into the children. The result is a list of
861 config sets that do not have properties at top-level. For
864 mkMerge [ { boot = set1; } (mkIf cond { boot = set2; services = set3; }) ]
868 [ { boot = set1; } { boot = mkIf cond set2; services = mkIf cond set3; } ].
870 This transform is the critical step that allows mkIf conditions
871 to refer to the full configuration without creating an infinite
874 pushDownProperties = cfg:
875 if cfg._type or "" == "merge" then
876 concatMap pushDownProperties cfg.contents
877 else if cfg._type or "" == "if" then
878 map (mapAttrs (n: v: mkIf cfg.condition v)) (pushDownProperties cfg.content)
879 else if cfg._type or "" == "override" then
880 map (mapAttrs (n: v: mkOverride cfg.priority v)) (pushDownProperties cfg.content)
881 else # FIXME: handle mkOrder?
884 /* Given a config value, expand mkMerge properties, and discharge
885 any mkIf conditions. That is, this is the place where mkIf
886 conditions are actually evaluated. The result is a list of
887 config values. For example, ‘mkIf false x’ yields ‘[]’,
888 ‘mkIf true x’ yields ‘[x]’, and
890 mkMerge [ 1 (mkIf true 2) (mkIf true (mkIf false 3)) ]
892 yields ‘[ 1 2 ]’.
894 dischargeProperties = def:
895 if def._type or "" == "merge" then
896 concatMap dischargeProperties def.contents
897 else if def._type or "" == "if" then
898 if isBool def.condition then
899 if def.condition then
900 dischargeProperties def.content
904 throw "‘mkIf’ called with a non-Boolean condition"
908 /* Given a list of config values, process the mkOverride properties,
909 that is, return the values that have the highest (that is,
910 numerically lowest) priority, and strip the mkOverride
911 properties. For example,
913 [ { file = "/1"; value = mkOverride 10 "a"; }
914 { file = "/2"; value = mkOverride 20 "b"; }
915 { file = "/3"; value = "z"; }
916 { file = "/4"; value = mkOverride 10 "d"; }
921 [ { file = "/1"; value = "a"; }
922 { file = "/4"; value = "d"; }
925 Note that "z" has the default priority 100.
927 filterOverrides = defs: (filterOverrides' defs).values;
929 filterOverrides' = defs:
931 getPrio = def: if def.value._type or "" == "override" then def.value.priority else defaultOverridePriority;
932 highestPrio = foldl' (prio: def: min (getPrio def) prio) 9999 defs;
933 strip = def: if def.value._type or "" == "override" then def // { value = def.value.content; } else def;
935 values = concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs;
939 /* Sort a list of properties. The sort priority of a property is
940 defaultOrderPriority by default, but can be overridden by wrapping the property
942 sortProperties = defs:
945 if def.value._type or "" == "order"
946 then def // { value = def.value.content; inherit (def.value) priority; }
948 defs' = map strip defs;
949 compare = a: b: (a.priority or defaultOrderPriority) < (b.priority or defaultOrderPriority);
950 in sort compare defs';
952 # This calls substSubModules, whose entire purpose is only to ensure that
953 # option declarations in submodules have accurate position information.
954 # TODO: Merge this into mergeOptionDecls
955 fixupOptionType = loc: opt:
956 if opt.type.getSubModules or null == null
957 then opt // { type = opt.type or types.unspecified; }
958 else opt // { type = opt.type.substSubModules opt.options; options = []; };
962 Merge an option's definitions in a way that preserves the priority of the
963 individual attributes in the option value.
965 This does not account for all option semantics, such as readOnly.
968 option -> attrsOf { highestPrio, value }
970 mergeAttrDefinitionsWithPrio = opt:
978 (lib.mapAttrsToList (k: value: { ${k} = def // { inherit value; }; }))
979 (pushDownProperties value)
981 opt.definitionsWithLocations
985 assert opt.type.name == "attrsOf" || opt.type.name == "lazyAttrsOf";
988 let merging = lib.mergeDefinitions (opt.loc ++ [k]) opt.type.nestedTypes.elemType v;
990 value = merging.mergedValue;
991 inherit (merging.defsFinal') highestPrio;
997 mkIf = condition: content:
999 inherit condition content;
1002 mkAssert = assertion: message: content:
1004 (if assertion then true else throw "\nFailed assertion: ${message}")
1012 mkOverride = priority: content:
1013 { _type = "override";
1014 inherit priority content;
1017 mkOptionDefault = mkOverride 1500; # priority of option defaults
1018 mkDefault = mkOverride 1000; # used in config sections of non-user modules to set a default
1019 defaultOverridePriority = 100;
1020 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
1021 mkForce = mkOverride 50;
1022 mkVMOverride = mkOverride 10; # used by ‘nixos-rebuild build-vm’
1024 defaultPriority = lib.warnIf (lib.isInOldestRelease 2305) "lib.modules.defaultPriority is deprecated, please use lib.modules.defaultOverridePriority instead." defaultOverridePriority;
1026 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;
1028 mkOrder = priority: content:
1030 inherit priority content;
1033 mkBefore = mkOrder 500;
1034 defaultOrderPriority = 1000;
1035 mkAfter = mkOrder 1500;
1037 # Convenient property used to transfer all definitions and their
1038 # properties from one option to another. This property is useful for
1039 # renaming options, and also for including properties from another module
1040 # system, including sub-modules.
1042 # { config, options, ... }:
1045 # # 'bar' might not always be defined in the current module-set.
1046 # config.foo.enable = mkAliasDefinitions (options.bar.enable or {});
1048 # # 'barbaz' has to be defined in the current module-set.
1049 # config.foobar.paths = mkAliasDefinitions options.barbaz.paths;
1052 # Note, this is different than taking the value of the option and using it
1053 # as a definition, as the new definition will not keep the mkOverride /
1054 # mkDefault properties of the previous option.
1056 mkAliasDefinitions = mkAliasAndWrapDefinitions id;
1057 mkAliasAndWrapDefinitions = wrap: option:
1058 mkAliasIfDef option (wrap (mkMerge option.definitions));
1060 # Similar to mkAliasAndWrapDefinitions but copies over the priority from the
1063 # If a priority is not set, it assumes a priority of defaultOverridePriority.
1064 mkAliasAndWrapDefsWithPriority = wrap: option:
1066 prio = option.highestPrio or defaultOverridePriority;
1067 defsWithPrio = map (mkOverride prio) option.definitions;
1068 in mkAliasIfDef option (wrap (mkMerge defsWithPrio));
1070 mkAliasIfDef = option:
1071 mkIf (isOption option && option.isDefined);
1073 /* Compatibility. */
1074 fixMergeModules = modules: args: evalModules { inherit modules args; check = false; };
1077 /* Return a module that causes a warning to be shown if the
1078 specified option is defined. For example,
1080 mkRemovedOptionModule [ "boot" "loader" "grub" "bootDevice" ] "<replacement instructions>"
1082 causes a assertion if the user defines boot.loader.grub.bootDevice.
1084 replacementInstructions is a string that provides instructions on
1085 how to achieve the same functionality without the removed option,
1086 or alternatively a reasoning why the functionality is not needed.
1087 replacementInstructions SHOULD be provided!
1089 mkRemovedOptionModule = optionName: replacementInstructions:
1091 { options = setAttrByPath optionName (mkOption {
1093 apply = x: throw "The option `${showOption optionName}' can no longer be used since it's been removed. ${replacementInstructions}";
1096 let opt = getAttrFromPath optionName options; in [{
1097 assertion = !opt.isDefined;
1099 The option definition `${showOption optionName}' in ${showFiles opt.files} no longer has any effect; please remove it.
1100 ${replacementInstructions}
1105 /* Return a module that causes a warning to be shown if the
1106 specified "from" option is defined; the defined value is however
1107 forwarded to the "to" option. This can be used to rename options
1108 while providing backward compatibility. For example,
1110 mkRenamedOptionModule [ "boot" "copyKernels" ] [ "boot" "loader" "grub" "copyKernels" ]
1112 forwards any definitions of boot.copyKernels to
1113 boot.loader.grub.copyKernels while printing a warning.
1115 This also copies over the priority from the aliased option to the
1118 mkRenamedOptionModule = from: to: doRename {
1122 use = builtins.trace "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
1125 mkRenamedOptionModuleWith = {
1126 /* Old option path as list of strings. */
1128 /* New option path as list of strings. */
1132 Release number of the first release that contains the rename, ignoring backports.
1133 Set it to the upcoming release, matching the nixpkgs/.version file.
1140 warn = lib.isInOldestRelease sinceRelease;
1141 use = lib.warnIf (lib.isInOldestRelease sinceRelease)
1142 "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
1145 /* Return a module that causes a warning to be shown if any of the "from"
1146 option is defined; the defined values can be used in the "mergeFn" to set
1148 This function can be used to merge multiple options into one that has a
1151 "mergeFn" takes the module "config" as a parameter and must return a value
1152 of "to" option type.
1154 mkMergedOptionModule
1159 let value = p: getAttrFromPath p config;
1161 if (value [ "a" "b" "c" ]) == true then "foo"
1162 else if (value [ "d" "e" "f" ]) == true then "bar"
1165 - options.a.b.c is a removed boolean option
1166 - options.d.e.f is a removed boolean option
1167 - options.x.y.z is a new str option that combines a.b.c and d.e.f
1170 This show a warning if any a.b.c or d.e.f is set, and set the value of
1171 x.y.z to the result of the merge function
1173 mkMergedOptionModule = from: to: mergeFn:
1174 { config, options, ... }:
1176 options = foldl' recursiveUpdate {} (map (path: setAttrByPath path (mkOption {
1178 # To use the value in mergeFn without triggering errors
1179 default = "_mkMergedOptionModule";
1183 warnings = filter (x: x != "") (map (f:
1184 let val = getAttrFromPath f config;
1185 opt = getAttrFromPath f options;
1188 (val != "_mkMergedOptionModule")
1189 "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."
1191 } // setAttrByPath to (mkMerge
1193 (any (f: (getAttrFromPath f config) != "_mkMergedOptionModule") from)
1197 /* Single "from" version of mkMergedOptionModule.
1198 Return a module that causes a warning to be shown if the "from" option is
1199 defined; the defined value can be used in the "mergeFn" to set the "to"
1201 This function can be used to change an option into another that has a
1204 "mergeFn" takes the module "config" as a parameter and must return a value of
1207 mkChangedOptionModule [ "a" "b" "c" ] [ "x" "y" "z" ]
1209 let value = getAttrFromPath [ "a" "b" "c" ] config;
1211 if value > 100 then "high"
1214 - options.a.b.c is a removed int option
1215 - options.x.y.z is a new str option that supersedes a.b.c
1217 This show a warning if a.b.c is set, and set the value of x.y.z to the
1218 result of the change function
1220 mkChangedOptionModule = from: to: changeFn:
1221 mkMergedOptionModule [ from ] to changeFn;
1223 /* Like ‘mkRenamedOptionModule’, but doesn't show a warning. */
1224 mkAliasOptionModule = from: to: doRename {
1231 /* Transitional version of mkAliasOptionModule that uses MD docs.
1233 This function is no longer necessary and merely an alias of `mkAliasOptionModule`.
1235 mkAliasOptionModuleMD = mkAliasOptionModule;
1237 /* mkDerivedConfig : Option a -> (a -> Definition b) -> Definition b
1239 Create config definitions with the same priority as the definition of another option.
1240 This should be used for option definitions where one option sets the value of another as a convenience.
1241 For instance a config file could be set with a `text` or `source` option, where text translates to a `source`
1242 value using `mkDerivedConfig options.text (pkgs.writeText "filename.conf")`.
1244 It takes care of setting the right priority using `mkOverride`.
1246 # TODO: make the module system error message include information about `opt` in
1247 # error messages about conflicts. E.g. introduce a variation of `mkOverride` which
1248 # adds extra location context to the definition object. This will allow context to be added
1249 # to all messages that report option locations "this value was derived from <full option name>
1250 # which was defined in <locations>". It can provide a trace of options that contributed
1252 mkDerivedConfig = opt: f:
1254 (opt.highestPrio or defaultOverridePriority)
1257 doRename = { from, to, visible, warn, use, withPriority ? true }:
1258 { config, options, ... }:
1260 fromOpt = getAttrFromPath from options;
1261 toOf = attrByPath to
1262 (abort "Renaming error: option `${showOption to}' does not exist.");
1263 toType = let opt = attrByPath to {} options; in opt.type or (types.submodule {});
1266 options = setAttrByPath from (mkOption {
1268 description = "Alias of {option}`${showOption to}`.";
1269 apply = x: use (toOf config);
1270 } // optionalAttrs (toType != null) {
1274 (optionalAttrs (options ? warnings) {
1275 warnings = optional (warn && fromOpt.isDefined)
1276 "The option `${showOption from}' defined in ${showFiles fromOpt.files} has been renamed to `${showOption to}'.";
1279 then mkAliasAndWrapDefsWithPriority (setAttrByPath to) fromOpt
1280 else mkAliasAndWrapDefinitions (setAttrByPath to) fromOpt)
1284 /* Use this function to import a JSON file as NixOS configuration.
1286 modules.importJSON :: path -> attrs
1288 importJSON = file: {
1290 config = lib.importJSON file;
1293 /* Use this function to import a TOML file as NixOS configuration.
1295 modules.importTOML :: path -> attrs
1297 importTOML = file: {
1299 config = lib.importTOML file;
1302 private = lib.mapAttrs
1303 (k: lib.warn "External use of `lib.modules.${k}` is deprecated. If your use case isn't covered by non-deprecated functions, we'd like to know more and perhaps support your use case well, instead of providing access to these low level functions. In this case please open an issue in https://github.com/nixos/nixpkgs/issues/.")
1306 applyModuleArgsIfFunction
1314 collectModules = collectModules null;
1320 # NOTE: not all of these functions are necessarily public interfaces; some
1321 # are just needed by types.nix, but are not meant to be consumed
1324 defaultOrderPriority
1325 defaultOverridePriority
1332 fixupOptionType # should be private?
1336 mergeAttrDefinitionsWithPrio
1337 mergeOptionDecls # should be private?
1339 mkAliasAndWrapDefinitions
1340 mkAliasAndWrapDefsWithPriority
1344 mkAliasOptionModuleMD
1347 mkChangedOptionModule
1353 mkImageMediaOverride
1355 mkMergedOptionModule
1359 mkRemovedOptionModule
1360 mkRenamedOptionModule
1361 mkRenamedOptionModuleWith
1363 setDefaultModuleLocation