1# From an end-user configuration file (`configuration.nix'), build a NixOS
2# configuration object (`config') from which we can retrieve option
3# values.
4
5# !!! Please think twice before adding to this argument list!
6# Ideally eval-config.nix would be an extremely thin wrapper
7# around lib.evalModules, so that modular systems that have nixos configs
8# as subcomponents (e.g. the container feature, or nixops if network
9# expressions are ever made modular at the top level) can just use
10# types.submodule instead of using eval-config.nix
11evalConfigArgs@{
12 # !!! system can be set modularly, would be nice to remove,
13 # however, removing or changing this default is too much
14 # of a breaking change. To set it modularly, pass `null`.
15 system ? builtins.currentSystem,
16 # !!! is this argument needed any more? The pkgs argument can
17 # be set modularly anyway.
18 pkgs ? null,
19 # !!! what do we gain by making this configurable?
20 # we can add modules that are included in specialisations, regardless
21 # of inheritParentConfig.
22 baseModules ? import ../modules/module-list.nix,
23 # !!! See comment about args in lib/modules.nix
24 extraArgs ? { },
25 # !!! See comment about args in lib/modules.nix
26 specialArgs ? { },
27 modules,
28 modulesLocation ? (builtins.unsafeGetAttrPos "modules" evalConfigArgs).file or null,
29 # !!! See comment about check in lib/modules.nix
30 check ? true,
31 prefix ? [ ],
32 lib ? import ../../lib,
33 extraModules ?
34 let
35 e = builtins.getEnv "NIXOS_EXTRA_MODULE_PATH";
36 in
37 lib.optional (e != "") (
38 lib.warn
39 ''
40 The NIXOS_EXTRA_MODULE_PATH environment variable is deprecated and will be
41 removed in NixOS 25.05.
42 We recommend a workflow where you update the expression files instead, but
43 if you wish to continue to use this variable, you may do so with a module like:
44
45 {
46 imports = [
47 (builtins.getEnv "NIXOS_EXTRA_MODULE_PATH")
48 ];
49 }
50
51 This has the benefit that your configuration hints at the
52 non-standard workflow.
53 ''
54 # NOTE: this import call is unnecessary and it even removes the file name
55 # from error messages.
56 import
57 e
58 ),
59}:
60
61let
62 inherit (lib) optional;
63
64 evalModulesMinimal =
65 (import ./default.nix {
66 inherit lib;
67 # Implicit use of feature is noted in implementation.
68 featureFlags.minimalModules = { };
69 }).evalModules;
70
71 pkgsModule = rec {
72 _file = ./eval-config.nix;
73 key = _file;
74 config = lib.mkMerge (
75 (optional (system != null) {
76 # Explicit `nixpkgs.system` or `nixpkgs.localSystem` should override
77 # this. Since the latter defaults to the former, the former should
78 # default to the argument. That way this new default could propagate all
79 # they way through, but has the last priority behind everything else.
80 nixpkgs.system = lib.mkDefault system;
81 })
82 ++ (optional (pkgs != null) {
83 # This should be default priority, so it conflicts with any user-defined pkgs.
84 nixpkgs.pkgs = pkgs;
85 })
86 );
87 };
88
89 withWarnings =
90 x:
91 lib.warnIf (evalConfigArgs ? extraArgs)
92 "The extraArgs argument to eval-config.nix is deprecated. Please set config._module.args instead."
93 lib.warnIf
94 (evalConfigArgs ? check)
95 "The check argument to eval-config.nix is deprecated. Please set config._module.check instead."
96 lib.warnIf
97 (specialArgs ? pkgs)
98 ''
99 You have set specialArgs.pkgs, which means that options like nixpkgs.config
100 and nixpkgs.overlays will be ignored. If you wish to reuse an already created
101 pkgs, which you know is configured correctly for this NixOS configuration,
102 please import the `nixosModules.readOnlyPkgs` module from the nixpkgs flake or
103 `(modulesPath + "/misc/nixpkgs/read-only.nix"), and set `{ nixpkgs.pkgs = <your pkgs>; }`.
104 This properly disables the ignored options to prevent future surprises.
105 ''
106 x;
107
108 legacyModules =
109 lib.optional (evalConfigArgs ? extraArgs) {
110 config = {
111 _module.args = extraArgs;
112 };
113 }
114 ++ lib.optional (evalConfigArgs ? check) {
115 config = {
116 _module.check = lib.mkDefault check;
117 };
118 };
119
120 allUserModules =
121 let
122 # Add the invoking file (or specified modulesLocation) as error message location
123 # for modules that don't have their own locations; presumably inline modules.
124 locatedModules =
125 if modulesLocation == null then
126 modules
127 else
128 map (lib.setDefaultModuleLocation modulesLocation) modules;
129 in
130 locatedModules ++ legacyModules;
131
132 noUserModules = evalModulesMinimal ({
133 inherit prefix specialArgs;
134 modules =
135 baseModules
136 ++ extraModules
137 ++ [
138 pkgsModule
139 modulesModule
140 ];
141 });
142
143 # Extra arguments that are useful for constructing a similar configuration.
144 modulesModule = {
145 config = {
146 _module.args = {
147 inherit
148 noUserModules
149 baseModules
150 extraModules
151 modules
152 ;
153 };
154 };
155 };
156
157 nixosWithUserModules = noUserModules.extendModules { modules = allUserModules; };
158
159 withExtraAttrs =
160 configuration:
161 configuration
162 // {
163 inherit extraArgs;
164 inherit (configuration._module.args) pkgs;
165 inherit lib;
166 extendModules = args: withExtraAttrs (configuration.extendModules args);
167 };
168in
169withWarnings (withExtraAttrs nixosWithUserModules)