chromium,chromedriver: 128.0.6613.137 -> 129.0.6668.58 (#342721)
[NixPkgs.git] / lib / modules.nix
blob381480a1a07357823973d9161dc7b4320d66c171
1 { lib }:
3 let
4   inherit (lib)
5     addErrorContext
6     all
7     any
8     attrByPath
9     attrNames
10     catAttrs
11     concatLists
12     concatMap
13     concatStringsSep
14     elem
15     filter
16     foldl'
17     functionArgs
18     getAttrFromPath
19     genericClosure
20     head
21     id
22     imap1
23     isAttrs
24     isBool
25     isFunction
26     isInOldestRelease
27     isList
28     isString
29     length
30     mapAttrs
31     mapAttrsToList
32     mapAttrsRecursiveCond
33     min
34     optional
35     optionalAttrs
36     optionalString
37     recursiveUpdate
38     reverseList sort
39     seq
40     setAttrByPath
41     substring
42     throwIfNot
43     trace
44     typeOf
45     types
46     unsafeGetAttrPos
47     warn
48     warnIf
49     zipAttrs
50     zipAttrsWith
51     ;
52   inherit (lib.options)
53     isOption
54     mkOption
55     showDefs
56     showFiles
57     showOption
58     unknownModule
59     ;
60   inherit (lib.strings)
61     isConvertibleWithToString
62     ;
64   showDeclPrefix = loc: decl: prefix:
65     " - option(s) with prefix `${showOption (loc ++ [prefix])}' in module `${decl._file}'";
66   showRawDecls = loc: decls:
67     concatStringsSep "\n"
68       (sort (a: b: a < b)
69         (concatMap
70           (decl: map
71             (showDeclPrefix loc decl)
72             (attrNames decl.options)
73           )
74           decls
75       ));
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@
86                 { modules
87                 , prefix ? []
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.
92                   specialArgs ? {}
93                 , # `class`:
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.
96                   class ? null
97                 , # This would be remove in the future, Prefer _module.args option instead.
98                   args ? {}
99                 , # This would be remove in the future, Prefer _module.check option instead.
100                   check ? true
101                 }:
102     let
103       withWarnings = x:
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."
106         x;
108       legacyModules =
109         optional (evalModulesArgs?args) {
110           config = {
111             _module.args = args;
112           };
113         }
114         ++ optional (evalModulesArgs?check) {
115           config = {
116             _module.check = mkDefault check;
117           };
118         };
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.
124       #
125       # When extended with extendModules or moduleType, a fresh instance of
126       # this module is used, to avoid conflicts and allow chaining of
127       # extendModules.
128       internalModule = rec {
129         _file = "lib/modules.nix";
131         key = _file;
133         options = {
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.
145             ${if prefix == []
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
150             # separately
151             description = ''
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.
184                 ```
185                 { modulesPath, ... }: {
186                   imports = [
187                     (modulesPath + "/profiles/minimal.nix")
188                   ];
189                 }
190                 ```
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.
195             '';
196           };
198           _module.check = mkOption {
199             type = types.bool;
200             internal = true;
201             default = true;
202             description = "Whether to check whether all option definitions have matching declarations.";
203           };
205           _module.freeformType = mkOption {
206             type = types.nullOr types.optionType;
207             internal = true;
208             default = null;
209             description = ''
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 `
213               config` value.
215               If this is `null`, definitions without an option
216               will throw an error unless {option}`_module.check` is
217               turned off.
218             '';
219           };
221           _module.specialArgs = mkOption {
222             readOnly = true;
223             internal = true;
224             description = ''
225               Externally provided module arguments that can't be modified from
226               within a configuration, but can be used in module imports.
227             '';
228           };
229         };
231         config = {
232           _module.args = {
233             inherit extendModules;
234             moduleType = type;
235           };
236           _module.specialArgs = specialArgs;
237         };
238       };
240       merged =
241         let collected = collectModules
242           class
243           (specialArgs.modulesPath or "")
244           (regularModules ++ [ internalModule ])
245           ({ inherit lib options config specialArgs; } // specialArgs);
246         in mergeModules prefix (reverseList collected);
248       options = merged.matchedOptions;
250       config =
251         let
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
257           freeformConfig =
258             let
259               defs = map (def: {
260                 file = def.file;
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;
272       checkUnmatched =
273         if config._module.check && config._module.freeformType == null && merged.unmatchedDefns != [] then
274           let
275             firstDef = head merged.unmatchedDefns;
276             baseMsg =
277               let
278                 optText = showOption (prefix ++ firstDef.prefix);
279                 defText =
280                   addErrorContext
281                     "while evaluating the error message for definitions for `${optText}', which is an option that does not exist"
282                     (addErrorContext
283                       "while evaluating a definition from `${firstDef.file}'"
284                       ( showDefs [ firstDef ])
285                     );
286               in
287                 "The option `${optText}' does not exist. Definition values:${defText}";
288           in
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)
292               then
293                 let
294                   optionName = showOption prefix;
295                 in
296                   if optionName == ""
297                     then throw ''
298                       ${baseMsg}
300                       It seems as if you're trying to declare an option by placing it into `config' rather than `options'!
301                     ''
302                   else
303                     throw ''
304                       ${baseMsg}
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'.
309                     ''
310             else throw baseMsg
311         else null;
313       checked = seq checkUnmatched;
315       extendModules = extendArgs@{
316         modules ? [],
317         specialArgs ? {},
318         prefix ? [],
319         }:
320           evalModules (evalModulesArgs // {
321             inherit class;
322             modules = regularModules ++ modules;
323             specialArgs = evalModulesArgs.specialArgs or {} // specialArgs;
324             prefix = extendArgs.prefix or evalModulesArgs.prefix or [];
325           });
327       type = types.submoduleWith {
328         inherit modules specialArgs class;
329       };
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;
337         class = class;
338       };
339     in result;
341   # collectModules :: (class: String) -> (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]
342   #
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:
349         if isFunction m then
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; }
356           else
357             throw (
358               "Could not load a value as a module, because it is of type ${lib.strings.escapeNixString m._type}"
359               + optionalString (fallbackFile != unknownModule) ", in file ${toString fallbackFile}."
360               + 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."
361                # 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.
362             )
363         else if isList m then
364           let defs = [{ file = fallbackFile; value = m; }]; in
365           throw "Module imports can't be nested lists. Perhaps you meant to remove one level of lists? Definitions: ${showDefs defs}"
366         else unifyModuleSyntax (toString m) (toString m) (applyModuleArgsIfFunction (toString m) (import m) args);
368       checkModule =
369         if class != null
370         then
371           m:
372             if m._class != null -> m._class == class
373             then m
374             else
375               throw "The module ${m._file or m.key} was imported into ${class} instead of ${m._class}."
376         else
377           m: m;
379       /*
380       Collects all modules recursively into the form
382         {
383           disabled = [ <list of disabled modules> ];
384           # All modules of the main module list
385           modules = [
386             {
387               key = <key1>;
388               module = <module for key1>;
389               # All modules imported by the module for key1
390               modules = [
391                 {
392                   key = <key1-1>;
393                   module = <module for key1-1>;
394                   # All modules imported by the module for key1-1
395                   modules = [ ... ];
396                 }
397                 ...
398               ];
399             }
400             ...
401           ];
402         }
403       */
404       collectStructuredModules =
405         let
406           collectResults = modules: {
407             disabled = concatLists (catAttrs "disabled" modules);
408             inherit modules;
409           };
410         in parentFile: parentKey: initialModules: args: collectResults (imap1 (n: x:
411           let
412             module = checkModule (loadModule args parentFile "${parentKey}:anon-${toString n}" x);
413             collectedImports = collectStructuredModules module._file module.key module.imports args;
414           in {
415             key = module.key;
416             module = module;
417             modules = collectedImports.modules;
418             disabled = (if module.disabledModules != [] then [{ file = module._file; disabled = module.disabledModules; }] else []) ++ collectedImports.disabled;
419           }) initialModules);
421       # filterModules :: String -> { disabled, modules } -> [ Module ]
422       #
423       # Filters a structure as emitted by collectStructuredModules by removing all disabled
424       # modules recursively. It returns the final list of unique-by-key modules
425       filterModules = modulesPath: { disabled, modules }:
426         let
427           moduleKey = file: m:
428             if isString m
429             then
430               if substring 0 1 m == "/"
431               then m
432               else toString modulesPath + "/" + m
434             else if isConvertibleWithToString m
435             then
436               if m?key && m.key != toString m
437               then
438                 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."
439               else
440                 toString m
442             else if m?key
443             then
444               m.key
446             else if isAttrs m
447             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."
448             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}.";
450           disabledKeys = concatMap ({ file, disabled }: map (moduleKey file) disabled) disabled;
451           keyFilter = filter (attrs: ! elem attrs.key disabledKeys);
452         in map (attrs: attrs.module) (genericClosure {
453           startSet = keyFilter modules;
454           operator = attrs: keyFilter attrs.modules;
455         });
457     in modulesPath: initialModules: args:
458       filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args);
460   /* Wrap a module with a default location for reporting errors. */
461   setDefaultModuleLocation = file: m:
462     { _file = file; imports = [ m ]; };
464   /* Massage a module into canonical form, that is, a set consisting
465      of ‘options’, ‘config’ and ‘imports’ attributes. */
466   unifyModuleSyntax = file: key: m:
467     let
468       addMeta = config: if m ? meta
469         then mkMerge [ config { meta = m.meta; } ]
470         else config;
471       addFreeformType = config: if m ? freeformType
472         then mkMerge [ config { _module.freeformType = m.freeformType; } ]
473         else config;
474     in
475     if m ? config || m ? options then
476       let badAttrs = removeAttrs m ["_class" "_file" "key" "disabledModules" "imports" "options" "config" "meta" "freeformType"]; in
477       if badAttrs != {} then
478         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."
479       else
480         { _file = toString m._file or file;
481           _class = m._class or null;
482           key = toString m.key or key;
483           disabledModules = m.disabledModules or [];
484           imports = m.imports or [];
485           options = m.options or {};
486           config = addFreeformType (addMeta (m.config or {}));
487         }
488     else
489       # shorthand syntax
490       throwIfNot (isAttrs m) "module ${file} (${key}) does not look like a module."
491       { _file = toString m._file or file;
492         _class = m._class or null;
493         key = toString m.key or key;
494         disabledModules = m.disabledModules or [];
495         imports = m.require or [] ++ m.imports or [];
496         options = {};
497         config = addFreeformType (removeAttrs m ["_class" "_file" "key" "disabledModules" "require" "imports" "freeformType"]);
498       };
500   applyModuleArgsIfFunction = key: f: args@{ config, ... }:
501     if isFunction f then applyModuleArgs key f args else f;
503   applyModuleArgs = key: f: args@{ config, ... }:
504     let
505       # Module arguments are resolved in a strict manner when attribute set
506       # deconstruction is used.  As the arguments are now defined with the
507       # config._module.args option, the strictness used on the attribute
508       # set argument would cause an infinite loop, if the result of the
509       # option is given as argument.
510       #
511       # To work-around the strictness issue on the deconstruction of the
512       # attributes set argument, we create a new attribute set which is
513       # constructed to satisfy the expected set of attributes.  Thus calling
514       # a module will resolve strictly the attributes used as argument but
515       # not their values.  The values are forwarding the result of the
516       # evaluation of the option.
517       context = name: ''while evaluating the module argument `${name}' in "${key}":'';
518       extraArgs = mapAttrs (name: _:
519         addErrorContext (context name)
520           (args.${name} or config._module.args.${name})
521       ) (functionArgs f);
523       # Note: we append in the opposite order such that we can add an error
524       # context on the explicit arguments of "args" too. This update
525       # operator is used to make the "args@{ ... }: with args.lib;" notation
526       # works.
527     in f (args // extraArgs);
529   /* Merge a list of modules.  This will recurse over the option
530      declarations in all modules, combining them into a single set.
531      At the same time, for each option declaration, it will merge the
532      corresponding option definitions in all machines, returning them
533      in the ‘value’ attribute of each option.
535      This returns a set like
536        {
537          # A recursive set of options along with their final values
538          matchedOptions = {
539            foo = { _type = "option"; value = "option value of foo"; ... };
540            bar.baz = { _type = "option"; value = "option value of bar.baz"; ... };
541            ...
542          };
543          # A list of definitions that weren't matched by any option
544          unmatchedDefns = [
545            { file = "file.nix"; prefix = [ "qux" ]; value = "qux"; }
546            ...
547          ];
548        }
549   */
550   mergeModules = prefix: modules:
551     mergeModules' prefix modules
552       (concatMap (m: map (config: { file = m._file; inherit config; }) (pushDownProperties m.config)) modules);
554   mergeModules' = prefix: modules: configs:
555     let
556       # an attrset 'name' => list of submodules that declare ‘name’.
557       declsByName =
558         zipAttrsWith
559           (n: concatLists)
560           (map
561             (module: let subtree = module.options; in
562               if !(isAttrs subtree) then
563                 throw ''
564                   An option declaration for `${concatStringsSep "." prefix}' has type
565                   `${typeOf subtree}' rather than an attribute set.
566                   Did you mean to define this outside of `options'?
567                 ''
568               else
569                 mapAttrs
570                   (n: option:
571                     [{ inherit (module) _file; pos = unsafeGetAttrPos n subtree; options = option; }]
572                   )
573                   subtree
574               )
575             modules);
577       # The root of any module definition must be an attrset.
578       checkedConfigs =
579         assert
580           all
581             (c:
582               # TODO: I have my doubts that this error would occur when option definitions are not matched.
583               #       The implementation of this check used to be tied to a superficially similar check for
584               #       options, so maybe that's why this is here.
585               isAttrs c.config || throw ''
586                 In module `${c.file}', you're trying to define a value of type `${typeOf c.config}'
587                 rather than an attribute set for the option
588                 `${concatStringsSep "." prefix}'!
590                 This usually happens if `${concatStringsSep "." prefix}' has option
591                 definitions inside that are not matched. Please check how to properly define
592                 this option by e.g. referring to `man 5 configuration.nix'!
593               ''
594             )
595             configs;
596         configs;
598       # an attrset 'name' => list of submodules that define ‘name’.
599       pushedDownDefinitionsByName =
600         zipAttrsWith
601           (n: concatLists)
602           (map
603             (module:
604               mapAttrs
605                 (n: value:
606                   map (config: { inherit (module) file; inherit config; }) (pushDownProperties value)
607                 )
608               module.config
609             )
610             checkedConfigs);
611       # extract the definitions for each loc
612       rawDefinitionsByName =
613         zipAttrsWith
614           (n: concatLists)
615           (map
616             (module:
617               mapAttrs
618                 (n: value:
619                   [{ inherit (module) file; inherit value; }]
620                 )
621                 module.config
622             )
623             checkedConfigs);
625       # Convert an option tree decl to a submodule option decl
626       optionTreeToOption = decl:
627         if isOption decl.options
628         then decl
629         else decl // {
630             options = mkOption {
631               type = types.submoduleWith {
632                 modules = [ { options = decl.options; } ];
633                 # `null` is not intended for use by modules. It is an internal
634                 # value that means "whatever the user has declared elsewhere".
635                 # This might become obsolete with https://github.com/NixOS/nixpkgs/issues/162398
636                 shorthandOnlyDefinesConfig = null;
637               };
638             };
639           };
641       resultsByName = mapAttrs (name: decls:
642         # We're descending into attribute ‘name’.
643         let
644           loc = prefix ++ [name];
645           defns = pushedDownDefinitionsByName.${name} or [];
646           defns' = rawDefinitionsByName.${name} or [];
647           optionDecls = filter
648             (m: m.options?_type
649                 && (m.options._type == "option"
650                     || throwDeclarationTypeError loc m.options._type m._file
651                 )
652             )
653             decls;
654         in
655           if length optionDecls == length decls then
656             let opt = fixupOptionType loc (mergeOptionDecls loc decls);
657             in {
658               matchedOptions = evalOptionValue loc opt defns';
659               unmatchedDefns = [];
660             }
661           else if optionDecls != [] then
662               if all (x: x.options.type.name or null == "submodule") optionDecls
663               # Raw options can only be merged into submodules. Merging into
664               # attrsets might be nice, but ambiguous. Suppose we have
665               # attrset as a `attrsOf submodule`. User declares option
666               # attrset.foo.bar, this could mean:
667               #  a. option `bar` is only available in `attrset.foo`
668               #  b. option `foo.bar` is available in all `attrset.*`
669               #  c. reject and require "<name>" as a reminder that it behaves like (b).
670               #  d. magically combine (a) and (c).
671               # All of the above are merely syntax sugar though.
672               then
673                 let opt = fixupOptionType loc (mergeOptionDecls loc (map optionTreeToOption decls));
674                 in {
675                   matchedOptions = evalOptionValue loc opt defns';
676                   unmatchedDefns = [];
677                 }
678               else
679                 let
680                   nonOptions = filter (m: !isOption m.options) decls;
681                 in
682                 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${
683                   showRawDecls loc nonOptions
684                 }"
685           else
686             mergeModules' loc decls defns) declsByName;
688       matchedOptions = mapAttrs (n: v: v.matchedOptions) resultsByName;
690       # an attrset 'name' => list of unmatched definitions for 'name'
691       unmatchedDefnsByName =
692         # Propagate all unmatched definitions from nested option sets
693         mapAttrs (n: v: v.unmatchedDefns) resultsByName
694         # Plus the definitions for the current prefix that don't have a matching option
695         // removeAttrs rawDefinitionsByName (attrNames matchedOptions);
696     in {
697       inherit matchedOptions;
699       # Transforms unmatchedDefnsByName into a list of definitions
700       unmatchedDefns =
701         if configs == []
702         then
703           # When no config values exist, there can be no unmatched config, so
704           # we short circuit and avoid evaluating more _options_ than necessary.
705           []
706         else
707           concatLists (mapAttrsToList (name: defs:
708             map (def: def // {
709               # Set this so we know when the definition first left unmatched territory
710               prefix = [name] ++ (def.prefix or []);
711             }) defs
712           ) unmatchedDefnsByName);
713     };
715   throwDeclarationTypeError = loc: actualTag: file:
716     let
717       name = lib.strings.escapeNixIdentifier (lib.lists.last loc);
718       path = showOption loc;
719       depth = length loc;
721       paragraphs = [
722         "In module ${file}: expected an option declaration at option path `${path}` but got an attribute set with type ${actualTag}"
723       ] ++ optional (actualTag == "option-type") ''
724           When declaring an option, you must wrap the type in a `mkOption` call. It should look somewhat like:
725               ${comment}
726               ${name} = lib.mkOption {
727                 description = ...;
728                 type = <the type you wrote for ${name}>;
729                 ...
730               };
731         '';
733       # Ideally we'd know the exact syntax they used, but short of that,
734       # we can only reliably repeat the last. However, we repeat the
735       # full path in a non-misleading way here, in case they overlook
736       # the start of the message. Examples attract attention.
737       comment = optionalString (depth > 1) "\n    # ${showOption loc}";
738     in
739     throw (concatStringsSep "\n\n" paragraphs);
741   /* Merge multiple option declarations into a single declaration.  In
742      general, there should be only one declaration of each option.
743      The exception is the ‘options’ attribute, which specifies
744      sub-options.  These can be specified multiple times to allow one
745      module to add sub-options to an option declared somewhere else
746      (e.g. multiple modules define sub-options for ‘fileSystems’).
748      'loc' is the list of attribute names where the option is located.
750      'opts' is a list of modules.  Each module has an options attribute which
751      correspond to the definition of 'loc' in 'opt.file'. */
752   mergeOptionDecls =
753    loc: opts:
754     foldl' (res: opt:
755       let t  = res.type;
756           t' = opt.options.type;
757           mergedType = t.typeMerge t'.functor;
758           typesMergeable = mergedType != null;
759           typeSet = if (bothHave "type") && typesMergeable
760                        then { type = mergedType; }
761                        else {};
762           bothHave = k: opt.options ? ${k} && res ? ${k};
763       in
764       if bothHave "default" ||
765          bothHave "example" ||
766          bothHave "description" ||
767          bothHave "apply" ||
768          (bothHave "type" && (! typesMergeable))
769       then
770         throw "The option `${showOption loc}' in `${opt._file}' is already declared in ${showFiles res.declarations}."
771       else
772         let
773           getSubModules = opt.options.type.getSubModules or null;
774           submodules =
775             if getSubModules != null then map (setDefaultModuleLocation opt._file) getSubModules ++ res.options
776             else res.options;
777         in opt.options // res //
778           { declarations = res.declarations ++ [opt._file];
779             # In the case of modules that are generated dynamically, we won't
780             # have exact declaration lines; fall back to just the file being
781             # evaluated.
782             declarationPositions = res.declarationPositions
783               ++ (if opt.pos != null
784                 then [opt.pos]
785                 else [{ file = opt._file; line = null; column = null; }]);
786             options = submodules;
787           } // typeSet
788     ) { inherit loc; declarations = []; declarationPositions = []; options = []; } opts;
790   /* Merge all the definitions of an option to produce the final
791      config value. */
792   evalOptionValue = loc: opt: defs:
793     let
794       # Add in the default value for this option, if any.
795       defs' =
796           (optional (opt ? default)
797             { file = head opt.declarations; value = mkOptionDefault opt.default; }) ++ defs;
799       # Handle properties, check types, and merge everything together.
800       res =
801         if opt.readOnly or false && length defs' > 1 then
802           let
803             # For a better error message, evaluate all readOnly definitions as
804             # if they were the only definition.
805             separateDefs = map (def: def // {
806               value = (mergeDefinitions loc opt.type [ def ]).mergedValue;
807             }) defs';
808           in throw "The option `${showOption loc}' is read-only, but it's set multiple times. Definition values:${showDefs separateDefs}"
809         else
810           mergeDefinitions loc opt.type defs';
812       # Apply the 'apply' function to the merged value. This allows options to
813       # yield a value computed from the definitions
814       value = if opt ? apply then opt.apply res.mergedValue else res.mergedValue;
816       warnDeprecation =
817         warnIf (opt.type.deprecationMessage != null)
818           "The type `types.${opt.type.name}' of option `${showOption loc}' defined in ${showFiles opt.declarations} is deprecated. ${opt.type.deprecationMessage}";
820     in warnDeprecation opt //
821       { value = addErrorContext "while evaluating the option `${showOption loc}':" value;
822         inherit (res.defsFinal') highestPrio;
823         definitions = map (def: def.value) res.defsFinal;
824         files = map (def: def.file) res.defsFinal;
825         definitionsWithLocations = res.defsFinal;
826         inherit (res) isDefined;
827         # This allows options to be correctly displayed using `${options.path.to.it}`
828         __toString = _: showOption loc;
829       };
831   # Merge definitions of a value of a given type.
832   mergeDefinitions = loc: type: defs: rec {
833     defsFinal' =
834       let
835         # Process mkMerge and mkIf properties.
836         defs' = concatMap (m:
837           map (value: { inherit (m) file; inherit value; }) (addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))
838         ) defs;
840         # Process mkOverride properties.
841         defs'' = filterOverrides' defs';
843         # Sort mkOrder properties.
844         defs''' =
845           # Avoid sorting if we don't have to.
846           if any (def: def.value._type or "" == "order") defs''.values
847           then sortProperties defs''.values
848           else defs''.values;
849       in {
850         values = defs''';
851         inherit (defs'') highestPrio;
852       };
853     defsFinal = defsFinal'.values;
855     # Type-check the remaining definitions, and merge them. Or throw if no definitions.
856     mergedValue =
857       if isDefined then
858         if all (def: type.check def.value) defsFinal then type.merge loc defsFinal
859         else let allInvalid = filter (def: ! type.check def.value) defsFinal;
860         in throw "A definition for option `${showOption loc}' is not of type `${type.description}'. Definition values:${showDefs allInvalid}"
861       else
862         # (nixos-option detects this specific error message and gives it special
863         # handling.  If changed here, please change it there too.)
864         throw "The option `${showOption loc}' was accessed but has no value defined. Try setting the option.";
866     isDefined = defsFinal != [];
868     optionalValue =
869       if isDefined then { value = mergedValue; }
870       else {};
871   };
873   /* Given a config set, expand mkMerge properties, and push down the
874      other properties into the children.  The result is a list of
875      config sets that do not have properties at top-level.  For
876      example,
878        mkMerge [ { boot = set1; } (mkIf cond { boot = set2; services = set3; }) ]
880      is transformed into
882        [ { boot = set1; } { boot = mkIf cond set2; services = mkIf cond set3; } ].
884      This transform is the critical step that allows mkIf conditions
885      to refer to the full configuration without creating an infinite
886      recursion.
887   */
888   pushDownProperties = cfg:
889     if cfg._type or "" == "merge" then
890       concatMap pushDownProperties cfg.contents
891     else if cfg._type or "" == "if" then
892       map (mapAttrs (n: v: mkIf cfg.condition v)) (pushDownProperties cfg.content)
893     else if cfg._type or "" == "override" then
894       map (mapAttrs (n: v: mkOverride cfg.priority v)) (pushDownProperties cfg.content)
895     else # FIXME: handle mkOrder?
896       [ cfg ];
898   /* Given a config value, expand mkMerge properties, and discharge
899      any mkIf conditions.  That is, this is the place where mkIf
900      conditions are actually evaluated.  The result is a list of
901      config values.  For example, ‘mkIf false x’ yields ‘[]’,
902      ‘mkIf true x’ yields ‘[x]’, and
904        mkMerge [ 1 (mkIf true 2) (mkIf true (mkIf false 3)) ]
906      yields ‘[ 1 2 ]’.
907   */
908   dischargeProperties = def:
909     if def._type or "" == "merge" then
910       concatMap dischargeProperties def.contents
911     else if def._type or "" == "if" then
912       if isBool def.condition then
913         if def.condition then
914           dischargeProperties def.content
915         else
916           [ ]
917       else
918         throw "‘mkIf’ called with a non-Boolean condition"
919     else
920       [ def ];
922   /* Given a list of config values, process the mkOverride properties,
923      that is, return the values that have the highest (that is,
924      numerically lowest) priority, and strip the mkOverride
925      properties.  For example,
927        [ { file = "/1"; value = mkOverride 10 "a"; }
928          { file = "/2"; value = mkOverride 20 "b"; }
929          { file = "/3"; value = "z"; }
930          { file = "/4"; value = mkOverride 10 "d"; }
931        ]
933      yields
935        [ { file = "/1"; value = "a"; }
936          { file = "/4"; value = "d"; }
937        ]
939      Note that "z" has the default priority 100.
940   */
941   filterOverrides = defs: (filterOverrides' defs).values;
943   filterOverrides' = defs:
944     let
945       getPrio = def: if def.value._type or "" == "override" then def.value.priority else defaultOverridePriority;
946       highestPrio = foldl' (prio: def: min (getPrio def) prio) 9999 defs;
947       strip = def: if def.value._type or "" == "override" then def // { value = def.value.content; } else def;
948     in {
949       values = concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs;
950       inherit highestPrio;
951     };
953   /* Sort a list of properties.  The sort priority of a property is
954      defaultOrderPriority by default, but can be overridden by wrapping the property
955      using mkOrder. */
956   sortProperties = defs:
957     let
958       strip = def:
959         if def.value._type or "" == "order"
960         then def // { value = def.value.content; inherit (def.value) priority; }
961         else def;
962       defs' = map strip defs;
963       compare = a: b: (a.priority or defaultOrderPriority) < (b.priority or defaultOrderPriority);
964     in sort compare defs';
966   # This calls substSubModules, whose entire purpose is only to ensure that
967   # option declarations in submodules have accurate position information.
968   # TODO: Merge this into mergeOptionDecls
969   fixupOptionType = loc: opt:
970     if opt.type.getSubModules or null == null
971     then opt // { type = opt.type or types.unspecified; }
972     else opt // { type = opt.type.substSubModules opt.options; options = []; };
975   /*
976     Merge an option's definitions in a way that preserves the priority of the
977     individual attributes in the option value.
979     This does not account for all option semantics, such as readOnly.
981     Type:
982       option -> attrsOf { highestPrio, value }
983   */
984   mergeAttrDefinitionsWithPrio = opt:
985         let
986             defsByAttr =
987               zipAttrs (
988                 concatLists (
989                   concatMap
990                     ({ value, ... }@def:
991                       map
992                         (mapAttrsToList (k: value: { ${k} = def // { inherit value; }; }))
993                         (pushDownProperties value)
994                     )
995                     opt.definitionsWithLocations
996                 )
997               );
998         in
999           assert opt.type.name == "attrsOf" || opt.type.name == "lazyAttrsOf";
1000           mapAttrs
1001                 (k: v:
1002                   let merging = mergeDefinitions (opt.loc ++ [k]) opt.type.nestedTypes.elemType v;
1003                   in {
1004                     value = merging.mergedValue;
1005                     inherit (merging.defsFinal') highestPrio;
1006                   })
1007                 defsByAttr;
1009   /* Properties. */
1011   mkIf = condition: content:
1012     { _type = "if";
1013       inherit condition content;
1014     };
1016   mkAssert = assertion: message: content:
1017     mkIf
1018       (if assertion then true else throw "\nFailed assertion: ${message}")
1019       content;
1021   mkMerge = contents:
1022     { _type = "merge";
1023       inherit contents;
1024     };
1026   mkOverride = priority: content:
1027     { _type = "override";
1028       inherit priority content;
1029     };
1031   mkOptionDefault = mkOverride 1500; # priority of option defaults
1032   mkDefault = mkOverride 1000; # used in config sections of non-user modules to set a default
1033   defaultOverridePriority = 100;
1034   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
1035   mkForce = mkOverride 50;
1036   mkVMOverride = mkOverride 10; # used by ‘nixos-rebuild build-vm’
1038   defaultPriority = warnIf (isInOldestRelease 2305) "lib.modules.defaultPriority is deprecated, please use lib.modules.defaultOverridePriority instead." defaultOverridePriority;
1040   mkFixStrictness = warn "lib.mkFixStrictness has no effect and will be removed. It returns its argument unmodified, so you can just remove any calls." id;
1042   mkOrder = priority: content:
1043     { _type = "order";
1044       inherit priority content;
1045     };
1047   mkBefore = mkOrder 500;
1048   defaultOrderPriority = 1000;
1049   mkAfter = mkOrder 1500;
1051   # Convenient property used to transfer all definitions and their
1052   # properties from one option to another. This property is useful for
1053   # renaming options, and also for including properties from another module
1054   # system, including sub-modules.
1055   #
1056   #   { config, options, ... }:
1057   #
1058   #   {
1059   #     # 'bar' might not always be defined in the current module-set.
1060   #     config.foo.enable = mkAliasDefinitions (options.bar.enable or {});
1061   #
1062   #     # 'barbaz' has to be defined in the current module-set.
1063   #     config.foobar.paths = mkAliasDefinitions options.barbaz.paths;
1064   #   }
1065   #
1066   # Note, this is different than taking the value of the option and using it
1067   # as a definition, as the new definition will not keep the mkOverride /
1068   # mkDefault properties of the previous option.
1069   #
1070   mkAliasDefinitions = mkAliasAndWrapDefinitions id;
1071   mkAliasAndWrapDefinitions = wrap: option:
1072     mkAliasIfDef option (wrap (mkMerge option.definitions));
1074   # Similar to mkAliasAndWrapDefinitions but copies over the priority from the
1075   # option as well.
1076   #
1077   # If a priority is not set, it assumes a priority of defaultOverridePriority.
1078   mkAliasAndWrapDefsWithPriority = wrap: option:
1079     let
1080       prio = option.highestPrio or defaultOverridePriority;
1081       defsWithPrio = map (mkOverride prio) option.definitions;
1082     in mkAliasIfDef option (wrap (mkMerge defsWithPrio));
1084   mkAliasIfDef = option:
1085     mkIf (isOption option && option.isDefined);
1087   /* Compatibility. */
1088   fixMergeModules = modules: args: evalModules { inherit modules args; check = false; };
1091   /* Return a module that causes a warning to be shown if the
1092      specified option is defined. For example,
1094        mkRemovedOptionModule [ "boot" "loader" "grub" "bootDevice" ] "<replacement instructions>"
1096      causes a assertion if the user defines boot.loader.grub.bootDevice.
1098      replacementInstructions is a string that provides instructions on
1099      how to achieve the same functionality without the removed option,
1100      or alternatively a reasoning why the functionality is not needed.
1101      replacementInstructions SHOULD be provided!
1102   */
1103   mkRemovedOptionModule = optionName: replacementInstructions:
1104     { options, ... }:
1105     { options = setAttrByPath optionName (mkOption {
1106         visible = false;
1107         apply = x: throw "The option `${showOption optionName}' can no longer be used since it's been removed. ${replacementInstructions}";
1108       });
1109       config.assertions =
1110         let opt = getAttrFromPath optionName options; in [{
1111           assertion = !opt.isDefined;
1112           message = ''
1113             The option definition `${showOption optionName}' in ${showFiles opt.files} no longer has any effect; please remove it.
1114             ${replacementInstructions}
1115           '';
1116         }];
1117     };
1119   /* Return a module that causes a warning to be shown if the
1120      specified "from" option is defined; the defined value is however
1121      forwarded to the "to" option. This can be used to rename options
1122      while providing backward compatibility. For example,
1124        mkRenamedOptionModule [ "boot" "copyKernels" ] [ "boot" "loader" "grub" "copyKernels" ]
1126      forwards any definitions of boot.copyKernels to
1127      boot.loader.grub.copyKernels while printing a warning.
1129      This also copies over the priority from the aliased option to the
1130      non-aliased option.
1131   */
1132   mkRenamedOptionModule = from: to: doRename {
1133     inherit from to;
1134     visible = false;
1135     warn = true;
1136     use = trace "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
1137   };
1139   mkRenamedOptionModuleWith = {
1140     /* Old option path as list of strings. */
1141     from,
1142     /* New option path as list of strings. */
1143     to,
1145     /*
1146       Release number of the first release that contains the rename, ignoring backports.
1147       Set it to the upcoming release, matching the nixpkgs/.version file.
1148     */
1149     sinceRelease,
1151   }: doRename {
1152     inherit from to;
1153     visible = false;
1154     warn = isInOldestRelease sinceRelease;
1155     use = warnIf (isInOldestRelease sinceRelease)
1156       "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
1157   };
1159   /* Return a module that causes a warning to be shown if any of the "from"
1160      option is defined; the defined values can be used in the "mergeFn" to set
1161      the "to" value.
1162      This function can be used to merge multiple options into one that has a
1163      different type.
1165      "mergeFn" takes the module "config" as a parameter and must return a value
1166      of "to" option type.
1168        mkMergedOptionModule
1169          [ [ "a" "b" "c" ]
1170            [ "d" "e" "f" ] ]
1171          [ "x" "y" "z" ]
1172          (config:
1173            let value = p: getAttrFromPath p config;
1174            in
1175            if      (value [ "a" "b" "c" ]) == true then "foo"
1176            else if (value [ "d" "e" "f" ]) == true then "bar"
1177            else "baz")
1179      - options.a.b.c is a removed boolean option
1180      - options.d.e.f is a removed boolean option
1181      - options.x.y.z is a new str option that combines a.b.c and d.e.f
1182        functionality
1184      This show a warning if any a.b.c or d.e.f is set, and set the value of
1185      x.y.z to the result of the merge function
1186   */
1187   mkMergedOptionModule = from: to: mergeFn:
1188     { config, options, ... }:
1189     {
1190       options = foldl' recursiveUpdate {} (map (path: setAttrByPath path (mkOption {
1191         visible = false;
1192         # To use the value in mergeFn without triggering errors
1193         default = "_mkMergedOptionModule";
1194       })) from);
1196       config = {
1197         warnings = filter (x: x != "") (map (f:
1198           let val = getAttrFromPath f config;
1199               opt = getAttrFromPath f options;
1200           in
1201           optionalString
1202             (val != "_mkMergedOptionModule")
1203             "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."
1204         ) from);
1205       } // setAttrByPath to (mkMerge
1206              (optional
1207                (any (f: (getAttrFromPath f config) != "_mkMergedOptionModule") from)
1208                (mergeFn config)));
1209     };
1211   /* Single "from" version of mkMergedOptionModule.
1212      Return a module that causes a warning to be shown if the "from" option is
1213      defined; the defined value can be used in the "mergeFn" to set the "to"
1214      value.
1215      This function can be used to change an option into another that has a
1216      different type.
1218      "mergeFn" takes the module "config" as a parameter and must return a value of
1219      "to" option type.
1221        mkChangedOptionModule [ "a" "b" "c" ] [ "x" "y" "z" ]
1222          (config:
1223            let value = getAttrFromPath [ "a" "b" "c" ] config;
1224            in
1225            if   value > 100 then "high"
1226            else "normal")
1228      - options.a.b.c is a removed int option
1229      - options.x.y.z is a new str option that supersedes a.b.c
1231      This show a warning if a.b.c is set, and set the value of x.y.z to the
1232      result of the change function
1233   */
1234   mkChangedOptionModule = from: to: changeFn:
1235     mkMergedOptionModule [ from ] to changeFn;
1237   /* Like ‘mkRenamedOptionModule’, but doesn't show a warning. */
1238   mkAliasOptionModule = from: to: doRename {
1239     inherit from to;
1240     visible = true;
1241     warn = false;
1242     use = id;
1243   };
1245   /* Transitional version of mkAliasOptionModule that uses MD docs.
1247      This function is no longer necessary and merely an alias of `mkAliasOptionModule`.
1248   */
1249   mkAliasOptionModuleMD = mkAliasOptionModule;
1251   /* mkDerivedConfig : Option a -> (a -> Definition b) -> Definition b
1253     Create config definitions with the same priority as the definition of another option.
1254     This should be used for option definitions where one option sets the value of another as a convenience.
1255     For instance a config file could be set with a `text` or `source` option, where text translates to a `source`
1256     value using `mkDerivedConfig options.text (pkgs.writeText "filename.conf")`.
1258     It takes care of setting the right priority using `mkOverride`.
1259   */
1260   # TODO: make the module system error message include information about `opt` in
1261   # error messages about conflicts. E.g. introduce a variation of `mkOverride` which
1262   # adds extra location context to the definition object. This will allow context to be added
1263   # to all messages that report option locations "this value was derived from <full option name>
1264   # which was defined in <locations>". It can provide a trace of options that contributed
1265   # to definitions.
1266   mkDerivedConfig = opt: f:
1267     mkOverride
1268       (opt.highestPrio or defaultOverridePriority)
1269       (f opt.value);
1271   /*
1272     Return a module that help declares an option that has been renamed.
1273     When a value is defined for the old option, it is forwarded to the `to` option.
1274    */
1275   doRename = {
1276     # List of strings representing the attribute path of the old option.
1277     from,
1278     # List of strings representing the attribute path of the new option.
1279     to,
1280     # Boolean, whether the old option is to be included in documentation.
1281     visible,
1282     # Whether to warn when a value is defined for the old option.
1283     # NOTE: This requires the NixOS assertions module to be imported, so
1284     #        - this generally does not work in submodules
1285     #        - this may or may not work outside NixOS
1286     warn,
1287     # A function that is applied to the option value, to form the value
1288     # of the old `from` option.
1289     #
1290     # For example, the identity function can be passed, to return the option value unchanged.
1291     # ```nix
1292     # use = x: x;
1293     # ```
1294     #
1295     # To add a warning, you can pass the partially applied `warn` function.
1296     # ```nix
1297     # use = lib.warn "Obsolete option `${opt.old}' is used. Use `${opt.to}' instead.";
1298     # ```
1299     use,
1300     # Legacy option, enabled by default: whether to preserve the priority of definitions in `old`.
1301     withPriority ? true,
1302     # A boolean that defines the `mkIf` condition for `to`.
1303     # If the condition evaluates to `true`, and the `to` path points into an
1304     # `attrsOf (submodule ...)`, then `doRename` would cause an empty module to
1305     # be created, even if the `from` option is undefined.
1306     # By setting this to an expression that may return `false`, you can inhibit
1307     # this undesired behavior.
1308     #
1309     # Example:
1310     #
1311     # ```nix
1312     # { config, lib, ... }:
1313     # let
1314     #   inherit (lib) mkOption mkEnableOption types doRename;
1315     # in
1316     # {
1317     #   options = {
1318     #
1319     #     # Old service
1320     #     services.foo.enable = mkEnableOption "foo";
1321     #
1322     #     # New multi-instance service
1323     #     services.foos = mkOption {
1324     #       type = types.attrsOf (types.submodule …);
1325     #     };
1326     #   };
1327     #   imports = [
1328     #     (doRename {
1329     #       from = [ "services" "foo" "bar" ];
1330     #       to = [ "services" "foos" "" "bar" ];
1331     #       visible = true;
1332     #       warn = false;
1333     #       use = x: x;
1334     #       withPriority = true;
1335     #       # Only define services.foos."" if needed. (It's not just about `bar`)
1336     #       condition = config.services.foo.enable;
1337     #     })
1338     #   ];
1339     # }
1340     # ```
1341     condition ? true
1342   }:
1343     { config, options, ... }:
1344     let
1345       fromOpt = getAttrFromPath from options;
1346       toOf = attrByPath to
1347         (abort "Renaming error: option `${showOption to}' does not exist.");
1348       toType = let opt = attrByPath to {} options; in opt.type or (types.submodule {});
1349     in
1350     {
1351       options = setAttrByPath from (mkOption {
1352         inherit visible;
1353         description = "Alias of {option}`${showOption to}`.";
1354         apply = x: use (toOf config);
1355       } // optionalAttrs (toType != null) {
1356         type = toType;
1357       });
1358       config = mkIf condition (mkMerge [
1359         (optionalAttrs (options ? warnings) {
1360           warnings = optional (warn && fromOpt.isDefined)
1361             "The option `${showOption from}' defined in ${showFiles fromOpt.files} has been renamed to `${showOption to}'.";
1362         })
1363         (if withPriority
1364           then mkAliasAndWrapDefsWithPriority (setAttrByPath to) fromOpt
1365           else mkAliasAndWrapDefinitions (setAttrByPath to) fromOpt)
1366       ]);
1367     };
1369   /**
1370     `importApply file arg :: Path -> a -> Module`,  where `import file :: a -> Module`
1372     `importApply` imports a Nix expression file much like the module system would,
1373     after passing an extra positional argument to the function in the file.
1375     This function should be used when declaring a module in a file that refers to
1376     values from a different scope, such as that in a flake.
1378     It solves the problems of alternative solutions:
1380     - While `importApply file arg` is _mostly_ equivalent to
1381       `import file arg`, the latter returns a module without a location,
1382       as `import` only returns the contained expression. This leads to worse
1383       error messages.
1385     - Using `specialArgs` to provide arguments to all modules. This effectively
1386       creates an incomplete module, and requires the user of the module to
1387       manually pass the `specialArgs` to the configuration, which is error-prone,
1388       verbose, and unnecessary.
1390     The nix file must contain a function that returns a module.
1391     A module may itself be a function, so the file is often a function with two
1392     positional arguments instead of one. See the example below.
1394     This function does not add support for deduplication and `disabledModules`,
1395     although that could be achieved by wrapping the returned module and setting
1396     the `_key` module attribute.
1397     The reason for this omission is that the file path is not guaranteed to be
1398     a unique identifier for the module, as two instances of the module may
1399     reference different `arg`s in their closures.
1401     Example
1403         # lib.nix
1404         imports = [
1405           (lib.modules.importApply ./module.nix { bar = bar; })
1406         ];
1408         # module.nix
1409         { bar }:
1410         { lib, config, ... }:
1411         {
1412           options = ...;
1413           config = ... bar ...;
1414         }
1416   */
1417   importApply =
1418     modulePath: staticArg:
1419       lib.setDefaultModuleLocation modulePath (import modulePath staticArg);
1421   /* Use this function to import a JSON file as NixOS configuration.
1423      modules.importJSON :: path -> attrs
1424   */
1425   importJSON = file: {
1426     _file = file;
1427     config = lib.importJSON file;
1428   };
1430   /* Use this function to import a TOML file as NixOS configuration.
1432      modules.importTOML :: path -> attrs
1433   */
1434   importTOML = file: {
1435     _file = file;
1436     config = lib.importTOML file;
1437   };
1439   private = mapAttrs
1440     (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/.")
1441     {
1442       inherit
1443         applyModuleArgsIfFunction
1444         dischargeProperties
1445         mergeModules
1446         mergeModules'
1447         pushDownProperties
1448         unifyModuleSyntax
1449         ;
1450       collectModules = collectModules null;
1451     };
1454 private //
1456   # NOTE: not all of these functions are necessarily public interfaces; some
1457   #       are just needed by types.nix, but are not meant to be consumed
1458   #       externally.
1459   inherit
1460     defaultOrderPriority
1461     defaultOverridePriority
1462     defaultPriority
1463     doRename
1464     evalModules
1465     evalOptionValue  # for use by lib.types
1466     filterOverrides
1467     filterOverrides'
1468     fixMergeModules
1469     fixupOptionType  # should be private?
1470     importApply
1471     importJSON
1472     importTOML
1473     mergeDefinitions
1474     mergeAttrDefinitionsWithPrio
1475     mergeOptionDecls  # should be private?
1476     mkAfter
1477     mkAliasAndWrapDefinitions
1478     mkAliasAndWrapDefsWithPriority
1479     mkAliasDefinitions
1480     mkAliasIfDef
1481     mkAliasOptionModule
1482     mkAliasOptionModuleMD
1483     mkAssert
1484     mkBefore
1485     mkChangedOptionModule
1486     mkDefault
1487     mkDerivedConfig
1488     mkFixStrictness
1489     mkForce
1490     mkIf
1491     mkImageMediaOverride
1492     mkMerge
1493     mkMergedOptionModule
1494     mkOptionDefault
1495     mkOrder
1496     mkOverride
1497     mkRemovedOptionModule
1498     mkRenamedOptionModule
1499     mkRenamedOptionModuleWith
1500     mkVMOverride
1501     setDefaultModuleLocation
1502     sortProperties;