26 oldestSupportedReleaseIsAtLeast
61 isConvertibleWithToString
64 showDeclPrefix = loc: decl: prefix:
65 " - option(s) with prefix `${showOption (loc ++ [prefix])}' in module `${decl._file}'";
66 showRawDecls = loc: decls:
71 (showDeclPrefix loc decl)
72 (attrNames decl.options)
77 /* See https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules
78 or file://./../doc/module-system/module-system.chapter.md
80 !!! Please think twice before adding to this argument list! The more
81 that is specified here instead of in the modules themselves the harder
82 it is to transparently move a set of modules to be a submodule of another
83 config (as the proper arguments need to be replicated at each call to
84 evalModules) and the less declarative the module set is. */
85 evalModules = evalModulesArgs@
88 , # This should only be used for special arguments that need to be evaluated
89 # when resolving module structure (like in imports). For everything else,
90 # there's _module.args. If specialArgs.modulesPath is defined it will be
91 # used as the base path for disabledModules.
94 # A nominal type for modules. When set and non-null, this adds a check to
95 # make sure that only compatible modules are imported.
97 , # This would be remove in the future, Prefer _module.args option instead.
99 , # This would be remove in the future, Prefer _module.check option instead.
104 warnIf (evalModulesArgs?args) "The args argument to evalModules is deprecated. Please set config._module.args instead."
105 warnIf (evalModulesArgs?check) "The check argument to evalModules is deprecated. Please set config._module.check instead."
109 optional (evalModulesArgs?args) {
114 ++ optional (evalModulesArgs?check) {
116 _module.check = mkDefault check;
119 regularModules = modules ++ legacyModules;
121 # This internal module declare internal options under the `_module'
122 # attribute. These options are fragile, as they are used by the
123 # module system to change the interpretation of modules.
125 # When extended with extendModules or moduleType, a fresh instance of
126 # this module is used, to avoid conflicts and allow chaining of
128 internalModule = rec {
129 _file = "lib/modules.nix";
134 _module.args = mkOption {
135 # Because things like `mkIf` are entirely useless for
136 # `_module.args` (because there's no way modules can check which
137 # arguments were passed), we'll use `lazyAttrsOf` which drops
138 # support for that, in turn it's lazy in its values. This means e.g.
139 # a `_module.args.pkgs = import (fetchTarball { ... }) {}` won't
140 # start a download when `pkgs` wasn't evaluated.
141 type = types.lazyAttrsOf types.raw;
142 # Only render documentation once at the root of the option tree,
143 # not for all individual submodules.
144 # Allow merging option decls to make this internal regardless.
146 then null # unset => visible
147 else "internal"} = true;
148 # TODO: Change the type of this option to a submodule with a
149 # freeformType, so that individual arguments can be documented
152 Additional arguments passed to each module in addition to ones
153 like `lib`, `config`,
154 and `pkgs`, `modulesPath`.
156 This option is also available to all submodules. Submodules do not
157 inherit args from their parent module, nor do they provide args to
158 their parent module or sibling submodules. The sole exception to
159 this is the argument `name` which is provided by
160 parent modules to a submodule and contains the attribute name
161 the submodule is bound to, or a unique generated name if it is
162 not bound to an attribute.
164 Some arguments are already passed by default, of which the
165 following *cannot* be changed with this option:
166 - {var}`lib`: The nixpkgs library.
167 - {var}`config`: The results of all options after merging the values from all modules together.
168 - {var}`options`: The options declared in all modules.
169 - {var}`specialArgs`: The `specialArgs` argument passed to `evalModules`.
170 - All attributes of {var}`specialArgs`
172 Whereas option values can generally depend on other option values
173 thanks to laziness, this does not apply to `imports`, which
174 must be computed statically before anything else.
176 For this reason, callers of the module system can provide `specialArgs`
177 which are available during import resolution.
179 For NixOS, `specialArgs` includes
180 {var}`modulesPath`, which allows you to import
181 extra modules from the nixpkgs package tree without having to
182 somehow make the module aware of the location of the
183 `nixpkgs` or NixOS directories.
185 { modulesPath, ... }: {
187 (modulesPath + "/profiles/minimal.nix")
192 For NixOS, the default value for this option includes at least this argument:
193 - {var}`pkgs`: The nixpkgs package set according to
194 the {option}`nixpkgs.pkgs` option.
198 _module.check = mkOption {
202 description = "Whether to check whether all option definitions have matching declarations.";
205 _module.freeformType = mkOption {
206 type = types.nullOr types.optionType;
210 If set, merge all definitions that don't have an associated option
211 together using this type. The result then gets combined with the
212 values of all declared options to produce the final `
215 If this is `null`, definitions without an option
216 will throw an error unless {option}`_module.check` is
221 _module.specialArgs = mkOption {
225 Externally provided module arguments that can't be modified from
226 within a configuration, but can be used in module imports.
233 inherit extendModules;
236 _module.specialArgs = specialArgs;
241 let collected = collectModules
243 (specialArgs.modulesPath or "")
244 (regularModules ++ [ internalModule ])
245 ({ inherit lib options config specialArgs; } // specialArgs);
246 in mergeModules prefix (reverseList collected);
248 options = merged.matchedOptions;
253 # For definitions that have an associated option
254 declaredConfig = mapAttrsRecursiveCond (v: ! isOption v) (_: v: v.value) options;
256 # If freeformType is set, this is for definitions that don't have an associated option
261 value = setAttrByPath def.prefix def.value;
262 }) merged.unmatchedDefns;
263 in if defs == [] then {}
264 else declaredConfig._module.freeformType.merge prefix defs;
266 in if declaredConfig._module.freeformType == null then declaredConfig
267 # Because all definitions that had an associated option ended in
268 # declaredConfig, freeformConfig can only contain the non-option
269 # paths, meaning recursiveUpdate will never override any value
270 else recursiveUpdate freeformConfig declaredConfig;
273 if config._module.check && config._module.freeformType == null && merged.unmatchedDefns != [] then
275 firstDef = head merged.unmatchedDefns;
278 optText = showOption (prefix ++ firstDef.prefix);
281 "while evaluating the error message for definitions for `${optText}', which is an option that does not exist"
283 "while evaluating a definition from `${firstDef.file}'"
284 ( showDefs [ firstDef ])
287 "The option `${optText}' does not exist. Definition values:${defText}";
289 if attrNames options == [ "_module" ]
290 # No options were declared at all (`_module` is built in)
291 # but we do have unmatched definitions, and no freeformType (earlier conditions)
294 optionName = showOption prefix;
300 It seems as if you're trying to declare an option by placing it into `config' rather than `options'!
306 However there are no options defined in `${showOption prefix}'. Are you sure you've
307 declared your options properly? This can happen if you e.g. declared your options in `types.submodule'
308 under `config' rather than `options'.
313 checked = seq checkUnmatched;
315 extendModules = extendArgs@{
320 evalModules (evalModulesArgs // {
322 modules = regularModules ++ modules;
323 specialArgs = evalModulesArgs.specialArgs or {} // specialArgs;
324 prefix = extendArgs.prefix or evalModulesArgs.prefix or [];
327 type = types.submoduleWith {
328 inherit modules specialArgs class;
331 result = withWarnings {
332 _type = "configuration";
333 options = checked options;
334 config = checked (removeAttrs config [ "_module" ]);
335 _module = checked (config._module);
336 inherit extendModules type;
341 # collectModules :: (class: String) -> (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]
343 # Collects all modules recursively through `import` statements, filtering out
344 # all modules in disabledModules.
345 collectModules = class: let
347 # Like unifyModuleSyntax, but also imports paths and calls functions if necessary
348 loadModule = args: fallbackFile: fallbackKey: m:
350 unifyModuleSyntax fallbackFile fallbackKey (applyModuleArgs fallbackKey m args)
351 else if isAttrs m then
352 if m._type or "module" == "module" then
353 unifyModuleSyntax fallbackFile fallbackKey m
354 else if m._type == "if" || m._type == "override" then
355 loadModule args fallbackFile fallbackKey { config = m; }
357 throw (messages.not_a_module { inherit fallbackFile; value = m; _type = m._type; expectedClass = class; })
358 else if isList m then
359 let defs = [{ file = fallbackFile; value = m; }]; in
360 throw "Module imports can't be nested lists. Perhaps you meant to remove one level of lists? Definitions: ${showDefs defs}"
361 else unifyModuleSyntax (toString m) (toString m) (applyModuleArgsIfFunction (toString m) (import m) args);
367 if m._class != null -> m._class == class
370 throw "The module ${m._file or m.key} was imported into ${class} instead of ${m._class}."
375 Collects all modules recursively into the form
378 disabled = [ <list of disabled modules> ];
379 # All modules of the main module list
383 module = <module for key1>;
384 # All modules imported by the module for key1
388 module = <module for key1-1>;
389 # All modules imported by the module for key1-1
399 collectStructuredModules =
401 collectResults = modules: {
402 disabled = concatLists (catAttrs "disabled" modules);
405 in parentFile: parentKey: initialModules: args: collectResults (imap1 (n: x:
407 module = checkModule (loadModule args parentFile "${parentKey}:anon-${toString n}" x);
408 collectedImports = collectStructuredModules module._file module.key module.imports args;
412 modules = collectedImports.modules;
413 disabled = (if module.disabledModules != [] then [{ file = module._file; disabled = module.disabledModules; }] else []) ++ collectedImports.disabled;
416 # filterModules :: String -> { disabled, modules } -> [ Module ]
418 # Filters a structure as emitted by collectStructuredModules by removing all disabled
419 # modules recursively. It returns the final list of unique-by-key modules
420 filterModules = modulesPath: { disabled, modules }:
425 if substring 0 1 m == "/"
427 else toString modulesPath + "/" + m
429 else if isConvertibleWithToString m
431 if m?key && m.key != toString m
433 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."
442 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."
443 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 ${typeOf m}.";
445 disabledKeys = concatMap ({ file, disabled }: map (moduleKey file) disabled) disabled;
446 keyFilter = filter (attrs: ! elem attrs.key disabledKeys);
447 in map (attrs: attrs.module) (genericClosure {
448 startSet = keyFilter modules;
449 operator = attrs: keyFilter attrs.modules;
452 in modulesPath: initialModules: args:
453 filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args);
455 /* Wrap a module with a default location for reporting errors. */
456 setDefaultModuleLocation = file: m:
457 { _file = file; imports = [ m ]; };
459 /* Massage a module into canonical form, that is, a set consisting
460 of ‘options’, ‘config’ and ‘imports’ attributes. */
461 unifyModuleSyntax = file: key: m:
463 addMeta = config: if m ? meta
464 then mkMerge [ config { meta = m.meta; } ]
466 addFreeformType = config: if m ? freeformType
467 then mkMerge [ config { _module.freeformType = m.freeformType; } ]
470 if m ? config || m ? options then
471 let badAttrs = removeAttrs m ["_class" "_file" "key" "disabledModules" "imports" "options" "config" "meta" "freeformType"]; in
472 if badAttrs != {} then
473 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."
475 { _file = toString m._file or file;
476 _class = m._class or null;
477 key = toString m.key or key;
478 disabledModules = m.disabledModules or [];
479 imports = m.imports or [];
480 options = m.options or {};
481 config = addFreeformType (addMeta (m.config or {}));
485 throwIfNot (isAttrs m) "module ${file} (${key}) does not look like a module."
486 { _file = toString m._file or file;
487 _class = m._class or null;
488 key = toString m.key or key;
489 disabledModules = m.disabledModules or [];
490 imports = m.require or [] ++ m.imports or [];
492 config = addFreeformType (removeAttrs m ["_class" "_file" "key" "disabledModules" "require" "imports" "freeformType"]);
495 applyModuleArgsIfFunction = key: f: args@{ config, ... }:
496 if isFunction f then applyModuleArgs key f args else f;
498 applyModuleArgs = key: f: args@{ config, ... }:
500 # Module arguments are resolved in a strict manner when attribute set
501 # deconstruction is used. As the arguments are now defined with the
502 # config._module.args option, the strictness used on the attribute
503 # set argument would cause an infinite loop, if the result of the
504 # option is given as argument.
506 # To work-around the strictness issue on the deconstruction of the
507 # attributes set argument, we create a new attribute set which is
508 # constructed to satisfy the expected set of attributes. Thus calling
509 # a module will resolve strictly the attributes used as argument but
510 # not their values. The values are forwarding the result of the
511 # evaluation of the option.
512 context = name: ''while evaluating the module argument `${name}' in "${key}":'';
513 extraArgs = mapAttrs (name: _:
514 addErrorContext (context name)
515 (args.${name} or config._module.args.${name})
518 # Note: we append in the opposite order such that we can add an error
519 # context on the explicit arguments of "args" too. This update
520 # operator is used to make the "args@{ ... }: with args.lib;" notation
522 in f (args // extraArgs);
524 /* Merge a list of modules. This will recurse over the option
525 declarations in all modules, combining them into a single set.
526 At the same time, for each option declaration, it will merge the
527 corresponding option definitions in all machines, returning them
528 in the ‘value’ attribute of each option.
530 This returns a set like
532 # A recursive set of options along with their final values
534 foo = { _type = "option"; value = "option value of foo"; ... };
535 bar.baz = { _type = "option"; value = "option value of bar.baz"; ... };
538 # A list of definitions that weren't matched by any option
540 { file = "file.nix"; prefix = [ "qux" ]; value = "qux"; }
545 mergeModules = prefix: modules:
546 mergeModules' prefix modules
547 (concatMap (m: map (config: { file = m._file; inherit config; }) (pushDownProperties m.config)) modules);
549 mergeModules' = prefix: modules: configs:
551 # an attrset 'name' => list of submodules that declare ‘name’.
556 (module: let subtree = module.options; in
557 if !(isAttrs subtree) then
559 An option declaration for `${concatStringsSep "." prefix}' has type
560 `${typeOf subtree}' rather than an attribute set.
561 Did you mean to define this outside of `options'?
566 [{ inherit (module) _file; pos = unsafeGetAttrPos n subtree; options = option; }]
572 # The root of any module definition must be an attrset.
577 # TODO: I have my doubts that this error would occur when option definitions are not matched.
578 # The implementation of this check used to be tied to a superficially similar check for
579 # options, so maybe that's why this is here.
580 isAttrs c.config || throw ''
581 In module `${c.file}', you're trying to define a value of type `${typeOf c.config}'
582 rather than an attribute set for the option
583 `${concatStringsSep "." prefix}'!
585 This usually happens if `${concatStringsSep "." prefix}' has option
586 definitions inside that are not matched. Please check how to properly define
587 this option by e.g. referring to `man 5 configuration.nix'!
593 # an attrset 'name' => list of submodules that define ‘name’.
594 pushedDownDefinitionsByName =
601 map (config: { inherit (module) file; inherit config; }) (pushDownProperties value)
606 # extract the definitions for each loc
607 rawDefinitionsByName =
614 [{ inherit (module) file; inherit value; }]
620 # Convert an option tree decl to a submodule option decl
621 optionTreeToOption = decl:
622 if isOption decl.options
626 type = types.submoduleWith {
627 modules = [ { options = decl.options; } ];
628 # `null` is not intended for use by modules. It is an internal
629 # value that means "whatever the user has declared elsewhere".
630 # This might become obsolete with https://github.com/NixOS/nixpkgs/issues/162398
631 shorthandOnlyDefinesConfig = null;
636 resultsByName = mapAttrs (name: decls:
637 # We're descending into attribute ‘name’.
639 loc = prefix ++ [name];
640 defns = pushedDownDefinitionsByName.${name} or [];
641 defns' = rawDefinitionsByName.${name} or [];
644 && (m.options._type == "option"
645 || throwDeclarationTypeError loc m.options._type m._file
650 if length optionDecls == length decls then
651 let opt = fixupOptionType loc (mergeOptionDecls loc decls);
653 matchedOptions = evalOptionValue loc opt defns';
656 else if optionDecls != [] then
657 if all (x: x.options.type.name or null == "submodule") optionDecls
658 # Raw options can only be merged into submodules. Merging into
659 # attrsets might be nice, but ambiguous. Suppose we have
660 # attrset as a `attrsOf submodule`. User declares option
661 # attrset.foo.bar, this could mean:
662 # a. option `bar` is only available in `attrset.foo`
663 # b. option `foo.bar` is available in all `attrset.*`
664 # c. reject and require "<name>" as a reminder that it behaves like (b).
665 # d. magically combine (a) and (c).
666 # All of the above are merely syntax sugar though.
668 let opt = fixupOptionType loc (mergeOptionDecls loc (map optionTreeToOption decls));
670 matchedOptions = evalOptionValue loc opt defns';
675 nonOptions = filter (m: !isOption m.options) decls;
677 throw "The option `${showOption loc}' in module `${(head optionDecls)._file}' would be a parent of the following options, but its type `${(head optionDecls).options.type.description or "<no description>"}' does not support nested options.\n${
678 showRawDecls loc nonOptions
681 mergeModules' loc decls defns) declsByName;
683 matchedOptions = mapAttrs (n: v: v.matchedOptions) resultsByName;
685 # an attrset 'name' => list of unmatched definitions for 'name'
686 unmatchedDefnsByName =
687 # Propagate all unmatched definitions from nested option sets
688 mapAttrs (n: v: v.unmatchedDefns) resultsByName
689 # Plus the definitions for the current prefix that don't have a matching option
690 // removeAttrs rawDefinitionsByName (attrNames matchedOptions);
692 inherit matchedOptions;
694 # Transforms unmatchedDefnsByName into a list of definitions
698 # When no config values exist, there can be no unmatched config, so
699 # we short circuit and avoid evaluating more _options_ than necessary.
702 concatLists (mapAttrsToList (name: defs:
704 # Set this so we know when the definition first left unmatched territory
705 prefix = [name] ++ (def.prefix or []);
707 ) unmatchedDefnsByName);
710 throwDeclarationTypeError = loc: actualTag: file:
712 name = lib.strings.escapeNixIdentifier (lib.lists.last loc);
713 path = showOption loc;
717 "In module ${file}: expected an option declaration at option path `${path}` but got an attribute set with type ${actualTag}"
718 ] ++ optional (actualTag == "option-type") ''
719 When declaring an option, you must wrap the type in a `mkOption` call. It should look somewhat like:
721 ${name} = lib.mkOption {
723 type = <the type you wrote for ${name}>;
728 # Ideally we'd know the exact syntax they used, but short of that,
729 # we can only reliably repeat the last. However, we repeat the
730 # full path in a non-misleading way here, in case they overlook
731 # the start of the message. Examples attract attention.
732 comment = optionalString (depth > 1) "\n # ${showOption loc}";
734 throw (concatStringsSep "\n\n" paragraphs);
736 /* Merge multiple option declarations into a single declaration. In
737 general, there should be only one declaration of each option.
738 The exception is the ‘options’ attribute, which specifies
739 sub-options. These can be specified multiple times to allow one
740 module to add sub-options to an option declared somewhere else
741 (e.g. multiple modules define sub-options for ‘fileSystems’).
743 'loc' is the list of attribute names where the option is located.
745 'opts' is a list of modules. Each module has an options attribute which
746 correspond to the definition of 'loc' in 'opt.file'. */
751 t' = opt.options.type;
752 mergedType = t.typeMerge t'.functor;
753 typesMergeable = mergedType != null;
754 typeSet = if (bothHave "type") && typesMergeable
755 then { type = mergedType; }
757 bothHave = k: opt.options ? ${k} && res ? ${k};
759 if bothHave "default" ||
760 bothHave "example" ||
761 bothHave "description" ||
763 (bothHave "type" && (! typesMergeable))
765 throw "The option `${showOption loc}' in `${opt._file}' is already declared in ${showFiles res.declarations}."
768 getSubModules = opt.options.type.getSubModules or null;
770 if getSubModules != null then map (setDefaultModuleLocation opt._file) getSubModules ++ res.options
772 in opt.options // res //
773 { declarations = res.declarations ++ [opt._file];
774 # In the case of modules that are generated dynamically, we won't
775 # have exact declaration lines; fall back to just the file being
777 declarationPositions = res.declarationPositions
778 ++ (if opt.pos != null
780 else [{ file = opt._file; line = null; column = null; }]);
781 options = submodules;
783 ) { inherit loc; declarations = []; declarationPositions = []; options = []; } opts;
785 /* Merge all the definitions of an option to produce the final
787 evalOptionValue = loc: opt: defs:
789 # Add in the default value for this option, if any.
791 (optional (opt ? default)
792 { file = head opt.declarations; value = mkOptionDefault opt.default; }) ++ defs;
794 # Handle properties, check types, and merge everything together.
796 if opt.readOnly or false && length defs' > 1 then
798 # For a better error message, evaluate all readOnly definitions as
799 # if they were the only definition.
800 separateDefs = map (def: def // {
801 value = (mergeDefinitions loc opt.type [ def ]).mergedValue;
803 in throw "The option `${showOption loc}' is read-only, but it's set multiple times. Definition values:${showDefs separateDefs}"
805 mergeDefinitions loc opt.type defs';
807 # Apply the 'apply' function to the merged value. This allows options to
808 # yield a value computed from the definitions
809 value = if opt ? apply then opt.apply res.mergedValue else res.mergedValue;
812 warnIf (opt.type.deprecationMessage != null)
813 "The type `types.${opt.type.name}' of option `${showOption loc}' defined in ${showFiles opt.declarations} is deprecated. ${opt.type.deprecationMessage}";
815 in warnDeprecation opt //
816 { value = addErrorContext "while evaluating the option `${showOption loc}':" value;
817 inherit (res.defsFinal') highestPrio;
818 definitions = map (def: def.value) res.defsFinal;
819 files = map (def: def.file) res.defsFinal;
820 definitionsWithLocations = res.defsFinal;
821 inherit (res) isDefined;
822 # This allows options to be correctly displayed using `${options.path.to.it}`
823 __toString = _: showOption loc;
826 # Merge definitions of a value of a given type.
827 mergeDefinitions = loc: type: defs: rec {
830 # Process mkMerge and mkIf properties.
831 defs' = concatMap (m:
832 map (value: { inherit (m) file; inherit value; }) (addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))
835 # Process mkOverride properties.
836 defs'' = filterOverrides' defs';
838 # Sort mkOrder properties.
840 # Avoid sorting if we don't have to.
841 if any (def: def.value._type or "" == "order") defs''.values
842 then sortProperties defs''.values
846 inherit (defs'') highestPrio;
848 defsFinal = defsFinal'.values;
850 # Type-check the remaining definitions, and merge them. Or throw if no definitions.
853 if all (def: type.check def.value) defsFinal then type.merge loc defsFinal
854 else let allInvalid = filter (def: ! type.check def.value) defsFinal;
855 in throw "A definition for option `${showOption loc}' is not of type `${type.description}'. Definition values:${showDefs allInvalid}"
857 # (nixos-option detects this specific error message and gives it special
858 # handling. If changed here, please change it there too.)
859 throw "The option `${showOption loc}' was accessed but has no value defined. Try setting the option.";
861 isDefined = defsFinal != [];
864 if isDefined then { value = mergedValue; }
868 /* Given a config set, expand mkMerge properties, and push down the
869 other properties into the children. The result is a list of
870 config sets that do not have properties at top-level. For
873 mkMerge [ { boot = set1; } (mkIf cond { boot = set2; services = set3; }) ]
877 [ { boot = set1; } { boot = mkIf cond set2; services = mkIf cond set3; } ].
879 This transform is the critical step that allows mkIf conditions
880 to refer to the full configuration without creating an infinite
883 pushDownProperties = cfg:
884 if cfg._type or "" == "merge" then
885 concatMap pushDownProperties cfg.contents
886 else if cfg._type or "" == "if" then
887 map (mapAttrs (n: v: mkIf cfg.condition v)) (pushDownProperties cfg.content)
888 else if cfg._type or "" == "override" then
889 map (mapAttrs (n: v: mkOverride cfg.priority v)) (pushDownProperties cfg.content)
890 else # FIXME: handle mkOrder?
893 /* Given a config value, expand mkMerge properties, and discharge
894 any mkIf conditions. That is, this is the place where mkIf
895 conditions are actually evaluated. The result is a list of
896 config values. For example, ‘mkIf false x’ yields ‘[]’,
897 ‘mkIf true x’ yields ‘[x]’, and
899 mkMerge [ 1 (mkIf true 2) (mkIf true (mkIf false 3)) ]
901 yields ‘[ 1 2 ]’.
903 dischargeProperties = def:
904 if def._type or "" == "merge" then
905 concatMap dischargeProperties def.contents
906 else if def._type or "" == "if" then
907 if isBool def.condition then
908 if def.condition then
909 dischargeProperties def.content
913 throw "‘mkIf’ called with a non-Boolean condition"
917 /* Given a list of config values, process the mkOverride properties,
918 that is, return the values that have the highest (that is,
919 numerically lowest) priority, and strip the mkOverride
920 properties. For example,
922 [ { file = "/1"; value = mkOverride 10 "a"; }
923 { file = "/2"; value = mkOverride 20 "b"; }
924 { file = "/3"; value = "z"; }
925 { file = "/4"; value = mkOverride 10 "d"; }
930 [ { file = "/1"; value = "a"; }
931 { file = "/4"; value = "d"; }
934 Note that "z" has the default priority 100.
936 filterOverrides = defs: (filterOverrides' defs).values;
938 filterOverrides' = defs:
940 getPrio = def: if def.value._type or "" == "override" then def.value.priority else defaultOverridePriority;
941 highestPrio = foldl' (prio: def: min (getPrio def) prio) 9999 defs;
942 strip = def: if def.value._type or "" == "override" then def // { value = def.value.content; } else def;
944 values = concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs;
948 /* Sort a list of properties. The sort priority of a property is
949 defaultOrderPriority by default, but can be overridden by wrapping the property
951 sortProperties = defs:
954 if def.value._type or "" == "order"
955 then def // { value = def.value.content; inherit (def.value) priority; }
957 defs' = map strip defs;
958 compare = a: b: (a.priority or defaultOrderPriority) < (b.priority or defaultOrderPriority);
959 in sort compare defs';
961 # This calls substSubModules, whose entire purpose is only to ensure that
962 # option declarations in submodules have accurate position information.
963 # TODO: Merge this into mergeOptionDecls
964 fixupOptionType = loc: opt:
965 if opt.type.getSubModules or null == null
966 then opt // { type = opt.type or types.unspecified; }
967 else opt // { type = opt.type.substSubModules opt.options; options = []; };
971 Merge an option's definitions in a way that preserves the priority of the
972 individual attributes in the option value.
974 This does not account for all option semantics, such as readOnly.
977 option -> attrsOf { highestPrio, value }
979 mergeAttrDefinitionsWithPrio = opt:
987 (mapAttrsToList (k: value: { ${k} = def // { inherit value; }; }))
988 (pushDownProperties value)
990 opt.definitionsWithLocations
994 assert opt.type.name == "attrsOf" || opt.type.name == "lazyAttrsOf";
997 let merging = mergeDefinitions (opt.loc ++ [k]) opt.type.nestedTypes.elemType v;
999 value = merging.mergedValue;
1000 inherit (merging.defsFinal') highestPrio;
1006 mkIf = condition: content:
1008 inherit condition content;
1011 mkAssert = assertion: message: content:
1013 (if assertion then true else throw "\nFailed assertion: ${message}")
1021 mkOverride = priority: content:
1022 { _type = "override";
1023 inherit priority content;
1026 mkOptionDefault = mkOverride 1500; # priority of option defaults
1027 mkDefault = mkOverride 1000; # used in config sections of non-user modules to set a default
1028 defaultOverridePriority = 100;
1029 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
1030 mkForce = mkOverride 50;
1031 mkVMOverride = mkOverride 10; # used by ‘nixos-rebuild build-vm’
1033 defaultPriority = warnIf (oldestSupportedReleaseIsAtLeast 2305) "lib.modules.defaultPriority is deprecated, please use lib.modules.defaultOverridePriority instead." defaultOverridePriority;
1035 mkFixStrictness = warn "lib.mkFixStrictness has no effect and will be removed. It returns its argument unmodified, so you can just remove any calls." id;
1037 mkOrder = priority: content:
1039 inherit priority content;
1042 mkBefore = mkOrder 500;
1043 defaultOrderPriority = 1000;
1044 mkAfter = mkOrder 1500;
1046 # Convenient property used to transfer all definitions and their
1047 # properties from one option to another. This property is useful for
1048 # renaming options, and also for including properties from another module
1049 # system, including sub-modules.
1051 # { config, options, ... }:
1054 # # 'bar' might not always be defined in the current module-set.
1055 # config.foo.enable = mkAliasDefinitions (options.bar.enable or {});
1057 # # 'barbaz' has to be defined in the current module-set.
1058 # config.foobar.paths = mkAliasDefinitions options.barbaz.paths;
1061 # Note, this is different than taking the value of the option and using it
1062 # as a definition, as the new definition will not keep the mkOverride /
1063 # mkDefault properties of the previous option.
1065 mkAliasDefinitions = mkAliasAndWrapDefinitions id;
1066 mkAliasAndWrapDefinitions = wrap: option:
1067 mkAliasIfDef option (wrap (mkMerge option.definitions));
1069 # Similar to mkAliasAndWrapDefinitions but copies over the priority from the
1072 # If a priority is not set, it assumes a priority of defaultOverridePriority.
1073 mkAliasAndWrapDefsWithPriority = wrap: option:
1075 prio = option.highestPrio or defaultOverridePriority;
1076 defsWithPrio = map (mkOverride prio) option.definitions;
1077 in mkAliasIfDef option (wrap (mkMerge defsWithPrio));
1079 mkAliasIfDef = option:
1080 mkIf (isOption option && option.isDefined);
1082 /* Compatibility. */
1083 fixMergeModules = modules: args: evalModules { inherit modules args; check = false; };
1086 /* Return a module that causes a warning to be shown if the
1087 specified option is defined. For example,
1089 mkRemovedOptionModule [ "boot" "loader" "grub" "bootDevice" ] "<replacement instructions>"
1091 causes a assertion if the user defines boot.loader.grub.bootDevice.
1093 replacementInstructions is a string that provides instructions on
1094 how to achieve the same functionality without the removed option,
1095 or alternatively a reasoning why the functionality is not needed.
1096 replacementInstructions SHOULD be provided!
1098 mkRemovedOptionModule = optionName: replacementInstructions:
1100 { options = setAttrByPath optionName (mkOption {
1102 apply = x: throw "The option `${showOption optionName}' can no longer be used since it's been removed. ${replacementInstructions}";
1105 let opt = getAttrFromPath optionName options; in [{
1106 assertion = !opt.isDefined;
1108 The option definition `${showOption optionName}' in ${showFiles opt.files} no longer has any effect; please remove it.
1109 ${replacementInstructions}
1114 /* Return a module that causes a warning to be shown if the
1115 specified "from" option is defined; the defined value is however
1116 forwarded to the "to" option. This can be used to rename options
1117 while providing backward compatibility. For example,
1119 mkRenamedOptionModule [ "boot" "copyKernels" ] [ "boot" "loader" "grub" "copyKernels" ]
1121 forwards any definitions of boot.copyKernels to
1122 boot.loader.grub.copyKernels while printing a warning.
1124 This also copies over the priority from the aliased option to the
1127 mkRenamedOptionModule = from: to: doRename {
1131 use = trace "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
1134 mkRenamedOptionModuleWith = {
1135 /* Old option path as list of strings. */
1137 /* New option path as list of strings. */
1141 Release number of the first release that contains the rename, ignoring backports.
1142 Set it to the upcoming release, matching the nixpkgs/.version file.
1149 warn = oldestSupportedReleaseIsAtLeast sinceRelease;
1150 use = warnIf (oldestSupportedReleaseIsAtLeast sinceRelease)
1151 "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
1154 /* Return a module that causes a warning to be shown if any of the "from"
1155 option is defined; the defined values can be used in the "mergeFn" to set
1157 This function can be used to merge multiple options into one that has a
1160 "mergeFn" takes the module "config" as a parameter and must return a value
1161 of "to" option type.
1163 mkMergedOptionModule
1168 let value = p: getAttrFromPath p config;
1170 if (value [ "a" "b" "c" ]) == true then "foo"
1171 else if (value [ "d" "e" "f" ]) == true then "bar"
1174 - options.a.b.c is a removed boolean option
1175 - options.d.e.f is a removed boolean option
1176 - options.x.y.z is a new str option that combines a.b.c and d.e.f
1179 This show a warning if any a.b.c or d.e.f is set, and set the value of
1180 x.y.z to the result of the merge function
1182 mkMergedOptionModule = from: to: mergeFn:
1183 { config, options, ... }:
1185 options = foldl' recursiveUpdate {} (map (path: setAttrByPath path (mkOption {
1187 # To use the value in mergeFn without triggering errors
1188 default = "_mkMergedOptionModule";
1192 warnings = filter (x: x != "") (map (f:
1193 let val = getAttrFromPath f config;
1194 opt = getAttrFromPath f options;
1197 (val != "_mkMergedOptionModule")
1198 "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."
1200 } // setAttrByPath to (mkMerge
1202 (any (f: (getAttrFromPath f config) != "_mkMergedOptionModule") from)
1206 /* Single "from" version of mkMergedOptionModule.
1207 Return a module that causes a warning to be shown if the "from" option is
1208 defined; the defined value can be used in the "mergeFn" to set the "to"
1210 This function can be used to change an option into another that has a
1213 "mergeFn" takes the module "config" as a parameter and must return a value of
1216 mkChangedOptionModule [ "a" "b" "c" ] [ "x" "y" "z" ]
1218 let value = getAttrFromPath [ "a" "b" "c" ] config;
1220 if value > 100 then "high"
1223 - options.a.b.c is a removed int option
1224 - options.x.y.z is a new str option that supersedes a.b.c
1226 This show a warning if a.b.c is set, and set the value of x.y.z to the
1227 result of the change function
1229 mkChangedOptionModule = from: to: changeFn:
1230 mkMergedOptionModule [ from ] to changeFn;
1232 /* Like ‘mkRenamedOptionModule’, but doesn't show a warning. */
1233 mkAliasOptionModule = from: to: doRename {
1240 /* Transitional version of mkAliasOptionModule that uses MD docs.
1242 This function is no longer necessary and merely an alias of `mkAliasOptionModule`.
1244 mkAliasOptionModuleMD = mkAliasOptionModule;
1246 /* mkDerivedConfig : Option a -> (a -> Definition b) -> Definition b
1248 Create config definitions with the same priority as the definition of another option.
1249 This should be used for option definitions where one option sets the value of another as a convenience.
1250 For instance a config file could be set with a `text` or `source` option, where text translates to a `source`
1251 value using `mkDerivedConfig options.text (pkgs.writeText "filename.conf")`.
1253 It takes care of setting the right priority using `mkOverride`.
1255 # TODO: make the module system error message include information about `opt` in
1256 # error messages about conflicts. E.g. introduce a variation of `mkOverride` which
1257 # adds extra location context to the definition object. This will allow context to be added
1258 # to all messages that report option locations "this value was derived from <full option name>
1259 # which was defined in <locations>". It can provide a trace of options that contributed
1261 mkDerivedConfig = opt: f:
1263 (opt.highestPrio or defaultOverridePriority)
1267 Return a module that help declares an option that has been renamed.
1268 When a value is defined for the old option, it is forwarded to the `to` option.
1271 # List of strings representing the attribute path of the old option.
1273 # List of strings representing the attribute path of the new option.
1275 # Boolean, whether the old option is to be included in documentation.
1277 # Whether to warn when a value is defined for the old option.
1278 # NOTE: This requires the NixOS assertions module to be imported, so
1279 # - this generally does not work in submodules
1280 # - this may or may not work outside NixOS
1282 # A function that is applied to the option value, to form the value
1283 # of the old `from` option.
1285 # For example, the identity function can be passed, to return the option value unchanged.
1290 # To add a warning, you can pass the partially applied `warn` function.
1292 # use = lib.warn "Obsolete option `${opt.old}' is used. Use `${opt.to}' instead.";
1295 # Legacy option, enabled by default: whether to preserve the priority of definitions in `old`.
1296 withPriority ? true,
1297 # A boolean that defines the `mkIf` condition for `to`.
1298 # If the condition evaluates to `true`, and the `to` path points into an
1299 # `attrsOf (submodule ...)`, then `doRename` would cause an empty module to
1300 # be created, even if the `from` option is undefined.
1301 # By setting this to an expression that may return `false`, you can inhibit
1302 # this undesired behavior.
1307 # { config, lib, ... }:
1309 # inherit (lib) mkOption mkEnableOption types doRename;
1315 # services.foo.enable = mkEnableOption "foo";
1317 # # New multi-instance service
1318 # services.foos = mkOption {
1319 # type = types.attrsOf (types.submodule …);
1324 # from = [ "services" "foo" "bar" ];
1325 # to = [ "services" "foos" "" "bar" ];
1329 # withPriority = true;
1330 # # Only define services.foos."" if needed. (It's not just about `bar`)
1331 # condition = config.services.foo.enable;
1338 { config, options, ... }:
1340 fromOpt = getAttrFromPath from options;
1341 toOf = attrByPath to
1342 (abort "Renaming error: option `${showOption to}' does not exist.");
1343 toType = let opt = attrByPath to {} options; in opt.type or (types.submodule {});
1346 options = setAttrByPath from (mkOption {
1348 description = "Alias of {option}`${showOption to}`.";
1349 apply = x: use (toOf config);
1350 } // optionalAttrs (toType != null) {
1353 config = mkIf condition (mkMerge [
1354 (optionalAttrs (options ? warnings) {
1355 warnings = optional (warn && fromOpt.isDefined)
1356 "The option `${showOption from}' defined in ${showFiles fromOpt.files} has been renamed to `${showOption to}'.";
1359 then mkAliasAndWrapDefsWithPriority (setAttrByPath to) fromOpt
1360 else mkAliasAndWrapDefinitions (setAttrByPath to) fromOpt)
1365 `importApply file arg :: Path -> a -> Module`, where `import file :: a -> Module`
1367 `importApply` imports a Nix expression file much like the module system would,
1368 after passing an extra positional argument to the function in the file.
1370 This function should be used when declaring a module in a file that refers to
1371 values from a different scope, such as that in a flake.
1373 It solves the problems of alternative solutions:
1375 - While `importApply file arg` is _mostly_ equivalent to
1376 `import file arg`, the latter returns a module without a location,
1377 as `import` only returns the contained expression. This leads to worse
1380 - Using `specialArgs` to provide arguments to all modules. This effectively
1381 creates an incomplete module, and requires the user of the module to
1382 manually pass the `specialArgs` to the configuration, which is error-prone,
1383 verbose, and unnecessary.
1385 The nix file must contain a function that returns a module.
1386 A module may itself be a function, so the file is often a function with two
1387 positional arguments instead of one. See the example below.
1389 This function does not add support for deduplication and `disabledModules`,
1390 although that could be achieved by wrapping the returned module and setting
1391 the `_key` module attribute.
1392 The reason for this omission is that the file path is not guaranteed to be
1393 a unique identifier for the module, as two instances of the module may
1394 reference different `arg`s in their closures.
1400 (lib.modules.importApply ./module.nix { bar = bar; })
1405 { lib, config, ... }:
1408 config = ... bar ...;
1413 modulePath: staticArg:
1414 lib.setDefaultModuleLocation modulePath (import modulePath staticArg);
1416 /* Use this function to import a JSON file as NixOS configuration.
1418 modules.importJSON :: path -> attrs
1420 importJSON = file: {
1422 config = lib.importJSON file;
1425 /* Use this function to import a TOML file as NixOS configuration.
1427 modules.importTOML :: path -> attrs
1429 importTOML = file: {
1431 config = lib.importTOML file;
1435 (k: 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/.")
1438 applyModuleArgsIfFunction
1445 collectModules = collectModules null;
1449 Error messages produced by the module system.
1451 We factor these out to improve the flow when reading the code.
1453 Functions in `messages` that produce error messages are spelled in
1454 lower_snake_case. This goes against the convention in order to make the
1455 error message implementation more readable, and to visually distinguish
1456 them from other functions in the module system.
1459 inherit (lib.strings) concatMapStringsSep escapeNixString trim;
1460 /** "" or ", in file FOO" */
1461 into_fallback_file_maybe = file:
1463 (file != null && file != unknownModule)
1464 ", while trying to load a module into ${toString file}";
1466 /** Format text with one line break between each list item. */
1467 lines = concatMapStringsSep "\n" trim;
1469 /** Format text with two line break between each list item. */
1470 paragraphs = concatMapStringsSep "\n\n" trim;
1475 { foo = "Foo result";
1480 optionalMatch { foo = "Foo"; } "baz" == [ ]
1482 optionalMatch { foo = "Foo"; } true == [ ]
1485 optionalMatch = cases: value:
1486 if isString value && cases?${value}
1487 then [ cases.${value} ]
1490 # esc = builtins.fromJSON "\"\\u001b\"";
1491 esc = builtins.fromJSON "\"\\u001b\"";
1492 # Bold purple for warnings
1493 warn = s: "${esc}[1;35m${s}${esc}[0m";
1494 # Bold green for suggestions
1495 good = s: "${esc}[1;32m${s}${esc}[0m";
1496 # Bold, default color for code
1497 code = s: "${esc}[1m${s}${esc}[0m";
1501 /** When load a value with a (wrong) _type as a module */
1502 not_a_module = { fallbackFile, value, _type, expectedClass ? null }:
1505 Expected a module, but found a value of type ${warn (escapeNixString _type)}${into_fallback_file_maybe fallbackFile}.
1506 A module is typically loaded by adding it the ${code "imports = [ ... ];"} attribute of an existing module, or in the ${code "modules = [ ... ];"} argument of various functions.
1507 Please make sure that each of the list items is a module, and not a different kind of value.
1512 "configuration" = trim ''
1513 If you really mean to import this configuration, instead please only import the modules that make up the configuration.
1514 You may have to create a `let` binding, file or attribute to give yourself access to the relevant modules.
1515 While loading a configuration into the module system is a very sensible idea, it can not be done cleanly in practice.
1517 # ^^ 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.
1521 Perhaps you forgot to select an attribute name?
1522 Instead of, for example,
1523 ${warn "inputs.someflake"}
1524 you need to write something like
1525 ${warn "inputs.someflake"}${
1526 if expectedClass == null
1527 then good ".modules.someApp.default"
1528 else good ".modules.${expectedClass}.default"
1533 { # We'll no more than 5 custom suggestions here.
1534 # Please switch to `.modules.${class}` in your Module System application.
1537 ${warn "inputs.someflake"}${good ".nixosModules.default"}
1541 ${warn "inputs.someflake"}${good ".darwinModules.default"}
1555 # NOTE: not all of these functions are necessarily public interfaces; some
1556 # are just needed by types.nix, but are not meant to be consumed
1559 defaultOrderPriority
1560 defaultOverridePriority
1564 evalOptionValue # for use by lib.types
1568 fixupOptionType # should be private?
1573 mergeAttrDefinitionsWithPrio
1574 mergeOptionDecls # should be private?
1576 mkAliasAndWrapDefinitions
1577 mkAliasAndWrapDefsWithPriority
1581 mkAliasOptionModuleMD
1584 mkChangedOptionModule
1590 mkImageMediaOverride
1592 mkMergedOptionModule
1596 mkRemovedOptionModule
1597 mkRenamedOptionModule
1598 mkRenamedOptionModuleWith
1600 setDefaultModuleLocation