···14141515 /* Return an attribute from nested attribute sets.
16161717+ Nix has an [attribute selection operator `. or`](https://nixos.org/manual/nix/stable/language/operators#attribute-selection) which is sufficient for such queries, as long as the number of attributes is static. For example:
1818+1919+ ```nix
2020+ (x.a.b or 6) == attrByPath ["a" "b"] 6 x
2121+ # and
2222+ (x.${f p}."example.com" or 6) == attrByPath [ (f p) "example.com" ] 6 x
2323+ ```
2424+1725 Example:
1826 x = { a = { b = 3; }; }
1927 # ["a" "b"] is equivalent to x.a.b
···5058 attrByPath' 0 set;
51595260 /* Return if an attribute from nested attribute set exists.
6161+6262+ Nix has a [has attribute operator `?`](https://nixos.org/manual/nix/stable/language/operators#has-attribute), which is sufficient for such queries, as long as the number of attributes is static. For example:
6363+6464+ ```nix
6565+ (x?a.b) == hasAttryByPath ["a" "b"] x
6666+ # and
6767+ (x?${f p}."example.com") == hasAttryByPath [ (f p) "example.com" ] x
6868+ ```
53695470 **Laws**:
5571 1. ```nix
···176192177193 /* Like `attrByPath`, but without a default value. If it doesn't find the
178194 path it will throw an error.
195195+196196+ Nix has an [attribute selection operator](https://nixos.org/manual/nix/stable/language/operators#attribute-selection) which is sufficient for such queries, as long as the number of attributes is static. For example:
197197+198198+ ```nix
199199+ x.a.b == getAttrByPath ["a" "b"] x
200200+ # and
201201+ x.${f p}."example.com" == getAttrByPath [ (f p) "example.com" ] x
202202+ ```
179203180204 Example:
181205 x = { a = { b = 3; }; }
+17-41
lib/fileset/default.nix
···107107 _printFileset
108108 _intersection
109109 _difference
110110- _mirrorStorePath
110110+ _fromFetchGit
111111 _fetchGitSubmodulesMinver
112112 _emptyWithoutBase
113113 ;
···148148 inherit (lib.trivial)
149149 isFunction
150150 pipe
151151- inPureEvalMode
152151 ;
153152154153in {
···754753 This directory must contain a `.git` file or subdirectory.
755754 */
756755 path:
757757- # See the gitTrackedWith implementation for more explanatory comments
758758- let
759759- fetchResult = builtins.fetchGit path;
760760- in
761761- if inPureEvalMode then
762762- throw "lib.fileset.gitTracked: This function is currently not supported in pure evaluation mode, since it currently relies on `builtins.fetchGit`. See https://github.com/NixOS/nix/issues/9292."
763763- else if ! isPath path then
764764- throw "lib.fileset.gitTracked: Expected the argument to be a path, but it's a ${typeOf path} instead."
765765- else if ! pathExists (path + "/.git") then
766766- throw "lib.fileset.gitTracked: Expected the argument (${toString path}) to point to a local working tree of a Git repository, but it's not."
767767- else
768768- _mirrorStorePath path fetchResult.outPath;
756756+ _fromFetchGit
757757+ "gitTracked"
758758+ "argument"
759759+ path
760760+ {};
769761770762 /*
771763 Create a file set containing all [Git-tracked files](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository) in a repository.
···807799 This directory must contain a `.git` file or subdirectory.
808800 */
809801 path:
810810- let
811811- # This imports the files unnecessarily, which currently can't be avoided
812812- # because `builtins.fetchGit` is the only function exposing which files are tracked by Git.
813813- # With the [lazy trees PR](https://github.com/NixOS/nix/pull/6530),
814814- # the unnecessarily import could be avoided.
815815- # However a simpler alternative still would be [a builtins.gitLsFiles](https://github.com/NixOS/nix/issues/2944).
816816- fetchResult = builtins.fetchGit {
817817- url = path;
818818-819819- # This is the only `fetchGit` parameter that makes sense in this context.
820820- # We can't just pass `submodules = recurseSubmodules` here because
821821- # this would fail for Nix versions that don't support `submodules`.
822822- ${if recurseSubmodules then "submodules" else null} = true;
823823- };
824824- in
825825- if inPureEvalMode then
826826- throw "lib.fileset.gitTrackedWith: This function is currently not supported in pure evaluation mode, since it currently relies on `builtins.fetchGit`. See https://github.com/NixOS/nix/issues/9292."
827827- else if ! isBool recurseSubmodules then
802802+ if ! isBool recurseSubmodules then
828803 throw "lib.fileset.gitTrackedWith: Expected the attribute `recurseSubmodules` of the first argument to be a boolean, but it's a ${typeOf recurseSubmodules} instead."
829804 else if recurseSubmodules && versionOlder nixVersion _fetchGitSubmodulesMinver then
830805 throw "lib.fileset.gitTrackedWith: Setting the attribute `recurseSubmodules` to `true` is only supported for Nix version ${_fetchGitSubmodulesMinver} and after, but Nix version ${nixVersion} is used."
831831- else if ! isPath path then
832832- throw "lib.fileset.gitTrackedWith: Expected the second argument to be a path, but it's a ${typeOf path} instead."
833833- # We can identify local working directories by checking for .git,
834834- # see https://git-scm.com/docs/gitrepository-layout#_description.
835835- # Note that `builtins.fetchGit` _does_ work for bare repositories (where there's no `.git`),
836836- # even though `git ls-files` wouldn't return any files in that case.
837837- else if ! pathExists (path + "/.git") then
838838- throw "lib.fileset.gitTrackedWith: Expected the second argument (${toString path}) to point to a local working tree of a Git repository, but it's not."
839806 else
840840- _mirrorStorePath path fetchResult.outPath;
807807+ _fromFetchGit
808808+ "gitTrackedWith"
809809+ "second argument"
810810+ path
811811+ # This is the only `fetchGit` parameter that makes sense in this context.
812812+ # We can't just pass `submodules = recurseSubmodules` here because
813813+ # this would fail for Nix versions that don't support `submodules`.
814814+ (lib.optionalAttrs recurseSubmodules {
815815+ submodules = true;
816816+ });
841817}
+33
lib/fileset/internal.nix
···1010 split
1111 trace
1212 typeOf
1313+ fetchGit
1314 ;
14151516 inherit (lib.attrsets)
···5556 hasSuffix
5657 ;
57585959+ inherit (lib.trivial)
6060+ inPureEvalMode
6161+ ;
5862in
5963# Rare case of justified usage of rec:
6064# - This file is internal, so the return value doesn't matter, no need to make things overridable
···852856 in
853857 _create localPath
854858 (recurse storePath);
859859+860860+ # Create a file set from the files included in the result of a fetchGit call
861861+ # Type: String -> String -> Path -> Attrs -> FileSet
862862+ _fromFetchGit = function: argument: path: extraFetchGitAttrs:
863863+ let
864864+ # This imports the files unnecessarily, which currently can't be avoided
865865+ # because `builtins.fetchGit` is the only function exposing which files are tracked by Git.
866866+ # With the [lazy trees PR](https://github.com/NixOS/nix/pull/6530),
867867+ # the unnecessarily import could be avoided.
868868+ # However a simpler alternative still would be [a builtins.gitLsFiles](https://github.com/NixOS/nix/issues/2944).
869869+ fetchResult = fetchGit ({
870870+ url = path;
871871+ } // extraFetchGitAttrs);
872872+ in
873873+ if inPureEvalMode then
874874+ throw "lib.fileset.${function}: This function is currently not supported in pure evaluation mode, since it currently relies on `builtins.fetchGit`. See https://github.com/NixOS/nix/issues/9292."
875875+ else if ! isPath path then
876876+ throw "lib.fileset.${function}: Expected the ${argument} to be a path, but it's a ${typeOf path} instead."
877877+ else if pathType path != "directory" then
878878+ throw "lib.fileset.${function}: Expected the ${argument} (${toString path}) to be a directory, but it's a file instead."
879879+ # We can identify local working directories by checking for .git,
880880+ # see https://git-scm.com/docs/gitrepository-layout#_description.
881881+ # Note that `builtins.fetchGit` _does_ work for bare repositories (where there's no `.git`),
882882+ # even though `git ls-files` wouldn't return any files in that case.
883883+ else if ! pathExists (path + "/.git") then
884884+ throw "lib.fileset.${function}: Expected the ${argument} (${toString path}) to point to a local working tree of a Git repository, but it's not."
885885+ else
886886+ _mirrorStorePath path fetchResult.outPath;
887887+855888}
+6
lib/fileset/tests.sh
···13171317expectFailure 'gitTracked null' 'lib.fileset.gitTracked: Expected the argument to be a path, but it'\''s a null instead.'
13181318expectFailure 'gitTrackedWith {} null' 'lib.fileset.gitTrackedWith: Expected the second argument to be a path, but it'\''s a null instead.'
1319131913201320+# The path must be a directory
13211321+touch a
13221322+expectFailure 'gitTracked ./a' 'lib.fileset.gitTracked: Expected the argument \('"$work"'/a\) to be a directory, but it'\''s a file instead'
13231323+expectFailure 'gitTrackedWith {} ./a' 'lib.fileset.gitTrackedWith: Expected the second argument \('"$work"'/a\) to be a directory, but it'\''s a file instead'
13241324+rm -rf -- *
13251325+13201326# The path has to contain a .git directory
13211327expectFailure 'gitTracked ./.' 'lib.fileset.gitTracked: Expected the argument \('"$work"'\) to point to a local working tree of a Git repository, but it'\''s not.'
13221328expectFailure 'gitTrackedWith {} ./.' 'lib.fileset.gitTrackedWith: Expected the second argument \('"$work"'\) to point to a local working tree of a Git repository, but it'\''s not.'
+15-19
lib/meta.nix
···44{ lib }:
5566let
77- inherit (lib) matchAttrs any all;
88- inherit (builtins) isString;
77+ inherit (lib) matchAttrs any all isDerivation getBin assertMsg;
88+ inherit (builtins) isString match typeOf;
991010in
1111rec {
···154154 getExe pkgs.mustache-go
155155 => "/nix/store/am9ml4f4ywvivxnkiaqwr0hyxka1xjsf-mustache-go-1.3.0/bin/mustache"
156156 */
157157- getExe = x:
158158- let
159159- y = x.meta.mainProgram or (
160160- # This could be turned into an error when 23.05 is at end of life
161161- lib.warn "getExe: Package ${lib.strings.escapeNixIdentifier x.meta.name or x.pname or x.name} does not have the meta.mainProgram attribute. We'll assume that the main program has the same name for now, but this behavior is deprecated, because it leads to surprising errors when the assumption does not hold. If the package has a main program, please set `meta.mainProgram` in its definition to make this warning go away. Otherwise, if the package does not have a main program, or if you don't control its definition, use getExe' to specify the name to the program, such as lib.getExe' foo \"bar\"."
162162- lib.getName
163163- x
164164- );
165165- in
166166- getExe' x y;
157157+ getExe = x: getExe' x (x.meta.mainProgram or (
158158+ # This could be turned into an error when 23.05 is at end of life
159159+ lib.warn "getExe: Package ${lib.strings.escapeNixIdentifier x.meta.name or x.pname or x.name} does not have the meta.mainProgram attribute. We'll assume that the main program has the same name for now, but this behavior is deprecated, because it leads to surprising errors when the assumption does not hold. If the package has a main program, please set `meta.mainProgram` in its definition to make this warning go away. Otherwise, if the package does not have a main program, or if you don't control its definition, use getExe' to specify the name to the program, such as lib.getExe' foo \"bar\"."
160160+ lib.getName
161161+ x
162162+ ));
167163168164 /* Get the path of a program of a derivation.
169165···175171 => "/nix/store/5rs48jamq7k6sal98ymj9l4k2bnwq515-imagemagick-7.1.1-15/bin/convert"
176172 */
177173 getExe' = x: y:
178178- assert lib.assertMsg (lib.isDerivation x)
179179- "lib.meta.getExe': The first argument is of type ${builtins.typeOf x}, but it should be a derivation instead.";
180180- assert lib.assertMsg (lib.isString y)
181181- "lib.meta.getExe': The second argument is of type ${builtins.typeOf y}, but it should be a string instead.";
182182- assert lib.assertMsg (builtins.length (lib.splitString "/" y) == 1)
183183- "lib.meta.getExe': The second argument \"${y}\" is a nested path with a \"/\" character, but it should just be the name of the executable instead.";
184184- "${lib.getBin x}/bin/${y}";
174174+ assert assertMsg (isDerivation x)
175175+ "lib.meta.getExe': The first argument is of type ${typeOf x}, but it should be a derivation instead.";
176176+ assert assertMsg (isString y)
177177+ "lib.meta.getExe': The second argument is of type ${typeOf y}, but it should be a string instead.";
178178+ assert assertMsg (match ".*\/.*" y == null)
179179+ "lib.meta.getExe': The second argument \"${y}\" is a nested path with a \"/\" character, but it should just be the name of the executable instead.";
180180+ "${getBin x}/bin/${y}";
185181}
+81
lib/path/default.nix
···99 split
1010 match
1111 typeOf
1212+ storeDir
1213 ;
13141415 inherit (lib.lists)
···2324 take
2425 drop
2526 ;
2727+2828+ listHasPrefix = lib.lists.hasPrefix;
26292730 inherit (lib.strings)
2831 concatStringsSep
···119122 if base == dirOf base then { root = base; inherit components; }
120123 else recurse ([ (baseNameOf base) ] ++ components) (dirOf base);
121124 in recurse [];
125125+126126+ # The components of the store directory, typically [ "nix" "store" ]
127127+ storeDirComponents = splitRelPath ("./" + storeDir);
128128+ # The number of store directory components, typically 2
129129+ storeDirLength = length storeDirComponents;
130130+131131+ # Type: [ String ] -> Bool
132132+ #
133133+ # Whether path components have a store path as a prefix, according to
134134+ # https://nixos.org/manual/nix/stable/store/store-path.html#store-path.
135135+ componentsHaveStorePathPrefix = components:
136136+ # path starts with the store directory (typically /nix/store)
137137+ listHasPrefix storeDirComponents components
138138+ # is not the store directory itself, meaning there's at least one extra component
139139+ && storeDirComponents != components
140140+ # and the first component after the store directory has the expected format.
141141+ # NOTE: We could change the hash regex to be [0-9a-df-np-sv-z],
142142+ # because these are the actual ASCII characters used by Nix's base32 implementation,
143143+ # but this is not fully specified, so let's tie this too much to the currently implemented concept of store paths.
144144+ # Similar reasoning applies to the validity of the name part.
145145+ # We care more about discerning store path-ness on realistic values. Making it airtight would be fragile and slow.
146146+ && match ".{32}-.+" (elemAt components storeDirLength) != null;
122147123148in /* No rec! Add dependencies on this file at the top. */ {
124149···320345 root = deconstructed.root;
321346 subpath = joinRelPath deconstructed.components;
322347 };
348348+349349+ /*
350350+ Whether a [path](https://nixos.org/manual/nix/stable/language/values.html#type-path)
351351+ has a [store path](https://nixos.org/manual/nix/stable/store/store-path.html#store-path)
352352+ as a prefix.
353353+354354+ :::{.note}
355355+ As with all functions of this `lib.path` library, it does not work on paths in strings,
356356+ which is how you'd typically get store paths.
357357+358358+ Instead, this function only handles path values themselves,
359359+ which occur when Nix files in the store use relative path expressions.
360360+ :::
361361+362362+ Type:
363363+ hasStorePathPrefix :: Path -> Bool
364364+365365+ Example:
366366+ # Subpaths of derivation outputs have a store path as a prefix
367367+ hasStorePathPrefix /nix/store/nvl9ic0pj1fpyln3zaqrf4cclbqdfn1j-foo/bar/baz
368368+ => true
369369+370370+ # The store directory itself is not a store path
371371+ hasStorePathPrefix /nix/store
372372+ => false
373373+374374+ # Derivation outputs are store paths themselves
375375+ hasStorePathPrefix /nix/store/nvl9ic0pj1fpyln3zaqrf4cclbqdfn1j-foo
376376+ => true
377377+378378+ # Paths outside the Nix store don't have a store path prefix
379379+ hasStorePathPrefix /home/user
380380+ => false
381381+382382+ # Not all paths under the Nix store are store paths
383383+ hasStorePathPrefix /nix/store/.links/10gg8k3rmbw8p7gszarbk7qyd9jwxhcfq9i6s5i0qikx8alkk4hq
384384+ => false
385385+386386+ # Store derivations are also store paths themselves
387387+ hasStorePathPrefix /nix/store/nvl9ic0pj1fpyln3zaqrf4cclbqdfn1j-foo.drv
388388+ => true
389389+ */
390390+ hasStorePathPrefix = path:
391391+ let
392392+ deconstructed = deconstructPath path;
393393+ in
394394+ assert assertMsg
395395+ (isPath path)
396396+ "lib.path.hasStorePathPrefix: Argument is of type ${typeOf path}, but a path was expected";
397397+ assert assertMsg
398398+ # This function likely breaks or needs adjustment if used with other filesystem roots, if they ever get implemented.
399399+ # Let's try to error nicely in such a case, though it's unclear how an implementation would work even and whether this could be detected.
400400+ # See also https://github.com/NixOS/nix/pull/6530#discussion_r1422843117
401401+ (deconstructed.root == /. && toString deconstructed.root == "/")
402402+ "lib.path.hasStorePathPrefix: Argument has a filesystem root (${toString deconstructed.root}) that's not /, which is currently not supported.";
403403+ componentsHaveStorePathPrefix deconstructed.components;
323404324405 /*
325406 Whether a value is a valid subpath string.
···8989 # is why we use the more obscure "bfd" and not "binutils" for this
9090 # choice.
9191 else "bfd";
9292+ # The standard lib directory name that non-nixpkgs binaries distributed
9393+ # for this platform normally assume.
9494+ libDir = if final.isLinux then
9595+ if final.isx86_64 || final.isMips64 || final.isPower64
9696+ then "lib64"
9797+ else "lib"
9898+ else null;
9299 extensions = lib.optionalAttrs final.hasSharedLibraries {
93100 sharedLibrary =
94101 if final.isDarwin then ".dylib"
···11+#!/usr/bin/env nix-shell
22+#!nix-shell -i zsh -p zsh
33+set -euo pipefail
44+55+# cd into nixpkgs' root, get the store path of `systemd.man`
66+cd "$(dirname "$0")/../../.."
77+SYSTEMD_MAN_DIR="$(nix-build -A systemd.man)/share/man"
88+99+# For each manual section
1010+for section in {1..8}; do
1111+ sec_dir="${SYSTEMD_MAN_DIR}/man${section}"
1212+1313+ # skip section 3 (library calls)
1414+ ! [[ $section -eq 3 ]] || continue
1515+1616+ # for each manpage in that section (potentially none)
1717+ for manpage in ${sec_dir}/*(N); do
1818+ # strip the directory prefix and (compressed) manpage suffix
1919+ page="$(basename "$manpage" ".${section}.gz")"
2020+2121+ # if this is the manpage of a service unit
2222+ if [[ "$page" =~ ".*\.service" ]]; then
2323+ # ... and a manpage exists without the `.service` suffix
2424+ potential_alias="${sec_dir}/${page%\.service}.${section}.gz"
2525+ ! [[ -e "${potential_alias}" &&
2626+ # ... which points to the same file, then skip
2727+ "$(gunzip -c "${potential_alias}")" == ".so ${page}.${section}" ]] || continue
2828+ fi
2929+3030+ # else produce a JSON fragment, with the link to the upstream manpage (as HTML)
3131+ echo " \"${page}(${section})\": \"https://www.freedesktop.org/software/systemd/man/${page}.html\","
3232+ done
3333+done
···11+# NixOS {#sec-nixos-state}
22+33+## `/nix` {#sec-state-nix}
44+55+NixOS needs the entirety of `/nix` to be persistent, as it includes:
66+- `/nix/store`, which contains all the system's executables, libraries, and supporting data;
77+- `/nix/var/nix`, which contains:
88+ - the Nix daemon's database;
99+ - roots whose transitive closure is preserved when garbage-collecting the Nix store;
1010+ - system-wide and per-user profiles.
1111+1212+## `/boot` {#sec-state-boot}
1313+1414+`/boot` should also be persistent, as it contains:
1515+- the kernel and initrd which the bootloader loads,
1616+- the bootloader's configuration, including the kernel's command-line which
1717+ determines the store path to use as system environment.
1818+1919+2020+## Users and groups {#sec-state-users}
2121+2222+- `/var/lib/nixos` should persist: it holds state needed to generate stable
2323+ uids and gids for declaratively-managed users and groups, etc.
2424+- `users.mutableUsers` should be false, *or* the following files under `/etc`
2525+ should all persist:
2626+ - {manpage}`passwd(5)` and {manpage}`group(5)`,
2727+ - {manpage}`shadow(5)` and {manpage}`gshadow(5)`,
2828+ - {manpage}`subuid(5)` and {manpage}`subgid(5)`.
···11+# Necessary system state {#ch-system-state}
22+33+Normally — on systems with a persistent `rootfs` — system services can persist state to
44+the filesystem without administrator intervention.
55+66+However, it is possible and not-uncommon to create [impermanent systems], whose
77+`rootfs` is either a `tmpfs` or reset during boot. While NixOS itself supports
88+this kind of configuration, special care needs to be taken.
99+1010+[impermanent systems]: https://nixos.wiki/wiki/Impermanence
1111+1212+1313+```{=include=} sections
1414+nixos-state.section.md
1515+systemd-state.section.md
1616+zfs-state.section.md
1717+```
···11+# systemd {#sec-systemd-state}
22+33+## `machine-id(5)` {#sec-machine-id}
44+55+`systemd` uses per-machine identifier — {manpage}`machine-id(5)` — which must be
66+unique and persistent; otherwise, the system journal may fail to list earlier
77+boots, etc.
88+99+`systemd` generates a random `machine-id(5)` during boot if it does not already exist,
1010+and persists it in `/etc/machine-id`. As such, it suffices to make that file persistent.
1111+1212+Alternatively, it is possible to generate a random `machine-id(5)`; while the
1313+specification allows for *any* hex-encoded 128b value, systemd itself uses
1414+[UUIDv4], *i.e.* random UUIDs, and it is thus preferable to do so as well, in
1515+case some software assumes `machine-id(5)` to be a UUIDv4. Those can be
1616+generated with `uuidgen -r | tr -d -` (`tr` being used to remove the dashes).
1717+1818+Such a `machine-id(5)` can be set by writing it to `/etc/machine-id` or through
1919+the kernel's command-line, though NixOS' systemd maintainers [discourage] the
2020+latter approach.
2121+2222+[UUIDv4]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
2323+[discourage]: https://github.com/NixOS/nixpkgs/pull/268995
2424+2525+2626+## `/var/lib/systemd` {#sec-var-systemd}
2727+2828+Moreover, `systemd` expects its state directory — `/var/lib/systemd` — to persist, for:
2929+- {manpage}`systemd-random-seed(8)`, which loads a 256b “seed” into the kernel's RNG
3030+ at boot time, and saves a fresh one during shutdown;
3131+- {manpage}`systemd.timer(5)` with `Persistent=yes`, which are then run after boot if
3232+ the timer would have triggered during the time the system was shut down;
3333+- {manpage}`systemd-coredump(8)` to store core dumps there by default;
3434+ (see {manpage}`coredump.conf(5)`)
3535+- {manpage}`systemd-timesyncd(8)`;
3636+- {manpage}`systemd-backlight(8)` and {manpage}`systemd-rfkill(8)` persist hardware-related
3737+ state;
3838+- possibly other things, this list is not meant to be exhaustive.
3939+4040+In any case, making `/var/lib/systemd` persistent is recommended.
4141+4242+4343+## `/var/log/journal/{machine-id}` {#sec-var-journal}
4444+4545+Lastly, {manpage}`systemd-journald(8)` writes the system's journal in binary
4646+form to `/var/log/journal/{machine-id}`; if (locally) persisting the entire log
4747+is desired, it is recommended to make all of `/var/log/journal` persistent.
4848+4949+If not, one can set `Storage=volatile` in {manpage}`journald.conf(5)`
5050+([`services.journald.storage = "volatile";`](#opt-services.journald.storage)),
5151+which disables journal persistence and causes it to be written to
5252+`/run/log/journal`.
···11+# ZFS {#sec-zfs-state}
22+33+When using ZFS, `/etc/zfs/zpool.cache` should be persistent (or a symlink to a persistent
44+location) as it is the default value for the `cachefile` [property](man:zpoolprops(7)).
55+66+This cachefile is used on system startup to discover ZFS pools, so ZFS pools
77+holding the `rootfs` and/or early-boot datasets such as `/nix` can be set to
88+`cachefile=none`.
99+1010+In principle, if there are no other pools attached to the system, `zpool.cache`
1111+does not need to be persisted; it is however *strongly recommended* to persist
1212+it, in case additional pools are added later on, temporarily or permanently:
1313+1414+While mishandling the cachefile does not lead to data loss by itself, it may
1515+cause zpools not to be imported during boot, and services may then write to a
1616+location where a dataset was expected to be mounted.
+4
nixos/doc/manual/release-notes/rl-2405.section.md
···10101111- `screen`'s module has been cleaned, and will now require you to set `programs.screen.enable` in order to populate `screenrc` and add the program to the environment.
12121313+- NixOS now installs a stub ELF loader that prints an informative error message when users attempt to run binaries not made for NixOS.
1414+ - This can be disabled through the `environment.stub-ld.enable` option.
1515+ - If you use `programs.nix-ld.enable`, no changes are needed. The stub will be disabled automatically.
1616+1317## New Services {#sec-release-24.05-new-services}
14181519<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
+58
nixos/modules/config/ldso.nix
···11+{ config, lib, pkgs, ... }:
22+33+let
44+ inherit (lib) last splitString mkOption types mdDoc optionals;
55+66+ libDir = pkgs.stdenv.hostPlatform.libDir;
77+ ldsoBasename = last (splitString "/" pkgs.stdenv.cc.bintools.dynamicLinker);
88+99+ pkgs32 = pkgs.pkgsi686Linux;
1010+ libDir32 = pkgs32.stdenv.hostPlatform.libDir;
1111+ ldsoBasename32 = last (splitString "/" pkgs32.stdenv.cc.bintools.dynamicLinker);
1212+in {
1313+ options = {
1414+ environment.ldso = mkOption {
1515+ type = types.nullOr types.path;
1616+ default = null;
1717+ description = mdDoc ''
1818+ The executable to link into the normal FHS location of the ELF loader.
1919+ '';
2020+ };
2121+2222+ environment.ldso32 = mkOption {
2323+ type = types.nullOr types.path;
2424+ default = null;
2525+ description = mdDoc ''
2626+ The executable to link into the normal FHS location of the 32-bit ELF loader.
2727+2828+ This currently only works on x86_64 architectures.
2929+ '';
3030+ };
3131+ };
3232+3333+ config = {
3434+ assertions = [
3535+ { assertion = isNull config.environment.ldso32 || pkgs.stdenv.isx86_64;
3636+ message = "Option environment.ldso32 currently only works on x86_64.";
3737+ }
3838+ ];
3939+4040+ systemd.tmpfiles.rules = (
4141+ if isNull config.environment.ldso then [
4242+ "r /${libDir}/${ldsoBasename} - - - - -"
4343+ ] else [
4444+ "d /${libDir} 0755 root root - -"
4545+ "L+ /${libDir}/${ldsoBasename} - - - - ${config.environment.ldso}"
4646+ ]
4747+ ) ++ optionals pkgs.stdenv.isx86_64 (
4848+ if isNull config.environment.ldso32 then [
4949+ "r /${libDir32}/${ldsoBasename32} - - - - -"
5050+ ] else [
5151+ "d /${libDir32} 0755 root root - -"
5252+ "L+ /${libDir32}/${ldsoBasename32} - - - - ${config.environment.ldso32}"
5353+ ]
5454+ );
5555+ };
5656+5757+ meta.maintainers = with lib.maintainers; [ tejing ];
5858+}
+56
nixos/modules/config/stub-ld.nix
···11+{ config, lib, pkgs, ... }:
22+33+let
44+ inherit (lib) optionalString mkOption types mdDoc mkIf mkDefault;
55+66+ cfg = config.environment.stub-ld;
77+88+ message = ''
99+ NixOS cannot run dynamically linked executables intended for generic
1010+ linux environments out of the box. For more information, see:
1111+ https://nix.dev/permalink/stub-ld
1212+ '';
1313+1414+ stub-ld-for = pkgsArg: messageArg: pkgsArg.pkgsStatic.runCommandCC "stub-ld" {
1515+ nativeBuildInputs = [ pkgsArg.unixtools.xxd ];
1616+ inherit messageArg;
1717+ } ''
1818+ printf "%s" "$messageArg" | xxd -i -n message >main.c
1919+ cat <<EOF >>main.c
2020+ #include <stdio.h>
2121+ int main(int argc, char * argv[]) {
2222+ fprintf(stderr, "Could not start dynamically linked executable: %s\n", argv[0]);
2323+ fwrite(message, sizeof(unsigned char), message_len, stderr);
2424+ return 127; // matches behavior of bash and zsh without a loader. fish uses 139
2525+ }
2626+ EOF
2727+ $CC -Os main.c -o $out
2828+ '';
2929+3030+ pkgs32 = pkgs.pkgsi686Linux;
3131+3232+ stub-ld = stub-ld-for pkgs message;
3333+ stub-ld32 = stub-ld-for pkgs32 message;
3434+in {
3535+ options = {
3636+ environment.stub-ld = {
3737+ enable = mkOption {
3838+ type = types.bool;
3939+ default = true;
4040+ example = false;
4141+ description = mdDoc ''
4242+ Install a stub ELF loader to print an informative error message
4343+ in the event that a user attempts to run an ELF binary not
4444+ compiled for NixOS.
4545+ '';
4646+ };
4747+ };
4848+ };
4949+5050+ config = mkIf cfg.enable {
5151+ environment.ldso = mkDefault stub-ld;
5252+ environment.ldso32 = mkIf pkgs.stdenv.isx86_64 (mkDefault stub-ld32);
5353+ };
5454+5555+ meta.maintainers = with lib.maintainers; [ tejing ];
5656+}
···14351435 remote_timeout = mkOpt types.str ''
14361436 Timeout for requests to the remote write endpoint.
14371437 '';
14381438+ headers = mkOpt (types.attrsOf types.str) ''
14391439+ Custom HTTP headers to be sent along with each remote write request.
14401440+ Be aware that headers that are set by Prometheus itself can't be overwritten.
14411441+ '';
14381442 write_relabel_configs = mkOpt (types.listOf promTypes.relabel_config) ''
14391443 List of remote write relabel configurations.
14401444 '';
···15291533 '';
15301534 remote_timeout = mkOpt types.str ''
15311535 Timeout for requests to the remote read endpoint.
15361536+ '';
15371537+ headers = mkOpt (types.attrsOf types.str) ''
15381538+ Custom HTTP headers to be sent along with each remote read request.
15391539+ Be aware that headers that are set by Prometheus itself can't be overwritten.
15321540 '';
15331541 read_recent = mkOpt types.bool ''
15341542 Whether reads should be made for queries for time ranges that
···2020 , extraScripts ? []
2121 , ... }@args:
2222 let
2323+ strippedName = with builtins;
2424+ let groups = match "mpv[-_](.*)" pname; in
2525+ if groups != null
2626+ then head groups
2727+ else pname
2828+ ;
2329 # either passthru.scriptName, inferred from scriptPath, or from pname
2430 scriptName = (args.passthru or {}).scriptName or (
2531 if args ? scriptPath
2632 then fileName args.scriptPath
2727- else "${pname}.lua"
3333+ else "${strippedName}.lua"
2834 );
2935 scriptPath = args.scriptPath or "./${scriptName}";
3036 in {
···1414 };
15151616 meta = {
1717+ description = "Automatically skips chapters based on title";
1818+ longDescription = ''
1919+ MPV script that skips chapters based on their title, categorized using regexes.
2020+ The set of skipped categories can be configured globally, or by an auto-profile.
2121+ '';
1722 homepage = "https://github.com/po5/chapterskip";
2323+ license = lib.licenses.unfree; # https://github.com/po5/chapterskip/issues/10
1824 maintainers = with lib.maintainers; [ nicoo ];
1925 };
2026}
···11+{ lib
22+, stdenvNoCC
33+, fetchFromGitHub
44+, nixosTests
55+, gitUpdater
66+}:
77+88+stdenvNoCC.mkDerivation rec {
99+ pname = "noto-fonts-cjk-sans";
1010+ version = "2.004";
1111+1212+ src = fetchFromGitHub {
1313+ owner = "notofonts";
1414+ repo = "noto-cjk";
1515+ rev = "Sans${version}";
1616+ hash = "sha256-IgalJkiOAVjNxKaPAQWfb5hKeqclliR4qVXCq63FGWY=";
1717+ sparseCheckout = [ "Sans/Variable/OTC" ];
1818+ };
1919+2020+ installPhase = ''
2121+ install -m444 -Dt $out/share/fonts/opentype/noto-cjk Sans/Variable/OTC/*.otf.ttc
2222+ '';
2323+2424+ passthru.tests.noto-fonts = nixosTests.noto-fonts;
2525+2626+ passthru.updateScript = gitUpdater {
2727+ rev-prefix = "Sans";
2828+ };
2929+3030+ meta = {
3131+ description = "Beautiful and free fonts for CJK languages";
3232+ homepage = "https://www.google.com/get/noto/help/cjk/";
3333+ longDescription = ''
3434+ Noto Sans CJK is a sans typeface designed as
3535+ an intermediate style between the modern and traditional. It is
3636+ intended to be a multi-purpose digital font for user interface
3737+ designs, digital content, reading on laptops, mobile devices, and
3838+ electronic books. Noto Sans CJK comprehensively covers
3939+ Simplified Chinese, Traditional Chinese, Japanese, and Korean in a
4040+ unified font family. It supports regional variants of ideographic
4141+ characters for each of the four languages. In addition, it supports
4242+ Japanese kana, vertical forms, and variant characters (itaiji); it
4343+ supports Korean hangeul — both contemporary and archaic.
4444+ '';
4545+ license = lib.licenses.ofl;
4646+ platforms = lib.platforms.all;
4747+ maintainers = with lib.maintainers; [ mathnerd314 emily ];
4848+ };
4949+}
+49
pkgs/by-name/no/noto-fonts-cjk-serif/package.nix
···11+{ lib
22+, stdenvNoCC
33+, fetchFromGitHub
44+, nixosTests
55+, gitUpdater
66+}:
77+88+stdenvNoCC.mkDerivation rec {
99+ pname = "noto-fonts-cjk-serif";
1010+ version = "2.002";
1111+1212+ src = fetchFromGitHub {
1313+ owner = "notofonts";
1414+ repo = "noto-cjk";
1515+ rev = "Serif${version}";
1616+ hash = "sha256-GLjpTAiHfygj1J4AdUVDJh8kykkFOglq+h4kyat5W9s=";
1717+ sparseCheckout = [ "Serif/Variable/OTC" ];
1818+ };
1919+2020+ installPhase = ''
2121+ install -m444 -Dt $out/share/fonts/opentype/noto-cjk Serif/Variable/OTC/*.otf.ttc
2222+ '';
2323+2424+ passthru.tests.noto-fonts = nixosTests.noto-fonts;
2525+2626+ passthru.updateScript = gitUpdater {
2727+ rev-prefix = "Serif";
2828+ };
2929+3030+ meta = with lib; {
3131+ description = "Beautiful and free fonts for CJK languages";
3232+ homepage = "https://www.google.com/get/noto/help/cjk/";
3333+ longDescription = ''
3434+ Noto Serif CJK is a serif typeface designed as
3535+ an intermediate style between the modern and traditional. It is
3636+ intended to be a multi-purpose digital font for user interface
3737+ designs, digital content, reading on laptops, mobile devices, and
3838+ electronic books. Noto Serif CJK comprehensively covers
3939+ Simplified Chinese, Traditional Chinese, Japanese, and Korean in a
4040+ unified font family. It supports regional variants of ideographic
4141+ characters for each of the four languages. In addition, it supports
4242+ Japanese kana, vertical forms, and variant characters (itaiji); it
4343+ supports Korean hangeul — both contemporary and archaic.
4444+ '';
4545+ license = licenses.ofl;
4646+ platforms = platforms.all;
4747+ maintainers = with maintainers; [ mathnerd314 emily ];
4848+ };
4949+}
···11+{ lib
22+, stdenvNoCC
33+, fetchFromGitHub
44+, gitUpdater
55+, variants ? [ ]
66+, suffix ? ""
77+, longDescription ? ''
88+ When text is rendered by a computer, sometimes characters are
99+ displayed as “tofu”. They are little boxes to indicate your device
1010+ doesn’t have a font to display the text.
1111+ Google has been developing a font family called Noto, which aims to
1212+ support all languages with a harmonious look and feel. Noto is
1313+ Google’s answer to tofu. The name noto is to convey the idea that
1414+ Google’s goal is to see “no more tofu”. Noto has multiple styles and
1515+ weights, and freely available to all.
1616+ ''
1717+}:
1818+1919+stdenvNoCC.mkDerivation rec {
2020+ pname = "noto-fonts${suffix}";
2121+ version = "23.11.1";
2222+2323+ src = fetchFromGitHub {
2424+ owner = "notofonts";
2525+ repo = "notofonts.github.io";
2626+ rev = "noto-monthly-release-${version}";
2727+ hash = "sha256-qBHLCOfVBOn9CV194S4cYw9nhHyAe2AUBJHQMvyEfW8=";
2828+ };
2929+3030+ _variants = map (variant: builtins.replaceStrings [ " " ] [ "" ] variant) variants;
3131+3232+ installPhase = ''
3333+ # We check availability in order of variable -> otf -> ttf
3434+ # unhinted -- the hinted versions use autohint
3535+ # maintaining maximum coverage.
3636+ #
3737+ # We have a mix of otf and ttf fonts
3838+ local out_font=$out/share/fonts/noto
3939+ '' + (if _variants == [ ] then ''
4040+ for folder in $(ls -d fonts/*/); do
4141+ if [[ -d "$folder"unhinted/variable-ttf ]]; then
4242+ install -m444 -Dt $out_font "$folder"unhinted/variable-ttf/*.ttf
4343+ elif [[ -d "$folder"unhinted/otf ]]; then
4444+ install -m444 -Dt $out_font "$folder"unhinted/otf/*.otf
4545+ else
4646+ install -m444 -Dt $out_font "$folder"unhinted/ttf/*.ttf
4747+ fi
4848+ done
4949+ '' else ''
5050+ for variant in $_variants; do
5151+ if [[ -d fonts/"$variant"/unhinted/variable-ttf ]]; then
5252+ install -m444 -Dt $out_font fonts/"$variant"/unhinted/variable-ttf/*.ttf
5353+ elif [[ -d fonts/"$variant"/unhinted/otf ]]; then
5454+ install -m444 -Dt $out_font fonts/"$variant"/unhinted/otf/*.otf
5555+ else
5656+ install -m444 -Dt $out_font fonts/"$variant"/unhinted/ttf/*.ttf
5757+ fi
5858+ done
5959+ '');
6060+6161+ passthru.updateScript = gitUpdater {
6262+ rev-prefix = "noto-monthly-release-";
6363+ };
6464+6565+ meta = {
6666+ description = "Beautiful and free fonts for many languages";
6767+ homepage = "https://www.google.com/get/noto/";
6868+ inherit longDescription;
6969+ license = lib.licenses.ofl;
7070+ platforms = lib.platforms.all;
7171+ maintainers = with lib.maintainers; [ mathnerd314 emily jopejoe1 ];
7272+ };
7373+}
···258258 rm $out/host-linux-x64/libstdc++.so*
259259 ''}
260260 ${
261261- lib.optionalString (lib.versionAtLeast version "11.8")
261261+ lib.optionalString (lib.versionAtLeast version "11.8" && lib.versionOlder version "12")
262262 # error: auto-patchelf could not satisfy dependency libtiff.so.5 wanted by /nix/store/.......-cudatoolkit-12.0.1/host-linux-x64/Plugins/imageformats/libqtiff.so
263263 # we only ship libtiff.so.6, so let's use qt plugins built by Nix.
264264 # TODO: don't copy, come up with a symlink-based "merge"
265265 ''
266266 rsync ${lib.getLib qt6Packages.qtimageformats}/lib/qt-6/plugins/ $out/host-linux-x64/Plugins/ -aP
267267+ ''
268268+ }
269269+ ${
270270+ lib.optionalString (lib.versionAtLeast version "12")
271271+ # Use Qt plugins built by Nix.
272272+ ''
273273+ for qtlib in $out/host-linux-x64/Plugins/*/libq*.so; do
274274+ qtdir=$(basename $(dirname $qtlib))
275275+ filename=$(basename $qtlib)
276276+ for qtpkgdir in ${lib.concatMapStringsSep " " (x: qt6Packages.${x}) ["qtbase" "qtimageformats" "qtsvg" "qtwayland"]}; do
277277+ if [ -e $qtpkgdir/lib/qt-6/plugins/$qtdir/$filename ]; then
278278+ ln -snf $qtpkgdir/lib/qt-6/plugins/$qtdir/$filename $qtlib
279279+ fi
280280+ done
281281+ done
267282 ''
268283 }
269284···336351 wrapProgram "$out/bin/$b" \
337352 --set GDK_PIXBUF_MODULE_FILE "$GDK_PIXBUF_MODULE_FILE"
338353 done
354354+ ${
355355+ lib.optionalString (lib.versionAtLeast version "12")
356356+ # Check we don't have any lurking vendored qt libraries that weren't
357357+ # replaced during installPhase
358358+ ''
359359+ qtlibfiles=$(find $out -name "libq*.so" -type f)
360360+ if [ ! -z "$qtlibfiles" ]; then
361361+ echo "Found unexpected vendored Qt library files in $out" >&2
362362+ echo $qtlibfiles >&2
363363+ echo "These should be replaced with symlinks in installPhase" >&2
364364+ exit 1
365365+ fi
366366+ ''
367367+ }
339368 '';
340369341370 # cuda-gdb doesn't run correctly when not using sandboxing, so
···170170 ''
171171 # Handle the existence of libPath, which requires us to re-arrange the lib directory
172172 + strings.optionalString (libPath != null) ''
173173- if [[ ! -d "${libPath}" ]] ; then
174174- echo "${finalAttrs.pname}: ${libPath} does not exist, only found:" >&2
175175- find "$(dirname ${libPath})"/ -maxdepth 1 >&2
173173+ full_lib_path="lib/${libPath}"
174174+ if [[ ! -d "$full_lib_path" ]] ; then
175175+ echo "${finalAttrs.pname}: '$full_lib_path' does not exist, only found:" >&2
176176+ find lib/ -mindepth 1 -maxdepth 1 >&2
176177 echo "This release might not support your CUDA version" >&2
177178 exit 1
178179 fi
179179- mv "lib/${libPath}" lib_new
180180+ echo "Making libPath '$full_lib_path' the root of lib" >&2
181181+ mv "$full_lib_path" lib_new
180182 rm -r lib
181183 mv lib_new lib
182184 ''
···187189 ''
188190 # Move the outputs into their respective outputs.
189191 + strings.concatMapStringsSep "\n" mkMoveToOutputCommand (builtins.tail finalAttrs.outputs)
192192+ # Add a newline to the end of the installPhase, so that the post-install hook doesn't
193193+ # get concatenated with the last moveToOutput command.
194194+ + "\n"
190195 # Post-install hook
191196 + ''
192197 runHook postInstall
···4040 version = "146";
4141 buildVersion = makeBuildVersion version;
42424343+ gradleWithJdk = gradle.override { java = jdk; };
4444+4345 selectedGlew = if enableWayland then glew-egl else glew;
44464547 Mindustry = fetchFromGitHub {
···114116 inherit version unpackPhase patches;
115117 postPatch = cleanupMindustrySrc;
116118117117- nativeBuildInputs = [ gradle perl ];
119119+ nativeBuildInputs = [ gradleWithJdk perl ];
118120 # Here we download dependencies for both the server and the client so
119121 # we only have to specify one hash for 'deps'. Deps can be garbage
120122 # collected after the build, so this is not really an issue.
···149151 ];
150152 nativeBuildInputs = [
151153 pkg-config
152152- gradle
154154+ gradleWithJdk
153155 makeWrapper
154156 jdk
155157 ] ++ lib.optionals enableClient [
···5566rustPlatform.buildRustPackage rec {
77 pname = "automatic-timezoned";
88- version = "1.0.131";
88+ version = "1.0.137";
991010 src = fetchFromGitHub {
1111 owner = "maxbrunet";
1212 repo = pname;
1313 rev = "v${version}";
1414- sha256 = "sha256-92OpvUt+0iN+UdEGjDdVCjUUlbuOjUgOjc+DGMUnx9U=";
1414+ sha256 = "sha256-+/P+pt79kGIr399c3oTwqbvtMc1nJNRhBYmYJsLrmDg=";
1515 };
16161717- cargoHash = "sha256-FaQwxt3XcDOXlzcKEdMyE9TpmGykQOnJdxtM3EqMpfU=";
1717+ cargoHash = "sha256-QCWlyuoogrU09JvP+X5If1KcYjaoL0zVhBexXwSqc1U=";
18181919 meta = with lib; {
2020 description = "Automatically update system timezone based on location";
+3
pkgs/top-level/aliases.nix
···372372 hepmc = throw "'hepmc' has been renamed to/replaced by 'hepmc2'"; # Converted to throw 2023-09-10
373373 hip = throw "'hip' has been removed in favor of 'rocmPackages.clr'"; # Added 2023-10-08
374374 hipcc = throw "'hipcc' has been replaced with 'rocmPackages.hipcc'"; # Added 2023-10-08
375375+ hipchat = throw "'hipchat' has been discontinued since 2019; upstream recommends Slack."; # Added 2023-12-02
375376 hipify = throw "'hipify' has been replaced with 'rocmPackages.hipify'"; # Added 2023-10-08
376377 hipcub = throw "'hipcub' has been replaced with 'rocmPackages.hipcub'"; # Added 2023-10-08
377378 hipsparse = throw "'hipsparse' has been replaced with 'rocmPackages.hipsparse'"; # Added 2023-10-08
···598599 miopen-hip = throw "'miopen-hip' has been replaced with 'rocmPackages.miopen-hip'"; # Added 2023-10-08
599600 miopen-opencl = throw "'miopen-opencl' has been replaced with 'rocmPackages.miopen-opencl'"; # Added 2023-10-08
600601 mime-types = mailcap; # Added 2022-01-21
602602+ minetestclient_5 = minetestclient; # Added 2023-12-11
603603+ minetestserver_5 = minetestserver; # Added 2023-12-11
601604 minizip2 = pkgs.minizip-ng; # Added 2022-12-28
602605 mirage-im = throw "'mirage-im' has been removed, as it was broken and unmaintained"; # Added 2023-11-26
603606 monero = monero-cli; # Added 2021-11-28