about summary refs log tree commit diff
path: root/nixpkgs/nixos/modules/config/nix.nix
blob: a40953a3a3c92b7d45c9df30d7a2f9ad75f85f32 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
/*
  Manages /etc/nix/nix.conf.

  See also
   - ./nix-channel.nix
   - ./nix-flakes.nix
   - ./nix-remote-build.nix
   - nixos/modules/services/system/nix-daemon.nix
 */
{ config, lib, pkgs, ... }:

let
  inherit (lib)
    concatStringsSep
    boolToString
    escape
    filterAttrs
    floatToString
    getVersion
    hasPrefix
    isBool
    isDerivation
    isFloat
    isInt
    isList
    isString
    literalExpression
    mapAttrsToList
    mkAfter
    mkDefault
    mkIf
    mkOption
    mkRenamedOptionModuleWith
    optionalString
    optionals
    strings
    systems
    toPretty
    types
    versionAtLeast
    ;

  cfg = config.nix;

  nixPackage = cfg.package.out;

  isNixAtLeast = versionAtLeast (getVersion nixPackage);

  legacyConfMappings = {
    useSandbox = "sandbox";
    buildCores = "cores";
    maxJobs = "max-jobs";
    sandboxPaths = "extra-sandbox-paths";
    binaryCaches = "substituters";
    trustedBinaryCaches = "trusted-substituters";
    binaryCachePublicKeys = "trusted-public-keys";
    autoOptimiseStore = "auto-optimise-store";
    requireSignedBinaryCaches = "require-sigs";
    trustedUsers = "trusted-users";
    allowedUsers = "allowed-users";
    systemFeatures = "system-features";
  };

  semanticConfType = with types;
    let
      confAtom = nullOr
        (oneOf [
          bool
          int
          float
          str
          path
          package
        ]) // {
        description = "Nix config atom (null, bool, int, float, str, path or package)";
      };
    in
    attrsOf (either confAtom (listOf confAtom));

  nixConf =
    assert isNixAtLeast "2.2";
    let

      mkValueString = v:
        if v == null then ""
        else if isInt v then toString v
        else if isBool v then boolToString v
        else if isFloat v then floatToString v
        else if isList v then toString v
        else if isDerivation v then toString v
        else if builtins.isPath v then toString v
        else if isString v then v
        else if strings.isConvertibleWithToString v then toString v
        else abort "The nix conf value: ${toPretty {} v} can not be encoded";

      mkKeyValue = k: v: "${escape [ "=" ] k} = ${mkValueString v}";

      mkKeyValuePairs = attrs: concatStringsSep "\n" (mapAttrsToList mkKeyValue attrs);

      isExtra = key: hasPrefix "extra-" key;

    in
    pkgs.writeTextFile {
      name = "nix.conf";
      # workaround for https://github.com/NixOS/nix/issues/9487
      # extra-* settings must come after their non-extra counterpart
      text = ''
        # WARNING: this file is generated from the nix.* options in
        # your NixOS configuration, typically
        # /etc/nixos/configuration.nix.  Do not edit it!
        ${mkKeyValuePairs (filterAttrs (key: value: !(isExtra key)) cfg.settings)}
        ${mkKeyValuePairs (filterAttrs (key: value: isExtra key) cfg.settings)}
        ${cfg.extraOptions}
      '';
      checkPhase = lib.optionalString cfg.checkConfig (
        if pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform then ''
          echo "Ignoring validation for cross-compilation"
        ''
        else
        let
          showCommand = if isNixAtLeast "2.20pre" then "config show" else "show-config";
        in
        ''
          echo "Validating generated nix.conf"
          ln -s $out ./nix.conf
          set -e
          set +o pipefail
          NIX_CONF_DIR=$PWD \
            ${cfg.package}/bin/nix ${showCommand} ${optionalString (isNixAtLeast "2.3pre") "--no-net"} \
              ${optionalString (isNixAtLeast "2.4pre") "--option experimental-features nix-command"} \
            |& sed -e 's/^warning:/error:/' \
            | (! grep '${if cfg.checkAllErrors then "^error:" else "^error: unknown setting"}')
          set -o pipefail
        '');
    };

in
{
  imports = [
    (mkRenamedOptionModuleWith { sinceRelease = 2003; from = [ "nix" "useChroot" ]; to = [ "nix" "useSandbox" ]; })
    (mkRenamedOptionModuleWith { sinceRelease = 2003; from = [ "nix" "chrootDirs" ]; to = [ "nix" "sandboxPaths" ]; })
  ] ++
    mapAttrsToList
      (oldConf: newConf:
        mkRenamedOptionModuleWith {
          sinceRelease = 2205;
          from = [ "nix" oldConf ];
          to = [ "nix" "settings" newConf ];
      })
      legacyConfMappings;

  options = {
    nix = {
      checkConfig = mkOption {
        type = types.bool;
        default = true;
        description = lib.mdDoc ''
          If enabled, checks that Nix can parse the generated nix.conf.
        '';
      };

      checkAllErrors = mkOption {
        type = types.bool;
        default = true;
        description = lib.mdDoc ''
          If enabled, checks the nix.conf parsing for any kind of error. When disabled, checks only for unknown settings.
        '';
      };

      extraOptions = mkOption {
        type = types.lines;
        default = "";
        example = ''
          keep-outputs = true
          keep-derivations = true
        '';
        description = lib.mdDoc "Additional text appended to {file}`nix.conf`.";
      };

      settings = mkOption {
        type = types.submodule {
          freeformType = semanticConfType;

          options = {
            max-jobs = mkOption {
              type = types.either types.int (types.enum [ "auto" ]);
              default = "auto";
              example = 64;
              description = lib.mdDoc ''
                This option defines the maximum number of jobs that Nix will try to
                build in parallel. The default is auto, which means it will use all
                available logical cores. It is recommend to set it to the total
                number of logical cores in your system (e.g., 16 for two CPUs with 4
                cores each and hyper-threading).
              '';
            };

            auto-optimise-store = mkOption {
              type = types.bool;
              default = false;
              example = true;
              description = lib.mdDoc ''
                If set to true, Nix automatically detects files in the store that have
                identical contents, and replaces them with hard links to a single copy.
                This saves disk space. If set to false (the default), you can still run
                nix-store --optimise to get rid of duplicate files.
              '';
            };

            cores = mkOption {
              type = types.int;
              default = 0;
              example = 64;
              description = lib.mdDoc ''
                This option defines the maximum number of concurrent tasks during
                one build. It affects, e.g., -j option for make.
                The special value 0 means that the builder should use all
                available CPU cores in the system. Some builds may become
                non-deterministic with this option; use with care! Packages will
                only be affected if enableParallelBuilding is set for them.
              '';
            };

            sandbox = mkOption {
              type = types.either types.bool (types.enum [ "relaxed" ]);
              default = true;
              description = lib.mdDoc ''
                If set, Nix will perform builds in a sandboxed environment that it
                will set up automatically for each build. This prevents impurities
                in builds by disallowing access to dependencies outside of the Nix
                store by using network and mount namespaces in a chroot environment.

                This is enabled by default even though it has a possible performance
                impact due to the initial setup time of a sandbox for each build. It
                doesn't affect derivation hashes, so changing this option will not
                trigger a rebuild of packages.

                When set to "relaxed", this option permits derivations that set
                `__noChroot = true;` to run outside of the sandboxed environment.
                Exercise caution when using this mode of operation! It is intended to
                be a quick hack when building with packages that are not easily setup
                to be built reproducibly.
              '';
            };

            extra-sandbox-paths = mkOption {
              type = types.listOf types.str;
              default = [ ];
              example = [ "/dev" "/proc" ];
              description = lib.mdDoc ''
                Directories from the host filesystem to be included
                in the sandbox.
              '';
            };

            substituters = mkOption {
              type = types.listOf types.str;
              description = lib.mdDoc ''
                List of binary cache URLs used to obtain pre-built binaries
                of Nix packages.

                By default https://cache.nixos.org/ is added.
              '';
            };

            trusted-substituters = mkOption {
              type = types.listOf types.str;
              default = [ ];
              example = [ "https://hydra.nixos.org/" ];
              description = lib.mdDoc ''
                List of binary cache URLs that non-root users can use (in
                addition to those specified using
                {option}`nix.settings.substituters`) by passing
                `--option binary-caches` to Nix commands.
              '';
            };

            require-sigs = mkOption {
              type = types.bool;
              default = true;
              description = lib.mdDoc ''
                If enabled (the default), Nix will only download binaries from binary caches if
                they are cryptographically signed with any of the keys listed in
                {option}`nix.settings.trusted-public-keys`. If disabled, signatures are neither
                required nor checked, so it's strongly recommended that you use only
                trustworthy caches and https to prevent man-in-the-middle attacks.
              '';
            };

            trusted-public-keys = mkOption {
              type = types.listOf types.str;
              example = [ "hydra.nixos.org-1:CNHJZBh9K4tP3EKF6FkkgeVYsS3ohTl+oS0Qa8bezVs=" ];
              description = lib.mdDoc ''
                List of public keys used to sign binary caches. If
                {option}`nix.settings.trusted-public-keys` is enabled,
                then Nix will use a binary from a binary cache if and only
                if it is signed by *any* of the keys
                listed here. By default, only the key for
                `cache.nixos.org` is included.
              '';
            };

            trusted-users = mkOption {
              type = types.listOf types.str;
              default = [ "root" ];
              example = [ "root" "alice" "@wheel" ];
              description = lib.mdDoc ''
                A list of names of users that have additional rights when
                connecting to the Nix daemon, such as the ability to specify
                additional binary caches, or to import unsigned NARs. You
                can also specify groups by prefixing them with
                `@`; for instance,
                `@wheel` means all users in the wheel
                group.
              '';
            };

            system-features = mkOption {
              type = types.listOf types.str;
              example = [ "kvm" "big-parallel" "gccarch-skylake" ];
              description = lib.mdDoc ''
                The set of features supported by the machine. Derivations
                can express dependencies on system features through the
                `requiredSystemFeatures` attribute.

                By default, pseudo-features `nixos-test`, `benchmark`,
                and `big-parallel` used in Nixpkgs are set, `kvm`
                is also included if it is available.
              '';
            };

            allowed-users = mkOption {
              type = types.listOf types.str;
              default = [ "*" ];
              example = [ "@wheel" "@builders" "alice" "bob" ];
              description = lib.mdDoc ''
                A list of names of users (separated by whitespace) that are
                allowed to connect to the Nix daemon. As with
                {option}`nix.settings.trusted-users`, you can specify groups by
                prefixing them with `@`. Also, you can
                allow all users by specifying `*`. The
                default is `*`. Note that trusted users are
                always allowed to connect.
              '';
            };
          };
        };
        default = { };
        example = literalExpression ''
          {
            use-sandbox = true;
            show-trace = true;

            system-features = [ "big-parallel" "kvm" "recursive-nix" ];
            sandbox-paths = [ "/bin/sh=''${pkgs.busybox-sandbox-shell.out}/bin/busybox" ];
          }
        '';
        description = lib.mdDoc ''
          Configuration for Nix, see
          <https://nixos.org/manual/nix/stable/command-ref/conf-file.html> or
          {manpage}`nix.conf(5)` for available options.
          The value declared here will be translated directly to the key-value pairs Nix expects.

          You can use {command}`nix-instantiate --eval --strict '<nixpkgs/nixos>' -A config.nix.settings`
          to view the current value. By default it is empty.

          Nix configurations defined under {option}`nix.*` will be translated and applied to this
          option. In addition, configuration specified in {option}`nix.extraOptions` will be appended
          verbatim to the resulting config file.
        '';
      };
    };
  };

  config = mkIf cfg.enable {
    environment.etc."nix/nix.conf".source = nixConf;
    nix.settings = {
      trusted-public-keys = [ "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" ];
      substituters = mkAfter [ "https://cache.nixos.org/" ];
      system-features = mkDefault (
        [ "nixos-test" "benchmark" "big-parallel" "kvm" ] ++
        optionals (pkgs.stdenv.hostPlatform ? gcc.arch) (
          # a builder can run code for `gcc.arch` and inferior architectures
          [ "gccarch-${pkgs.stdenv.hostPlatform.gcc.arch}" ] ++
          map (x: "gccarch-${x}") (systems.architectures.inferiors.${pkgs.stdenv.hostPlatform.gcc.arch} or [])
        )
      );
    };
  };
}