staging-nixos merge for 2026-02-16 (#490990)

This commit is contained in:
K900
2026-02-16 10:33:38 +00:00
committed by GitHub
30 changed files with 335 additions and 167 deletions
+30 -6
View File
@@ -62,6 +62,19 @@ in
config = lib.mkIf cfg.enable {
warnings = lib.optional (cfg.powerUpCommands != "") ''
powerManagement.powerUpCommands is deprecated due to it having unclear ordering semantics.
It will be removed in NixOS 26.11.
It is recommended to create an explicit systemd oneshot service instead,
that is pulled in at the right time during the boot process.
See https://www.freedesktop.org/software/systemd/man/latest/systemd.special.html
for more information on possible targets that can be used for this.
If you also want to run this service upon waking up from resume, the recommended
method to do so is described here:
https://www.freedesktop.org/software/systemd/man/latest/systemd.special.html#sleep.target
'';
systemd.targets.post-resume = {
description = "Post-Resume Actions";
requires = [ "post-resume.service" ];
@@ -81,14 +94,25 @@ in
serviceConfig.Type = "oneshot";
};
systemd.services.post-boot = {
description = "Post-boot Actions";
# It's not well defined at what point in the bootup sequence this should run
# we should eventually just remove this.
wantedBy = [ "multi-user.target" ];
restartIfChanged = false;
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
${cfg.powerUpCommands}
'';
};
systemd.services.post-resume = {
description = "Post-Resume Actions";
after = [
"suspend.target"
"hibernate.target"
"hybrid-sleep.target"
"suspend-then-hibernate.target"
];
# Pulled in by post-resume.service above
after = [ "sleep.target" ];
script = ''
/run/current-system/systemd/bin/systemctl try-restart --no-block post-resume.target
${cfg.resumeCommands}
@@ -742,6 +742,8 @@ in
};
systemd = {
generatorPath = [ cfg.package ];
sockets.sshd = lib.mkIf cfg.startWhenNeeded {
description = "SSH Socket";
wantedBy = [ "sockets.target" ];
@@ -58,10 +58,6 @@ in
assertion = config.boot.postBootCommands == "";
message = "nixos-init cannot be used with boot.postBootCommands";
}
{
assertion = config.powerManagement.powerUpCommands == "";
message = "nixos-init cannot be used with powerManagement.powerUpCommands";
}
];
})
];
-1
View File
@@ -30,7 +30,6 @@ let
);
postBootCommands = pkgs.writeText "local-cmds" ''
${config.boot.postBootCommands}
${config.powerManagement.powerUpCommands}
'';
};
};
+41 -6
View File
@@ -233,6 +233,8 @@ let
proxy_env = config.networking.proxy.envVars;
json = pkgs.formats.json { };
in
{
@@ -356,6 +358,28 @@ in
'';
};
generatorEnvironment = mkOption {
type = types.attrsOf types.str;
default = { };
example = {
MY_VAR = "my-value";
};
description = ''
Environment variables for systemd generators.
The `PATH` environment variable is populated via `systemd.generatorPath`.
'';
};
generatorPath = mkOption {
type = types.listOf types.package;
default = [ ];
example = lib.literalExpression "[ pkgs.hello ]";
description = ''
Packages added to the `PATH` environment variable of all systemd generators.
'';
};
shutdown = mkOption {
type = types.attrsOf types.path;
default = { };
@@ -636,6 +660,12 @@ in
"systemd/user-preset/00-nixos.preset".text = ''
ignore *
'';
"systemd/generator-environment.json".source =
json.generate "systemd-generator-environment.json" cfg.generatorEnvironment;
"systemd/system-environment-generators/env-generator".source =
"${config.system.nixos-init.package}/bin/env-generator";
};
services.dbus.enable = true;
@@ -683,12 +713,7 @@ in
systemd.managerEnvironment = {
# Doesn't contain systemd itself - everything works so it seems to use the compiled-in value for its tools
# util-linux is needed for the main fsck utility wrapping the fs-specific ones
PATH = lib.makeBinPath (
config.system.fsPackages
++ [ cfg.package.util-linux ]
# systemd-ssh-generator needs sshd in PATH
++ lib.optional config.services.openssh.enable config.services.openssh.package
);
PATH = lib.makeBinPath (config.system.fsPackages ++ [ cfg.package.util-linux ]);
LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
TZDIR = "/etc/zoneinfo";
# If SYSTEMD_UNIT_PATH ends with an empty component (":"), the usual unit load path will be appended to the contents of the variable
@@ -704,6 +729,16 @@ in
DefaultIPAccounting = lib.mkDefault true;
};
# These are needed for systemd-fstab-generator to schedule systemd-fsck@
# units.
systemd.generatorPath = config.system.fsPackages ++ [
cfg.package.util-linux
];
systemd.generatorEnvironment = {
PATH = lib.makeBinPath cfg.generatorPath;
};
system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled [
"DEVTMPFS"
"CGROUPS"
@@ -92,6 +92,7 @@ let
# Declare root explicitly to avoid shellcheck warnings, it comes from the env
declare root
mkdir -p "$root/usr/bin"
mkdir -p "$root/etc" "$root/var/lib"
chmod 0755 "$root/etc" "$root/var/lib"
mkdir -p "$root/var/lib/private" "$root/root" /run/nixos-containers
+2 -3
View File
@@ -19,8 +19,6 @@ in
nodes.machine =
{ pkgs, ... }:
{
imports = lib.optionals (!systemdStage1) [ ./common/auto-format-root-device.nix ];
virtualisation = {
emptyDiskImages = [ 512 ];
useBootLoader = true;
@@ -30,7 +28,6 @@ in
# the new root device is /dev/vdb
# an empty 512MiB drive, containing no Nix store.
mountHostNixStore = true;
fileSystems."/".autoFormat = lib.mkIf systemdStage1 true;
};
boot.loader.systemd-boot.enable = true;
@@ -90,6 +87,8 @@ in
# Create encrypted volume
machine.wait_for_unit("multi-user.target")
machine.succeed("echo "" | cryptsetup luksFormat /dev/vdb --batch-mode")
machine.succeed("echo "" | cryptsetup luksOpen /dev/vdb cryptroot")
machine.succeed("mkfs.ext4 /dev/mapper/cryptroot")
machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-luks-wrong-keyfile.conf")
machine.succeed("sync")
machine.crash()
+5 -1
View File
@@ -5,7 +5,6 @@
nodes.machine =
{ pkgs, ... }:
{
imports = [ ./common/auto-format-root-device.nix ];
# Use systemd-boot
virtualisation = {
@@ -48,7 +47,12 @@
# Create encrypted volume
machine.wait_for_unit("multi-user.target")
machine.succeed("echo -n supersecret | cryptsetup luksFormat -q --iter-time=1 /dev/vdb -")
machine.succeed("echo -n supersecret | cryptsetup luksOpen -q /dev/vdb cryptroot")
machine.succeed("mkfs.ext4 /dev/mapper/cryptroot")
machine.succeed("echo -n supersecret | cryptsetup luksFormat -q --iter-time=1 /dev/vdc -")
machine.succeed("echo -n supersecret | cryptsetup luksOpen -q /dev/vdc cryptroot2")
machine.succeed("mkfs.ext4 /dev/mapper/cryptroot2")
# Boot from the encrypted disk
machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-luks.conf")
+2 -1
View File
@@ -38,7 +38,6 @@ in
};
};
virtualisation.rootDevice = "/dev/mapper/cryptroot";
virtualisation.fileSystems."/".autoFormat = true;
boot.initrd.secrets."/etc/cryptroot.key" = keyfile;
};
};
@@ -47,6 +46,8 @@ in
# Create encrypted volume
machine.wait_for_unit("multi-user.target")
machine.succeed("cryptsetup luksFormat -q --iter-time=1 -d ${keyfile} /dev/vdb")
machine.succeed("cryptsetup luksOpen --key-file ${keyfile} /dev/vdb cryptroot")
machine.succeed("mkfs.ext4 /dev/mapper/cryptroot")
# Boot from the encrypted disk
machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-luks.conf")
+4 -1
View File
@@ -31,7 +31,6 @@
cryptroot2.device = "/dev/vdc";
};
virtualisation.rootDevice = "/dev/mapper/cryptroot";
virtualisation.fileSystems."/".autoFormat = true;
# test mounting device unlocked in initrd after switching root
virtualisation.fileSystems."/cryptroot2".device = "/dev/mapper/cryptroot2";
};
@@ -40,7 +39,11 @@
testScript = ''
# Create encrypted volume
machine.wait_for_unit("multi-user.target")
machine.succeed("echo -n supersecret | cryptsetup luksFormat -q --iter-time=1 /dev/vdb -")
machine.succeed("echo -n supersecret | cryptsetup luksOpen -q /dev/vdb cryptroot")
machine.succeed("mkfs.ext4 /dev/mapper/cryptroot")
machine.succeed("echo -n supersecret | cryptsetup luksFormat -q --iter-time=1 /dev/vdc -")
machine.succeed("echo -n supersecret | cryptsetup luksOpen -q /dev/vdc cryptroot2")
machine.succeed("mkfs.ext4 /dev/mapper/cryptroot2")
+2 -1
View File
@@ -32,7 +32,6 @@
};
};
virtualisation.rootDevice = "/dev/mapper/cryptroot";
virtualisation.fileSystems."/".autoFormat = true;
};
};
@@ -40,6 +39,8 @@
# Create encrypted volume
machine.wait_for_unit("multi-user.target")
machine.succeed("echo -n supersecret | cryptsetup luksFormat -q --iter-time=1 /dev/vdb -")
machine.succeed("echo -n supersecret | cryptsetup luksOpen -q /dev/vdb cryptroot")
machine.succeed("mkfs.ext4 /dev/mapper/cryptroot")
machine.succeed("PASSWORD=supersecret SYSTEMD_LOG_LEVEL=debug systemd-cryptenroll --tpm2-pcrs= --tpm2-device=auto /dev/vdb |& systemd-cat")
# Boot from the encrypted disk
+4 -1
View File
@@ -79,9 +79,12 @@ in
};
testScript = ''
# Create encrypted volume
machine.wait_for_unit("multi-user.target")
machine.succeed("echo -n ${passphrase} | cryptsetup luksFormat -q --iter-time=1 /dev/vdb -")
machine.succeed("echo -n ${passphrase} | cryptsetup luksOpen -q /dev/vdb cryptroot")
machine.succeed("mkfs.ext4 /dev/mapper/cryptroot")
machine.succeed("echo -n ${passphrase} | cryptsetup luksFormat -q --iter-time=1 /dev/vdc -")
machine.succeed("echo -n ${passphrase} | cryptsetup luksOpen -q /dev/vdc cryptroot2")
machine.succeed("mkfs.ext4 /dev/mapper/cryptroot2")
+5
View File
@@ -19,6 +19,7 @@ in
nodes = {
virthost = {
environment.systemPackages = [ pkgs.jq ];
services.openssh = {
enable = true;
settings.PermitRootLogin = "prohibit-password";
@@ -48,6 +49,10 @@ in
virthost.succeed("cp '${snakeOilEd25519PrivateKey}' ~/.ssh/id_ed25519")
virthost.succeed("chmod 600 ~/.ssh/id_ed25519")
with subtest("Check the environment generator"):
print(virthost.succeed("jq '.' /etc/systemd/generator-environment.json"))
print(virthost.succeed("/etc/systemd/system-environment-generators/env-generator"))
with subtest("ssh into a container with AF_UNIX"):
virthost.wait_for_unit("container@guest.service")
virthost.wait_until_succeeds("ssh -i ~/.ssh/id_ed25519 unix/run/systemd/nspawn/unix-export/guest/ssh echo meow | grep meow")
@@ -136,11 +136,11 @@ stdenv.mkDerivation (finalAttrs: {
+ lib.optionalString nixosTestRunner "-for-vm-tests"
+ lib.optionalString toolsOnly "-utils"
+ lib.optionalString userOnly "-user";
version = "10.2.0";
version = "10.2.1";
src = fetchurl {
url = "https://download.qemu.org/qemu-${finalAttrs.version}.tar.xz";
hash = "sha256-njCtG4ufe0RjABWC0aspfznPzOpdCFQMDKbWZyeFiDo=";
hash = "sha256-o3F0d9jiyE1jC//7wg9s0yk+tFqh5trG0MwnaJmRyeE=";
};
depsBuildBuild = [
@@ -267,50 +267,6 @@ stdenv.mkDerivation (finalAttrs: {
sha256 = "sha256-oC+bRjEHixv1QEFO9XAm4HHOwoiT+NkhknKGPydnZ5E=";
revert = true;
})
# Implement termios2 (TCGETS2 etc) for glibc 2.42 compatibility. Should be in the next release.
# https://gitlab.com/qemu-project/qemu/-/issues/3065
# https://lore.kernel.org/qemu-devel/20260103153239.15787-1-dilfridge@gentoo.org/t/#u
(fetchpatch {
name = "0001-Add-termios2-support-to-linux-user.patch";
url = "https://gitlab.com/qemu-project/qemu/-/commit/e9a8a10e84c1bf6e2e8be000e4dd5c83ba0d8470.patch";
hash = "sha256-Zc+ZjiSug3uT/F7+mmoYc2VXqw2MV6UubYqB+pr2dNY=";
})
(fetchpatch {
name = "0002-Add-termios2-support-to-alpha-target.patch";
url = "https://gitlab.com/qemu-project/qemu/-/commit/8d8c6aeee8599a099e49ec4411f3d1e087ae40ad.patch";
hash = "sha256-5e5vUp9nr96ZmVA98W/ETReLbkofayysJXlx1Ck9gDs=";
})
(fetchpatch {
name = "0003-Add-termios2-support-to-hppa-target.patch";
url = "https://gitlab.com/qemu-project/qemu/-/commit/edc741710acedd61011f937967b960d154794258.patch";
hash = "sha256-nls6eTOB06eqACjQ/r1sQvb9YaYmrpJcegsDGqKAOaI=";
})
(fetchpatch {
name = "0004-Add-termios2-support-to-mips-target.patch";
url = "https://gitlab.com/qemu-project/qemu/-/commit/edf9184f4feb691b0f70dc544443db2380891598.patch";
hash = "sha256-GrBhyMq2QiCc+WlUwaB9j4G8vB3ipxJRV5Hvyab/5Fk=";
})
(fetchpatch {
name = "0005-Add-termios2-support-to-sh4-target.patch";
url = "https://gitlab.com/qemu-project/qemu/-/commit/afbe0ff81c29d674b9c18a588bcaab34ddcb8a7b.patch";
hash = "sha256-h+9eC6H8/GJ85Lt1Y0ggdJbbgTIvDfIJkPQfX/FgO4c=";
})
(fetchpatch {
name = "0006-Add-termios2-support-to-sparc-target.patch";
url = "https://gitlab.com/qemu-project/qemu/-/commit/947b971cad90375040f399899909a3f1f32b483f.patch";
hash = "sha256-/JvF25aSR2mBSvkpqupDySMJYZI+lv7L0YwhqiaDk3A=";
})
(fetchpatch {
name = "0007-linux-user-Add-missing-termios-baud-rates.patch";
url = "https://gitlab.com/qemu-project/qemu/-/commit/4f22fcb5c67f40a36e6654f6cfaee23f9f9e93d1.patch";
hash = "sha256-CM81yL0/i+fmQe8qzemre13N3A74J1HIC7ilCbb7ESQ=";
})
(fetchpatch {
name = "0008-linux-user-fixup-termios2-related-things-on-PowerPC.patch";
url = "https://gitlab.com/qemu-project/qemu/-/commit/d68f0e2e906939bef076d0cd52f902d433c8c3da.patch";
hash = "sha256-vF47CKqg0wBBOUkHeJ3hv3nUHCftl2OwD3Nh0dL1PNk=";
})
]
++ lib.optional nixosTestRunner ./force-uid0-on-9p.patch;
+36 -31
View File
@@ -16,7 +16,6 @@ in
pkgsBuildHost,
makeInitrdNGTool,
binutils,
runCommand,
# Name of the derivation (not of the resulting file!)
name ? "initrd",
@@ -74,47 +73,53 @@ in
_compressorMeta.ubootName
or (throw "Unrecognised compressor ${_compressorName}, please specify uInitrdCompression"),
}:
runCommand name
{
compress = "${_compressorExecutable} ${lib.escapeShellArgs _compressorArgsReal}";
passthru = {
compressorExecutableFunction = _compressorFunction;
compressorArgs = _compressorArgsReal;
};
stdenvNoCC.mkDerivation (finalAttrs: {
__structuredAttrs = true;
inherit
extension
makeUInitrd
uInitrdArch
prepend
;
${if makeUInitrd then "uInitrdCompression" else null} = uInitrdCompression;
# the initrd will be self-contained so we can drop references
# to the closure that was used to build it
unsafeDiscardReferences.out = true;
passAsFile = [ "contents" ];
contents = builtins.toJSON contents;
inherit
name
extension
makeUInitrd
uInitrdArch
prepend
;
${if makeUInitrd then "uInitrdCompression" else null} = uInitrdCompression;
nativeBuildInputs = [
makeInitrdNGTool
cpio
]
++ lib.optional makeUInitrd ubootTools;
}
''
compress = "${_compressorExecutable} ${lib.escapeShellArgs _compressorArgsReal}";
contentsJSON = builtins.toJSON contents;
nativeBuildInputs = [
makeInitrdNGTool
cpio
]
++ lib.optional makeUInitrd ubootTools;
buildCommand = ''
mkdir -p ./root/{run,tmp,var/empty}
ln -s ../run ./root/var/run
make-initrd-ng "$contentsPath" ./root
make-initrd-ng <(echo "$contentsJSON") ./root
mkdir "$out"
(cd root && find . -exec touch -h -d '@1' '{}' +)
for PREP in $prepend; do
for PREP in ''${prepend[@]}; do
cat $PREP >> $out/initrd
done
(cd root && find . -print0 | sort -z | cpio --quiet -o -H newc -R +0:+0 --reproducible --null | eval -- $compress >> "$out/initrd")
if [ -n "$makeUInitrd" ]; then
mkimage -A "$uInitrdArch" -O linux -T ramdisk -C "$uInitrdCompression" -d "$out/initrd" $out/initrd.img
# Compatibility symlink
ln -sf "initrd.img" "$out/initrd"
mkimage -A "$uInitrdArch" -O linux -T ramdisk -C "$uInitrdCompression" -d "$out/initrd" $out/initrd.img
# Compatibility symlink
ln -sf "initrd.img" "$out/initrd"
else
ln -s "initrd" "$out/initrd$extension"
ln -s "initrd" "$out/initrd$extension"
fi
''
'';
passthru = {
compressorExecutableFunction = _compressorFunction;
compressorArgs = _compressorArgsReal;
};
})
+35 -33
View File
@@ -81,42 +81,44 @@ in
_compressorMeta.ubootName
or (throw "Unrecognised compressor ${_compressorName}, please specify uInitrdCompression"),
}:
stdenvNoCC.mkDerivation (
rec {
inherit
name
makeUInitrd
extension
uInitrdArch
prepend
;
stdenvNoCC.mkDerivation (finalAttrs: {
__structuredAttrs = true;
builder = ./make-initrd.sh;
# the initrd will be self-contained so we can drop references
# to the closure that was used to build it
unsafeDiscardReferences.out = true;
nativeBuildInputs = [
cpio
]
++ lib.optional makeUInitrd ubootTools;
inherit
name
extension
makeUInitrd
uInitrdArch
prepend
;
${if makeUInitrd then "uInitrdCompression" else null} = uInitrdCompression;
compress = "${_compressorExecutable} ${lib.escapeShellArgs _compressorArgsReal}";
builder = ./make-initrd.sh;
# Pass the function through, for reuse in append-initrd-secrets. The
# function is used instead of the string, in order to support
# cross-compilation (append-initrd-secrets running on a different
# architecture than what the main initramfs is built on).
passthru = {
compressorExecutableFunction = _compressorFunction;
compressorArgs = _compressorArgsReal;
};
nativeBuildInputs = [
cpio
]
++ lib.optional makeUInitrd ubootTools;
# !!! should use XML.
objects = map (x: x.object) contents;
symlinks = map (x: x.symlink) contents;
suffices = map (x: if x ? suffix then x.suffix else "none") contents;
compress = "${_compressorExecutable} ${lib.escapeShellArgs _compressorArgsReal}";
closureInfo = "${pkgsBuildHost.closureInfo { rootPaths = objects; }}";
}
// lib.optionalAttrs makeUInitrd {
uInitrdCompression = uInitrdCompression;
}
)
# !!! should use XML.
objects = map (x: x.object) contents;
symlinks = map (x: x.symlink) contents;
suffices = map (x: if x ? suffix then x.suffix else "none") contents;
closureInfo = "${pkgsBuildHost.closureInfo { rootPaths = finalAttrs.objects; }}";
# Pass the function through, for reuse in append-initrd-secrets. The
# function is used instead of the string, in order to support
# cross-compilation (append-initrd-secrets running on a different
# architecture than what the main initramfs is built on).
passthru = {
compressorExecutableFunction = _compressorFunction;
compressorArgs = _compressorArgsReal;
};
})
+12 -16
View File
@@ -1,9 +1,5 @@
set -o pipefail
objects=($objects)
symlinks=($symlinks)
suffices=($suffices)
mkdir root
# Needed for splash_helper, which gets run before init.
@@ -12,14 +8,14 @@ mkdir root/sys
mkdir root/proc
for ((n = 0; n < ${#objects[*]}; n++)); do
object=${objects[$n]}
symlink=${symlinks[$n]}
suffix=${suffices[$n]}
if test "$suffix" = none; then suffix=; fi
for ((n = 0; n < ${#objects[@]}; n++)); do
object=${objects[n]}
symlink=${symlinks[n]}
suffix=${suffices[n]}
if test "$suffix" = none; then suffix=; fi
mkdir -p $(dirname root/$symlink)
ln -s $object$suffix root/$symlink
mkdir -p $(dirname root/$symlink)
ln -s $object$suffix root/$symlink
done
@@ -34,16 +30,16 @@ storePaths="$(cat $closureInfo/store-paths)"
# Put the closure in a gzipped cpio archive.
mkdir -p $out
for PREP in $prepend; do
for PREP in ${prepend[@]}; do
cat $PREP >> $out/initrd
done
(cd root && find * .[^.*] -exec touch -h -d '@1' '{}' +)
(cd root && find * .[^.*] -print0 | sort -z | cpio --quiet -o -H newc -R +0:+0 --reproducible --null | eval -- $compress >> "$out/initrd")
if [ -n "$makeUInitrd" ]; then
mkimage -A "$uInitrdArch" -O linux -T ramdisk -C "$uInitrdCompression" -d "$out/initrd" $out/initrd.img
# Compatibility symlink
ln -sf "initrd.img" "$out/initrd"
mkimage -A "$uInitrdArch" -O linux -T ramdisk -C "$uInitrdCompression" -d "$out/initrd" $out/initrd.img
# Compatibility symlink
ln -sf "initrd.img" "$out/initrd"
else
ln -s "initrd" "$out/initrd$extension"
ln -s "initrd" "$out/initrd$extension"
fi
+2 -2
View File
@@ -8,13 +8,13 @@
stdenv.mkDerivation (finalAttrs: {
pname = "capstone";
version = "5.0.6";
version = "5.0.7";
src = fetchFromGitHub {
owner = "capstone-engine";
repo = "capstone";
rev = finalAttrs.version;
hash = "sha256-ovIvsxVq+/q5UUMzP4WpxzaE0898uayNc1g2Coignnc=";
hash = "sha256-+6QReHZK+iIXspizy6Kvk7cj016HOKgiaKSaP4h7mao=";
};
cmakeFlags = [
+1
View File
@@ -48,6 +48,7 @@ rustPlatform.buildRustPackage (finalAttrs: {
"initrd-init"
"find-etc"
"resolve-in-root"
"env-generator"
];
postInstall = ''
@@ -0,0 +1,53 @@
use std::{
collections::HashMap,
fs,
io::{self, Write},
};
use anyhow::{Context, Result};
use serde::Deserialize;
const CONFIG_PATH: &str = "/etc/systemd/generator-environment.json";
const KMSG_PATH: &str = "/dev/kmsg";
#[derive(Deserialize)]
struct Config(HashMap<String, String>);
/// Implementation for the entrypoint of the `env-generator` binary.
///
/// Reads the JSON config for the systemd generator environment and prints it in KEY=VALUE format
/// to stdout. This makes the configured environment variables available for all systemd
/// generators.
fn env_generator_impl() -> Result<()> {
let content = fs::read(CONFIG_PATH).with_context(|| format!("Failed to read {CONFIG_PATH}"))?;
let config: Config = serde_json::from_slice(&content).context("Failed to parse config")?;
let mut buffer = Vec::new();
for (key, value) in config.0 {
writeln!(&mut buffer, "{key}=\"{value}\"").context("Failed to write to buffer")?;
}
let stdout = io::stdout();
let mut locked = stdout.lock();
locked
.write_all(&buffer)
.context("Failed to write to stdout")?;
Ok(())
}
/// Entrypoint for the `env-generator` binary.
///
/// Generators cannot use normal logging but have to write to /dev/kmsg.
///
/// The return value is just here so that we can use the `main.rs` entrypoint for this binary.
/// Errors returned from this function will not be logged and thus are meaningless.
pub fn env_generator() -> Result<()> {
if let Err(err) = env_generator_impl() {
// Sometimes we do not have /dev/kmsg, e.g. inside a container
if let Ok(mut kmsg) = fs::OpenOptions::new().write(true).open(KMSG_PATH) {
let _ = write!(kmsg, "<3>env-generator: {err:#}");
}
}
Ok(())
}
+2
View File
@@ -1,5 +1,6 @@
mod activate;
mod config;
mod env_generator;
mod find_etc;
mod fs;
mod init;
@@ -14,6 +15,7 @@ use anyhow::{Context, Result, bail};
pub use crate::{
activate::activate,
env_generator::env_generator,
find_etc::find_etc,
init::init,
initrd_init::initrd_init,
+2 -1
View File
@@ -2,7 +2,7 @@ use std::{env, io::Write, process::ExitCode};
use log::Level;
use nixos_init::{find_etc, initrd_init, resolve_in_root};
use nixos_init::{env_generator, find_etc, initrd_init, resolve_in_root};
fn main() -> ExitCode {
let arg0 = env::args()
@@ -15,6 +15,7 @@ fn main() -> ExitCode {
"find-etc" => find_etc,
"resolve-in-root" => resolve_in_root,
"initrd-init" => initrd_init,
"env-generator" => env_generator,
_ => {
log::error!("Command {arg0} unknown");
return ExitCode::FAILURE;
@@ -308,6 +308,14 @@ It must be one of the following:
option, it is possible to build non-flake NixOS configurations even if
the current NixOS systems uses flakes.
*--diff*
show the diff between the system closure in /run/current-system
and the newly built system closure.
(avaliable for actions: build, boot, test, switch)
This is similar to running:
"nix store diff-closures /run/current-system result" after build
In addition, *nixos-rebuild* accepts following options from nix commands that
the tool calls:
@@ -197,6 +197,12 @@ def get_parser() -> tuple[argparse.ArgumentParser, dict[str, argparse.ArgumentPa
help="Selects an image variant to build from the "
"config.system.build.images attribute of the given configuration",
)
main_parser.add_argument(
"--diff",
action="store_true",
help="prints out the diff between the current system "
"and the newly built one using nix store diff-closures"
)
main_parser.add_argument("action", choices=Action.values(), nargs="?")
return main_parser, sub_parsers
@@ -259,6 +265,20 @@ def parse_args(
if args.no_build_nix:
parser_warn("--no-build-nix is deprecated, we do not build nix anymore")
if args.diff and args.action not in (
# case for calling build_and_activate_system
# except excluding DRY_BUILD and DRY_ACTIVATE,
# in which --diff is uniquely a no-op
Action.SWITCH.value,
Action.BOOT.value,
Action.TEST.value,
Action.BUILD.value,
Action.BUILD_IMAGE.value,
Action.BUILD_VM.value,
Action.BUILD_VM_WITH_BOOTLOADER.value,
):
parser_warn(f"--diff is a no-op with '{args.action}'")
if args.action == Action.EDIT.value and (args.file or args.attr):
parser.error("--file and --attr are not supported with 'edit'")
@@ -1,3 +1,4 @@
import sys
import json
import logging
import os
@@ -537,6 +538,25 @@ def list_generations(profile: Profile) -> list[GenerationJson]:
reverse=True,
)
def diff_closures(current_config: Path, new_config: Path, target_host: Remote | None = None):
print(
f"<<< {current_config}\n"
f">>> {new_config}",
file=sys.stderr
)
run_wrapper(
[
"nix",
*FLAKE_FLAGS,
"store",
"diff-closures",
current_config,
new_config,
],
remote=target_host,
stdout=sys.stderr
)
def repl(build_attr: BuildAttr, nix_flags: Args | None = None) -> None:
run_args = ["nix", "repl", "--file", build_attr.path]
@@ -321,6 +321,13 @@ def build_and_activate_system(
grouped_nix_args=grouped_nix_args,
)
current_config = Path("/run/current-system")
if args.diff:
if current_config.exists():
nix.diff_closures(current_config=current_config.readlink(), new_config=path_to_config, target_host=target_host)
else:
logger.warning(f"missing '{str(current_config)}', skipping configuration diff...")
_activate_system(
path_to_config=path_to_config,
action=action,
@@ -1,3 +1,4 @@
import sys
import textwrap
import uuid
from pathlib import Path
@@ -550,6 +551,29 @@ def test_list_generations(mock_get_generations: Mock, tmp_path: Path) -> None:
]
@patch(get_qualified_name(n.run_wrapper, n), autospec=True)
def test_diff_closures(mock_run: Mock) -> None:
assert n.diff_closures(
Path("/run/current-system"),
Path("/nix/var/nix/profiles/system"),
None
) == None
mock_run.assert_called_with(
[
"nix",
"--extra-experimental-features",
"nix-command flakes",
"store",
"diff-closures",
Path("/run/current-system"),
Path("/nix/var/nix/profiles/system"),
],
remote=None,
stdout=sys.stderr
)
@patch(get_qualified_name(n.run_wrapper, n), autospec=True)
def test_repl(mock_run: Mock) -> None:
n.repl(m.BuildAttr("<nixpkgs/nixos>", None), {"nix_flag": True})
+3 -3
View File
@@ -16,18 +16,18 @@
rustPlatform.buildRustPackage (finalAttrs: {
pname = "ruff";
version = "0.15.0";
version = "0.15.1";
src = fetchFromGitHub {
owner = "astral-sh";
repo = "ruff";
tag = finalAttrs.version;
hash = "sha256-Q3xujVNv5i3mgdsjnvgTiPoKmK9aeSgz+2IoVrNur4k=";
hash = "sha256-Bj4ATRVYrKqigISNiDvgjUw4MLMwfgdID8MqaiVxz0g=";
};
cargoBuildFlags = [ "--package=ruff" ];
cargoHash = "sha256-JMMDOANg+nqrCoxiuIXTcdqm7UZ61pIJwUTJB20TjUM=";
cargoHash = "sha256-IF60aGv56Kh+wDYyN7XzLBywepvAxv2HMqSOz+Su2b4=";
nativeBuildInputs = [ installShellFiles ];
+2 -2
View File
@@ -11,11 +11,11 @@
stdenv.mkDerivation (finalAttrs: {
pname = "strace";
version = "6.18";
version = "6.19";
src = fetchurl {
url = "https://strace.io/files/${finalAttrs.version}/strace-${finalAttrs.version}.tar.xz";
hash = "sha256-CtXcupc6aed5ZQ7xyzNbEu5gcW/HMmYJiVvTPm0qcyU=";
hash = "sha256-4HbIUe7AlySG7IQhZP3FRUf50Xq9PRRJ3osSD10pkUM=";
};
separateDebugInfo = true;
@@ -20,23 +20,23 @@
"lts": true
},
"6.6": {
"version": "6.6.124",
"hash": "sha256:0kkri7y9g5c7hylwsdc2wq2drhniay171nnccr533qlvisgzpbm7",
"version": "6.6.125",
"hash": "sha256:0g88r1v5q0m1n1ii2f16awc8w9m471m6hqx7r5whad4a8dpkpqwf",
"lts": true
},
"6.12": {
"version": "6.12.70",
"hash": "sha256:1w1flq4phr3i51c85bz8d9a8cg780vn7dr29y4j4izyfv33wwk4v",
"version": "6.12.72",
"hash": "sha256:0ybijkw2zadhlg49r0wvnvy3s2czj5jnb149cz8ybvzvp90qgxdi",
"lts": true
},
"6.18": {
"version": "6.18.10",
"hash": "sha256:1plfwknqh5831kjq6f2yxcm4lqvp68a6kvcfnbxa5ba12wb7glyn",
"version": "6.18.11",
"hash": "sha256:1xrsc7s3kh7mipfs0v33n97gfi55ll83x4hxvwi969qh8293ibrq",
"lts": false
},
"6.19": {
"version": "6.19",
"hash": "sha256:0mqka8ii7bvmx9hvfjdiyva9ib0j7m390gxhh8gki3qb4nl7jc1h",
"version": "6.19.1",
"hash": "sha256:1vlki73j7m2khjl39hq4fy42qql9als18nmnjg00a8yklhqzb0qb",
"lts": false
}
}