Merge staging-nixos into staging-next
This commit is contained in:
@@ -93,3 +93,4 @@
|
||||
### Additions and Improvements {#sec-nixpkgs-release-26.11-lib-additions-improvements}
|
||||
|
||||
- Create the first release note entry in this section!
|
||||
|
||||
|
||||
@@ -64,6 +64,8 @@
|
||||
|
||||
- `security.polkit.settings` added for RFC42 style configuration of the polkitd daemon.
|
||||
|
||||
- The `programs.fuse` module, which provides the `fusermount3` executable and the `/etc/fuse.conf` config file, is now opt-in. The obligation to enable it has been shifted to its various consumers (e.g. gvfs, flatpak, appimage, sshfs). This can break fuse consumers at runtime, that don't explicitly declare that dependency with a module, e.g the mounting functionality in various backup tools (borg, restic, rclone, ...).
|
||||
|
||||
- `services.plausible` can now again seed an initial admin user declaratively via [`services.plausible.adminUser.email`](#opt-services.plausible.adminUser.email).
|
||||
This makes fully declarative deployments safer: Otherwise the user needed to either accept Plausible's unauthenticated "first launch" setup wizard, which lets anyone reaching the instance create the first admin account, or do more work (deploying with NixOS's default binding to `localhost` without exposing it publicly, going through the wizard, and then deploying Plausible exposed to the Internet).
|
||||
This option was previously removed with NixOS 25.05 due to an upstream Plausible change making declarative admin creation more difficult, but this change re-implements the admin creation directly.
|
||||
|
||||
@@ -1044,12 +1044,16 @@ class QemuMachine(BaseMachine):
|
||||
assert self.shell
|
||||
|
||||
tic = time.time()
|
||||
# TODO: do we want to bail after a set number of attempts?
|
||||
while not shell_ready(timeout_secs=30):
|
||||
|
||||
for _ in range(10):
|
||||
if shell_ready(timeout_secs=30):
|
||||
break
|
||||
self.log("Guest root shell did not produce any data yet...")
|
||||
self.log(
|
||||
" To debug, enter the VM and run 'systemctl status backdoor.service'."
|
||||
)
|
||||
else:
|
||||
raise RuntimeError("Shell did not start in time")
|
||||
|
||||
while True:
|
||||
chunk = self.shell.recv(1024)
|
||||
@@ -1587,7 +1591,7 @@ class NspawnMachine(BaseMachine):
|
||||
# NOTE If the test calls switch-to-configuration (with a differently configured specialization)
|
||||
# this will use the /etc/profile of the new specialisation while `QemuMachine` nodes
|
||||
# will continue to use the original /etc/profile.
|
||||
command = f"set -eo pipefail; source /etc/profile; set -u; {command}"
|
||||
command = f"set -eo pipefail; USER=root HOME=/root source /etc/profile; set -u; {command}"
|
||||
|
||||
cp = subprocess.run(
|
||||
[
|
||||
|
||||
@@ -135,8 +135,13 @@ let
|
||||
);
|
||||
udevRules = map (
|
||||
interface:
|
||||
# MAC Addresses for QEMU network devices are lowercase, and udev string comparison is case-sensitive.
|
||||
''SUBSYSTEM=="net",ACTION=="add",ATTR{address}=="${toLower (qemu-common.qemuNicMac interface.vlan config.virtualisation.test.nodeNumber)}",NAME="${interface.name}"''
|
||||
lib.concatStringsSep ", " [
|
||||
''SUBSYSTEM=="net"''
|
||||
''ACTION=="add"''
|
||||
# MAC Addresses for QEMU network devices are lowercase, and udev string comparison is case-sensitive.
|
||||
''ATTR{address}=="${toLower (qemu-common.qemuNicMac interface.vlan config.virtualisation.test.nodeNumber)}"''
|
||||
''NAME="${interface.name}"''
|
||||
]
|
||||
) interfaces;
|
||||
in
|
||||
{
|
||||
|
||||
@@ -74,7 +74,9 @@ in
|
||||
}
|
||||
(
|
||||
''
|
||||
set +e
|
||||
mmap_rnd_bits_max=$(grep "^CONFIG_ARCH_MMAP_RND_BITS_MAX=" $configfile | grep --only-matching "[0-9]*$")
|
||||
set -e
|
||||
if [[ -z "$mmap_rnd_bits_max" ]]; then
|
||||
echo "Unable to determine mmap_rnd_bits_max. Check your kernel configfile is valid."
|
||||
exit 1
|
||||
@@ -83,7 +85,9 @@ in
|
||||
''
|
||||
# HAVE_ARCH_MMAP_RND_COMPAT_BITS is not defined on 32-bit architectures or LoongArch64
|
||||
+ lib.optionalString (with pkgs.stdenv.hostPlatform; (!is32bit && !isLoongArch64)) ''
|
||||
set +e
|
||||
mmap_rnd_compat_bits_max=$(grep "^CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=" $configfile | grep --only-matching "[0-9]*$")
|
||||
set -e
|
||||
if [[ -z "$mmap_rnd_compat_bits_max" ]]; then
|
||||
echo "Unable to determine mmap_rnd_compat_bits_max. Check your kernel configfile is valid."
|
||||
exit 1
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
environment.corePackages = lib.mkForce [ ];
|
||||
# Contains bash completions
|
||||
nix.enable = lib.mkDefault false;
|
||||
# The fuse{,3} package contains a runtime dependency on bash.
|
||||
programs.fuse.enable = lib.mkDefault false;
|
||||
documentation.man.man-db.enable = lib.mkDefault false;
|
||||
# autovt depends on bash
|
||||
console.enable = lib.mkDefault false;
|
||||
|
||||
@@ -43,6 +43,8 @@ in
|
||||
}
|
||||
);
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
programs.fuse.enable = true;
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
|
||||
@@ -12,9 +12,7 @@ in
|
||||
meta.maintainers = [ ];
|
||||
|
||||
options.programs.fuse = {
|
||||
enable = lib.mkEnableOption "fuse" // {
|
||||
default = true;
|
||||
};
|
||||
enable = lib.mkEnableOption "fuse";
|
||||
|
||||
mountMax = lib.mkOption {
|
||||
# In the C code it's an "int" (i.e. signed and at least 16 bit), but
|
||||
|
||||
@@ -274,6 +274,7 @@ in
|
||||
|
||||
services.power-profiles-daemon.enable = mkDefault true;
|
||||
services.system-config-printer.enable = mkIf config.services.printing.enable (mkDefault true);
|
||||
programs.fuse.enable = true;
|
||||
services.udisks2.enable = true;
|
||||
services.upower.enable = config.powerManagement.enable;
|
||||
services.libinput.enable = mkDefault true;
|
||||
|
||||
@@ -40,6 +40,8 @@ in
|
||||
pkgs.fuse3
|
||||
];
|
||||
|
||||
programs.fuse.enable = true;
|
||||
|
||||
security.polkit.enable = true;
|
||||
|
||||
fonts.fontDir.enable = true;
|
||||
|
||||
@@ -40,6 +40,8 @@ in
|
||||
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
programs.fuse.enable = true;
|
||||
|
||||
services.dbus.packages = [ cfg.package ];
|
||||
|
||||
systemd.packages = [ cfg.package ];
|
||||
|
||||
@@ -17,7 +17,7 @@ in
|
||||
type = types.str;
|
||||
default = "http://localhost:8053/";
|
||||
description = ''
|
||||
HTTP XML API address of an Bind server.
|
||||
HTTP API address of a BIND server.
|
||||
'';
|
||||
};
|
||||
bindTimeout = mkOption {
|
||||
@@ -29,13 +29,14 @@ in
|
||||
};
|
||||
bindVersion = mkOption {
|
||||
type = types.enum [
|
||||
"xml.v2"
|
||||
"json"
|
||||
"xml"
|
||||
"xml.v3"
|
||||
"auto"
|
||||
];
|
||||
default = "auto";
|
||||
default = "json";
|
||||
description = ''
|
||||
BIND statistics version. Can be detected automatically.
|
||||
BIND statistics version. Defaults to JSON.
|
||||
'';
|
||||
};
|
||||
bindGroups = mkOption {
|
||||
|
||||
@@ -332,8 +332,9 @@ in
|
||||
boot.kernel.sysctl."net.core.rmem_max" = lib.mkDefault 7500000;
|
||||
boot.kernel.sysctl."net.core.wmem_max" = lib.mkDefault 7500000;
|
||||
|
||||
programs.fuse = lib.mkIf (cfg.autoMount && cfg.settings.Mounts.FuseAllowOther) {
|
||||
userAllowOther = true;
|
||||
programs.fuse = {
|
||||
enable = lib.mkIf cfg.autoMount true;
|
||||
userAllowOther = lib.mkIf cfg.settings.Mounts.fuseAllowOther true;
|
||||
};
|
||||
|
||||
users.users = lib.mkIf (cfg.user == "ipfs") {
|
||||
|
||||
@@ -124,6 +124,16 @@ let
|
||||
jobScripts = concatLists (
|
||||
mapAttrsToList (_: unit: unit.jobScripts or [ ]) (filterAttrs (_: v: v.enable) cfg.services)
|
||||
);
|
||||
unitEnv = pkgs.buildEnv {
|
||||
name = "initrd-unit-env";
|
||||
paths = concatLists (
|
||||
mapAttrsToList (_: unit: unit.path or [ ]) (filterAttrs (_: v: v.enable) cfg.services)
|
||||
);
|
||||
pathsToLink = [
|
||||
"/bin"
|
||||
"/sbin"
|
||||
];
|
||||
};
|
||||
|
||||
stage1Units = generateUnits {
|
||||
type = "initrd";
|
||||
@@ -636,6 +646,7 @@ in
|
||||
"${pkgs.bashNonInteractive}/bin"
|
||||
]
|
||||
++ jobScripts
|
||||
++ [ unitEnv ]
|
||||
++ map (c: removeAttrs c [ "text" ]) (builtins.attrValues cfg.contents)
|
||||
++ lib.optional (pkgs.stdenv.hostPlatform.libc == "glibc") "${pkgs.glibc}/lib/libnss_files.so.2";
|
||||
|
||||
@@ -763,6 +774,7 @@ in
|
||||
];
|
||||
};
|
||||
serviceConfig.Type = "oneshot";
|
||||
serviceConfig.EnvironmentFile = "-/etc/switch-root.conf";
|
||||
description = "NixOS Activation";
|
||||
|
||||
script = # bash
|
||||
@@ -770,6 +782,14 @@ in
|
||||
set -uo pipefail
|
||||
export PATH="/bin:${cfg.package.util-linux}/bin"
|
||||
|
||||
# A non-NixOS closure (e.g. init=/bin/sh) has no prepare-root;
|
||||
# initrd-find-nixos-closure records this as a non-empty NEW_INIT.
|
||||
# Skip activation and let initrd-switch-root hand over to it directly.
|
||||
if [ -n "''${NEW_INIT:-}" ]; then
|
||||
echo "$NEW_INIT is not a NixOS system - not activating"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
closure="$(realpath /nixos-closure)"
|
||||
|
||||
# Initialize the system
|
||||
|
||||
@@ -71,6 +71,10 @@
|
||||
RequiresMountsFor = [
|
||||
"/sysroot/nix/store"
|
||||
];
|
||||
# find-etc only creates this symlink for a NixOS init. For a
|
||||
# non-NixOS init= (e.g. init=/bin/sh) it is absent, so skip the
|
||||
# mount instead of failing the whole initrd.
|
||||
ConditionPathExists = "/etc-metadata-image";
|
||||
};
|
||||
requires = [
|
||||
config.boot.initrd.systemd.services.initrd-find-etc.name
|
||||
@@ -123,6 +127,8 @@
|
||||
"/run/nixos-etc-metadata"
|
||||
];
|
||||
DefaultDependencies = false;
|
||||
# Skip for a non-NixOS init=, see the metadata mount above.
|
||||
ConditionPathExists = "/etc-basedir";
|
||||
};
|
||||
}
|
||||
];
|
||||
@@ -140,6 +146,8 @@
|
||||
# before the overlay is mounted.
|
||||
"/run/nixos-etc-metadata"
|
||||
];
|
||||
# Skip for a non-NixOS init=, see the metadata mount above.
|
||||
ConditionPathExists = "/etc-metadata-image";
|
||||
};
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
lib.mkIf
|
||||
(config.boot.supportedFilesystems.sshfs or config.boot.supportedFilesystems."fuse.sshfs" or false)
|
||||
{
|
||||
programs.fuse.enable = true;
|
||||
|
||||
system.fsPackages = [ pkgs.sshfs ];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1646,6 +1646,7 @@ in
|
||||
"i686-linux"
|
||||
] ./initrd-network-openvpn { systemdStage1 = true; };
|
||||
systemd-initrd-networkd-ssh = runTest ./systemd-initrd-networkd-ssh.nix;
|
||||
systemd-initrd-non-nixos = runTest ./systemd-initrd-non-nixos.nix;
|
||||
systemd-initrd-shutdown = runTest {
|
||||
imports = [ ./systemd-shutdown.nix ];
|
||||
_module.args.systemdStage1 = true;
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
pkgs.openssl
|
||||
];
|
||||
|
||||
programs.fuse.enable = true;
|
||||
|
||||
specialisation.fstab-test.configuration = {
|
||||
# This can't be fileSytems, as the qemu machinery doesn't honor it.
|
||||
virtualisation.fileSystems."/plain" = {
|
||||
|
||||
@@ -111,7 +111,7 @@ let
|
||||
wait_for_unit("prometheus-bind-exporter.service")
|
||||
wait_for_open_port(9119)
|
||||
succeed(
|
||||
"curl -sSf http://localhost:9119/metrics | grep 'bind_query_recursions_total 0'"
|
||||
"curl -sSf http://localhost:9119/metrics | grep 'bind_up 1'"
|
||||
)
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
{
|
||||
name = "simple-container";
|
||||
|
||||
containers.machine = { };
|
||||
containers = {
|
||||
machine = { pkgs, ... }: {
|
||||
users.users.root.packages = [ pkgs.hello ];
|
||||
};
|
||||
noprofile = { };
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
machine.shutdown()
|
||||
machine.succeed("hello")
|
||||
noprofile.fail("hello")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -43,6 +43,19 @@ let
|
||||
server.serve_forever()
|
||||
'';
|
||||
|
||||
# Per-connection (Accept=yes) socket-activated service that requires the
|
||||
# connection socket to be passed via socket activation and fails when started
|
||||
# without one. It greets the client and stays alive for as long as the
|
||||
# connection is held open.
|
||||
acceptSocketTest = pkgs.writeShellScript "accept-socket-test.sh" ''
|
||||
if [ "''${LISTEN_FDS:-0}" -lt 1 ]; then
|
||||
echo "Expected exactly one socket, got 0" >&2
|
||||
exit 4
|
||||
fi
|
||||
printf hello >&3
|
||||
exec ${lib.getExe' pkgs.coreutils "cat"} <&3 >/dev/null
|
||||
'';
|
||||
|
||||
in
|
||||
{
|
||||
name = "switch-test";
|
||||
@@ -508,6 +521,32 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
accept-socket.configuration = {
|
||||
systemd.sockets.accept-socket = {
|
||||
wantedBy = [ "sockets.target" ];
|
||||
listenStreams = [ "/run/accept-test.sock" ];
|
||||
socketConfig = {
|
||||
Accept = "yes";
|
||||
SocketMode = "0777";
|
||||
};
|
||||
};
|
||||
systemd.services."accept-socket@" = {
|
||||
description = "A per-connection socket-activated service";
|
||||
serviceConfig.ExecStart = acceptSocketTest;
|
||||
};
|
||||
};
|
||||
|
||||
accept-socket-service-modified.configuration = {
|
||||
imports = [ accept-socket.configuration ];
|
||||
systemd.services."accept-socket@".serviceConfig.X-Test = "test";
|
||||
};
|
||||
|
||||
socket-activated-without-socket.configuration = {
|
||||
imports = [ simple-socket.configuration ];
|
||||
systemd.sockets.socket-activated.enable = false;
|
||||
systemd.services.socket-activated.wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
|
||||
mount.configuration = {
|
||||
systemd.mounts = [
|
||||
{
|
||||
@@ -1587,6 +1626,49 @@ in
|
||||
if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
|
||||
raise Exception("Socket was not properly activated after the service was restarted")
|
||||
|
||||
# A service transitioning to socket activation is not started directly,
|
||||
# it's left for the newly started socket to activate on demand
|
||||
switch_to_specialisation("${machine}", "socket-activated-without-socket")
|
||||
machine.succeed("systemctl is-active socket-activated.service")
|
||||
out = switch_to_specialisation("${machine}", "simple-socket-stop-if-changed")
|
||||
assert_contains(out, "stopping the following units: socket-activated.service\n")
|
||||
assert_lacks(out, "\nstarting the following units:")
|
||||
assert_contains(out, "the following new units were started: socket-activated.socket\n")
|
||||
machine.succeed("[ -S /run/test.sock ]")
|
||||
if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
|
||||
raise Exception("Socket was not properly activated after the transition")
|
||||
|
||||
with subtest("socket-activated services with Accept=yes"):
|
||||
# Socket-activated services don't get started, just the socket
|
||||
machine.fail("[ -S /run/accept-test.sock ]")
|
||||
out = switch_to_specialisation("${machine}", "accept-socket")
|
||||
assert_contains(out, "the following new units were started: accept-socket.socket\n")
|
||||
machine.succeed("[ -S /run/accept-test.sock ]")
|
||||
|
||||
# Hold a connection open so a per-connection instance keeps running
|
||||
machine.succeed("socat EXEC:'sleep infinity' UNIX-CONNECT:/run/accept-test.sock >&2 &")
|
||||
instance = machine.wait_until_succeeds(
|
||||
"systemctl list-units --no-legend --state=running 'accept-socket@*.service' "
|
||||
+ "| grep -m1 -o 'accept-socket@[^ ]*\\.service'"
|
||||
).strip()
|
||||
|
||||
# Changing the templated service must stop the running instance and
|
||||
# restart the socket instead of (re)starting the per-connection
|
||||
# instance, which cannot be started without a connection socket
|
||||
out = switch_to_specialisation("${machine}", "accept-socket-service-modified")
|
||||
assert_contains(out, "stopping the following units:")
|
||||
assert_contains(out, instance)
|
||||
assert_contains(out, "accept-socket.socket")
|
||||
assert_contains(out, "\nstarting the following units: accept-socket.socket\n")
|
||||
assert_lacks(out, "NOT restarting the following changed units:")
|
||||
assert_lacks(out, "\nrestarting the following units:")
|
||||
# The per-connection instance must not be (re)started
|
||||
starting = out[out.index("\nstarting the following units:") :]
|
||||
assert instance not in starting, f"instance {instance} should not be (re)started"
|
||||
# Socket-activation of the unit still works
|
||||
if machine.succeed("socat - UNIX-CONNECT:/run/accept-test.sock </dev/null") != "hello":
|
||||
raise Exception("Socket was not properly activated after the service was changed")
|
||||
|
||||
with subtest("mounts"):
|
||||
switch_to_specialisation("${machine}", "mount")
|
||||
out = machine.succeed("mount | grep 'on /testmount'")
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
{ lib, pkgs, ... }:
|
||||
let
|
||||
marker = "REACHED NON-NIXOS INIT AS PID 1";
|
||||
|
||||
# A non-NixOS init (no prepare-root). We use a store path, not literal
|
||||
# /bin/sh: a fresh disk has no /bin/sh yet (it is created by the activation a
|
||||
# non-NixOS init skips), while the store is always mounted; init=/bin/sh works
|
||||
# the same on a real system. Writes a marker, then stays alive so PID 1 lives.
|
||||
nonNixosInit = pkgs.writeShellScriptBin "non-nixos" ''
|
||||
echo "${marker}" > /dev/console
|
||||
exec ${pkgs.coreutils}/bin/sleep infinity
|
||||
'';
|
||||
|
||||
common = {
|
||||
boot.initrd.systemd.enable = true;
|
||||
|
||||
virtualisation = {
|
||||
# tmpfs root, like real non-NixOS closure init= microvm consumers.
|
||||
diskImage = null;
|
||||
|
||||
graphics = false;
|
||||
};
|
||||
|
||||
# Speed up wait_for_console.
|
||||
boot.consoleLogLevel = lib.mkForce 3;
|
||||
boot.initrd.systemd.managerEnvironment.SYSTEMD_LOG_LEVEL = "warning";
|
||||
|
||||
# switch-root needs an os-release on the target root. A real system has one
|
||||
# on disk; our fresh tmpfs does not, so create it.
|
||||
boot.initrd.systemd.tmpfiles.settings."10-os-release"."/sysroot/etc/os-release".f = {
|
||||
mode = "0644";
|
||||
argument = "ID=test-non-nixos";
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
name = "systemd-initrd-non-nixos";
|
||||
|
||||
nodes = {
|
||||
bashActivation = common;
|
||||
|
||||
nixosInit = {
|
||||
imports = [ common ];
|
||||
system.nixos-init.enable = true;
|
||||
system.etc.overlay.enable = true;
|
||||
services.userborn.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
import os
|
||||
|
||||
# The last init= on the cmdline wins; QEMU_KERNEL_PARAMS is appended after
|
||||
# the default one, so this boots our non-NixOS init.
|
||||
os.environ["QEMU_KERNEL_PARAMS"] = "init=${lib.getExe nonNixosInit}"
|
||||
|
||||
start_all()
|
||||
|
||||
# If a code path does not skip the non-NixOS init, switch-root is blocked and
|
||||
# the machine drops to emergency mode: the marker never appears and the wait
|
||||
# times out.
|
||||
with subtest("bash initrd-nixos-activation skips a non-NixOS init"):
|
||||
bashActivation.wait_for_console_text("${marker}", timeout=300)
|
||||
|
||||
with subtest("nixos-init switches to a non-NixOS init directly"):
|
||||
nixosInit.wait_for_console_text("${marker}", timeout=300)
|
||||
'';
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
libidn2,
|
||||
libtool,
|
||||
libxml2,
|
||||
json_c,
|
||||
openssl,
|
||||
liburcu,
|
||||
libuv,
|
||||
@@ -29,11 +30,11 @@
|
||||
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "bind";
|
||||
version = "9.20.23";
|
||||
version = "9.20.24";
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://downloads.isc.org/isc/bind9/${finalAttrs.version}/bind-${finalAttrs.version}.tar.xz";
|
||||
hash = "sha256-XUR1rtP55QDvVUsrFNlyvbg9M94hSps76SkY6kaQg3E=";
|
||||
hash = "sha256-mJ/vH8iOpZ0EzYb4VNylpGFqIKmWi83ePBo2aKs2vgg=";
|
||||
};
|
||||
|
||||
outputs = [
|
||||
@@ -59,6 +60,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
libidn2
|
||||
libtool
|
||||
libxml2
|
||||
json_c
|
||||
openssl
|
||||
liburcu
|
||||
libuv
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
rustPlatform.buildRustPackage (finalAttrs: {
|
||||
pname = "gram";
|
||||
version = "2.1.2";
|
||||
version = "2.2.0";
|
||||
|
||||
outputs = [
|
||||
"out"
|
||||
@@ -44,7 +44,7 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
owner = "GramEditor";
|
||||
repo = "gram";
|
||||
tag = finalAttrs.version;
|
||||
hash = "sha256-7FzAvC/JMMIFcuTGkL2Ju644UAIsneOMhiDUFnQske4=";
|
||||
hash = "sha256-w0uZ2qAc3Tt6QVRAX97LWW9aOs02fG1SEYCDhpUhinE=";
|
||||
};
|
||||
|
||||
postPatch = ''
|
||||
@@ -54,7 +54,7 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
--replace-fail '$CARGO_ABOUT_VERSION' '${cargo-about.version}'
|
||||
'';
|
||||
|
||||
cargoHash = "sha256-feESY8ALSG3xa906HBc4pOKGerQ1jF7VUxzvUcsZbrY=";
|
||||
cargoHash = "sha256-+lmDbawAIRllC7LzGJ9qPMtHXPd5aMoul47YOA7nfXA=";
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
@@ -71,7 +71,7 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
dontUseCmakeConfigure = true;
|
||||
|
||||
buildInputs = [
|
||||
libgit2
|
||||
(libgit2.override { withExperimentalSha256 = true; })
|
||||
openssl
|
||||
sqlite
|
||||
zlib
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
gitstatus,
|
||||
llhttp,
|
||||
withGssapi ? false,
|
||||
withExperimentalSha256 ? false,
|
||||
krb5,
|
||||
}:
|
||||
|
||||
@@ -43,6 +44,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
"-DUSE_HTTP_PARSER=llhttp"
|
||||
"-DUSE_SSH=ON"
|
||||
(lib.cmakeBool "USE_GSSAPI" withGssapi)
|
||||
(lib.cmakeBool "EXPERIMENTAL_SHA256" withExperimentalSha256)
|
||||
"-DBUILD_SHARED_LIBS=${if staticBuild then "OFF" else "ON"}"
|
||||
]
|
||||
++ lib.optionals stdenv.hostPlatform.isWindows [
|
||||
@@ -89,6 +91,13 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
)
|
||||
'';
|
||||
|
||||
postInstall = lib.optionalString withExperimentalSha256 ''
|
||||
# Downstream Rust bindings (git2-rs / git2-sys) expect experimental headers
|
||||
# to be located at 'git2/experimental.h', but upstream libgit2 installs them
|
||||
# into 'git2-experimental/' when EXPERIMENTAL_SHA256 is enabled.
|
||||
ln -s git2-experimental $dev/include/git2
|
||||
'';
|
||||
|
||||
passthru.tests = lib.mapAttrs (_: v: v.override { libgit2 = finalAttrs.finalPackage; }) {
|
||||
inherit libgit2-glib;
|
||||
inherit (python3Packages) pygit2;
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
diff --git a/Makefile b/Makefile
|
||||
index 2a51d813..a31ac48a 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -63,6 +63,9 @@ endif
|
||||
ifdef DEBIAN
|
||||
CPPFLAGS += -DDEBIAN
|
||||
endif
|
||||
+ifdef NIXOS
|
||||
+CPPFLAGS += -DNIXOS
|
||||
+endif
|
||||
ifdef DEFAULT_OLD_METADATA
|
||||
CPPFLAGS += -DDEFAULT_OLD_METADATA
|
||||
DEFAULT_METADATA=0.90
|
||||
@@ -129,6 +132,7 @@ endif
|
||||
INSTALL = /usr/bin/install
|
||||
DESTDIR =
|
||||
BINDIR = /sbin
|
||||
+INSTALL_BINDIR = ${BINDIR}
|
||||
MANDIR = /usr/share/man
|
||||
MAN4DIR = $(MANDIR)/man4
|
||||
MAN5DIR = $(MANDIR)/man5
|
||||
@@ -253,16 +257,16 @@ sha1.o : sha1.c sha1.h md5.h
|
||||
install : install-bin install-man install-udev
|
||||
|
||||
install-static : mdadm.static install-man
|
||||
- $(INSTALL) -D $(STRIP) -m 755 mdadm.static $(DESTDIR)$(BINDIR)/mdadm
|
||||
+ $(INSTALL) -D $(STRIP) -m 755 mdadm.static $(DESTDIR)$(INSTALL_BINDIR)/mdadm
|
||||
|
||||
install-tcc : mdadm.tcc install-man
|
||||
- $(INSTALL) -D $(STRIP) -m 755 mdadm.tcc $(DESTDIR)$(BINDIR)/mdadm
|
||||
+ $(INSTALL) -D $(STRIP) -m 755 mdadm.tcc $(DESTDIR)$(INSTALL_BINDIR)/mdadm
|
||||
|
||||
install-uclibc : mdadm.uclibc install-man
|
||||
- $(INSTALL) -D $(STRIP) -m 755 mdadm.uclibc $(DESTDIR)$(BINDIR)/mdadm
|
||||
+ $(INSTALL) -D $(STRIP) -m 755 mdadm.uclibc $(DESTDIR)$(INSTALL_BINDIR)/mdadm
|
||||
|
||||
install-klibc : mdadm.klibc install-man
|
||||
- $(INSTALL) -D $(STRIP) -m 755 mdadm.klibc $(DESTDIR)$(BINDIR)/mdadm
|
||||
+ $(INSTALL) -D $(STRIP) -m 755 mdadm.klibc $(DESTDIR)$(INSTALL_BINDIR)/mdadm
|
||||
|
||||
install-man: mdadm.8 md.4 mdadm.conf.5 mdmon.8
|
||||
$(INSTALL) -D -m 644 mdadm.8 $(DESTDIR)$(MAN8DIR)/mdadm.8
|
||||
@@ -305,7 +309,7 @@ install-bin: mdadm mdmon
|
||||
$(INSTALL) -D $(STRIP) -m 755 mdmon $(DESTDIR)$(BINDIR)/mdmon
|
||||
|
||||
uninstall:
|
||||
- rm -f $(DESTDIR)$(MAN8DIR)/mdadm.8 $(DESTDIR)$(MAN8DIR)/mdmon.8 $(DESTDIR)$(MAN4DIR)/md.4 $(DESTDIR)$(MAN5DIR)/mdadm.conf.5 $(DESTDIR)$(BINDIR)/mdadm
|
||||
+ rm -f $(DESTDIR)$(MAN8DIR)/mdadm.8 $(DESTDIR)$(MAN8DIR)/mdmon.8 $(DESTDIR)$(MAN4DIR)/md.4 $(DESTDIR)$(MAN5DIR)/mdadm.conf.5 $(DESTDIR)$(INSTALL_BINDIR)/mdadm
|
||||
|
||||
test: mdadm mdmon test_stripe swap_super raid6check
|
||||
@echo "Please run './test' as root"
|
||||
diff --git a/policy.c b/policy.c
|
||||
index eee9ef63..9f916e9d 100644
|
||||
--- a/policy.c
|
||||
+++ b/policy.c
|
||||
@@ -817,12 +817,39 @@ char *find_rule(struct rule *rule, char *rule_type)
|
||||
#define UDEV_RULE_FORMAT \
|
||||
"ACTION==\"add\", SUBSYSTEM==\"block\", " \
|
||||
"ENV{DEVTYPE}==\"%s\", ENV{ID_PATH}==\"%s\", " \
|
||||
-"RUN+=\"" BINDIR "/mdadm --incremental $env{DEVNAME}\"\n"
|
||||
+"RUN+=\"%s/mdadm --incremental $env{DEVNAME}\"\n"
|
||||
|
||||
#define UDEV_RULE_FORMAT_NOTYPE \
|
||||
"ACTION==\"add\", SUBSYSTEM==\"block\", " \
|
||||
"ENV{ID_PATH}==\"%s\", " \
|
||||
-"RUN+=\"" BINDIR "/mdadm --incremental $env{DEVNAME}\"\n"
|
||||
+"RUN+=\"%s/mdadm --incremental $env{DEVNAME}\"\n"
|
||||
+
|
||||
+#ifdef NIXOS
|
||||
+const char *get_mdadm_bindir(void)
|
||||
+{
|
||||
+ static char *bindir = NULL;
|
||||
+ if (bindir != NULL) {
|
||||
+ return bindir;
|
||||
+ } else {
|
||||
+ int len;
|
||||
+ bindir = xmalloc(1025);
|
||||
+ len = readlink("/proc/self/exe", bindir, 1024);
|
||||
+ if (len > 0) {
|
||||
+ char *basename;
|
||||
+ if ((basename = strrchr(bindir, '/')) != NULL)
|
||||
+ *basename = '\0';
|
||||
+ else
|
||||
+ *(bindir + len) = '\0';
|
||||
+ } else {
|
||||
+ *bindir = '\0';
|
||||
+ }
|
||||
+ return bindir;
|
||||
+ }
|
||||
+}
|
||||
+#define SELF get_mdadm_bindir()
|
||||
+#else
|
||||
+#define SELF BINDIR
|
||||
+#endif
|
||||
|
||||
/* Write rule in the rule file. Use format from UDEV_RULE_FORMAT */
|
||||
int write_rule(struct rule *rule, int fd, int force_part)
|
||||
@@ -836,9 +863,9 @@ int write_rule(struct rule *rule, int fd, int force_part)
|
||||
if (force_part)
|
||||
typ = type_part;
|
||||
if (typ)
|
||||
- snprintf(line, sizeof(line) - 1, UDEV_RULE_FORMAT, typ, pth);
|
||||
+ snprintf(line, sizeof(line) - 1, UDEV_RULE_FORMAT, typ, pth, SELF);
|
||||
else
|
||||
- snprintf(line, sizeof(line) - 1, UDEV_RULE_FORMAT_NOTYPE, pth);
|
||||
+ snprintf(line, sizeof(line) - 1, UDEV_RULE_FORMAT_NOTYPE, pth, SELF);
|
||||
return write(fd, line, strlen(line)) == (int)strlen(line);
|
||||
}
|
||||
|
||||
diff --git a/util.c b/util.c
|
||||
index 3d05d074..e004a798 100644
|
||||
--- a/util.c
|
||||
+++ b/util.c
|
||||
@@ -1913,7 +1913,9 @@ int start_mdmon(char *devnm)
|
||||
char pathbuf[1024];
|
||||
char *paths[4] = {
|
||||
pathbuf,
|
||||
+#ifndef NIXOS
|
||||
BINDIR "/mdmon",
|
||||
+#endif
|
||||
"./mdmon",
|
||||
NULL
|
||||
};
|
||||
@@ -15,27 +15,16 @@
|
||||
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "mdadm";
|
||||
version = "4.4";
|
||||
version = "4.6";
|
||||
|
||||
src = fetchgit {
|
||||
url = "https://git.kernel.org/pub/scm/utils/mdadm/mdadm.git";
|
||||
tag = "mdadm-${finalAttrs.version}";
|
||||
hash = "sha256-jGmc8fkJM0V9J7V7tQPXSF/WD0kzyEAloBAwaAFenS0=";
|
||||
hash = "sha256-jFsVPJC4lcShkSwQCGjVdVkvk4q4weM7i5DzrLgpuSM=";
|
||||
};
|
||||
|
||||
patches = [
|
||||
./no-self-references.patch
|
||||
./fix-hardcoded-mapdir.patch
|
||||
# Fixes build on musl
|
||||
(fetchurl {
|
||||
url = "https://raw.githubusercontent.com/void-linux/void-packages/e58d2b17d3c40faffc0d426aab00184f28d9dafa/srcpkgs/mdadm/patches/musl.patch";
|
||||
hash = "sha256-TIcQs+8RM5Q6Z8MHkI50kaJd7f9WdS/EVI16F7b2+SA=";
|
||||
})
|
||||
# Fixes build on musl 1.2.5+
|
||||
(fetchurl {
|
||||
url = "https://lore.kernel.org/linux-raid/20240220165158.3521874-1-raj.khem@gmail.com/raw";
|
||||
hash = "sha256-JOZ8n7zi+nq236NPpB4e2gUy8I3l3DbcoLhpeL73f98=";
|
||||
})
|
||||
];
|
||||
|
||||
makeFlags = [
|
||||
@@ -97,6 +86,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
};
|
||||
|
||||
meta = {
|
||||
changelog = "https://git.kernel.org/pub/scm/utils/mdadm/mdadm.git/tree/CHANGELOG.md?h=${finalAttrs.src.tag}";
|
||||
description = "Programs for managing RAID arrays under Linux";
|
||||
homepage = "https://git.kernel.org/pub/scm/utils/mdadm/mdadm.git";
|
||||
license = lib.licenses.gpl2Plus;
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::{os::unix, path::Path};
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::{SYSROOT_PATH, find_toplevel_in_prefix, resolve_in_prefix};
|
||||
use crate::{SYSROOT_PATH, find_init_in_prefix, resolve_in_prefix, verify_init_is_nixos};
|
||||
|
||||
/// Entrypoint for the `find-etc` binary.
|
||||
///
|
||||
@@ -12,7 +12,20 @@ use crate::{SYSROOT_PATH, find_toplevel_in_prefix, resolve_in_prefix};
|
||||
/// This avoids needing a reference to the toplevel embedded in the initrd and thus reduces the
|
||||
/// need to re-build it.
|
||||
pub fn find_etc() -> Result<()> {
|
||||
let toplevel = find_toplevel_in_prefix(SYSROOT_PATH)?;
|
||||
let init_in_sysroot =
|
||||
find_init_in_prefix(SYSROOT_PATH).context("Failed to find init in sysroot")?;
|
||||
|
||||
// A non-NixOS init= (e.g. init=/bin/sh) has no etc metadata image. Skip
|
||||
// without creating the symlinks: the etc-overlay mounts are gated on them
|
||||
// and so skip too, and initrd-init switches root to the init directly.
|
||||
let Ok(toplevel) = verify_init_is_nixos(SYSROOT_PATH, &init_in_sysroot) else {
|
||||
log::info!(
|
||||
"{} is not a NixOS system - not setting up the etc overlay.",
|
||||
init_in_sysroot.display()
|
||||
);
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let config = Config::from_toplevel(&toplevel, SYSROOT_PATH)?;
|
||||
|
||||
let basedir = config
|
||||
|
||||
@@ -27,16 +27,6 @@ pub use crate::{
|
||||
|
||||
pub const SYSROOT_PATH: &str = "/sysroot";
|
||||
|
||||
/// Find the path to the toplevel closure of the system in a prefix.
|
||||
///
|
||||
/// Uses the `init=` parameter on the kernel command-line.
|
||||
///
|
||||
/// Returns the relative path of the init to the prefix, e.g. without the `/sysroot` prefix.
|
||||
pub fn find_toplevel_in_prefix(prefix: &str) -> Result<PathBuf> {
|
||||
let init_in_sysroot = find_init_in_prefix(prefix)?;
|
||||
verify_init_is_nixos(prefix, init_in_sysroot)
|
||||
}
|
||||
|
||||
/// Verify that an init path is inside a `NixOS` toplevel directory.
|
||||
///
|
||||
/// If the path is verified, returns the path to the toplevel.
|
||||
@@ -87,20 +77,16 @@ pub fn find_init_in_prefix(prefix: &str) -> Result<PathBuf> {
|
||||
}
|
||||
|
||||
/// Extract the value of the `init` parameter from the given kernel `cmdline`.
|
||||
///
|
||||
/// If `init=` appears multiple times the last one wins, matching the kernel.
|
||||
/// This is what makes appending `init=/bin/sh` at the boot prompt work even
|
||||
/// though the boot entry already has an `init=`.
|
||||
fn extract_init(cmdline: &str) -> Result<PathBuf> {
|
||||
let init_params: Vec<&str> = cmdline
|
||||
let init = cmdline
|
||||
.split_ascii_whitespace()
|
||||
.filter(|p| p.starts_with("init="))
|
||||
.collect();
|
||||
|
||||
if init_params.len() != 1 {
|
||||
bail!("Expected exactly one init param on kernel cmdline: {cmdline}")
|
||||
}
|
||||
|
||||
let init = init_params
|
||||
.first()
|
||||
.and_then(|s| s.split('=').next_back())
|
||||
.context("Failed to extract init path from kernel cmdline: {cmdline}")?;
|
||||
.filter_map(|p| p.strip_prefix("init="))
|
||||
.next_back()
|
||||
.with_context(|| format!("No init= parameter on kernel cmdline: {cmdline}"))?;
|
||||
|
||||
Ok(PathBuf::from(init))
|
||||
}
|
||||
@@ -129,4 +115,25 @@ mod tests {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_init_single() {
|
||||
assert_eq!(
|
||||
extract_init("root=fstab init=/nix/store/xxx-nixos/init quiet").unwrap(),
|
||||
PathBuf::from("/nix/store/xxx-nixos/init")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_init_last_wins() {
|
||||
assert_eq!(
|
||||
extract_init("init=/nix/store/xxx-nixos/init init=/bin/sh").unwrap(),
|
||||
PathBuf::from("/bin/sh")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_init_missing() {
|
||||
assert!(extract_init("root=fstab quiet").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,16 +7,16 @@
|
||||
|
||||
buildGoModule rec {
|
||||
pname = "bind_exporter";
|
||||
version = "0.7.0";
|
||||
version = "0.8.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
rev = "v${version}";
|
||||
owner = "prometheus-community";
|
||||
repo = "bind_exporter";
|
||||
sha256 = "sha256-x/XGatlXCKo9cI92JzFItApsjuZAfZX+8IZRpy7PVUo=";
|
||||
sha256 = "sha256-r1P+zy3iMgPmfvIBgycW8KS0gfNOxCT9YMmHdeY4uXA=";
|
||||
};
|
||||
|
||||
vendorHash = "sha256-f0ei/zotOj5ebURAOWUox/7J3jS2abQ5UgjninI9nRk=";
|
||||
vendorHash = "sha256-/fPj5LOe3QdnVPdtYdaqtnGMJ7/SZ458mpvjwO8TxEI=";
|
||||
|
||||
passthru.tests = { inherit (nixosTests.prometheus-exporters) bind; };
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
rustPlatform.buildRustPackage (finalAttrs: {
|
||||
pname = "ruff";
|
||||
version = "0.15.17";
|
||||
version = "0.15.18";
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
@@ -24,12 +24,12 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
owner = "astral-sh";
|
||||
repo = "ruff";
|
||||
tag = finalAttrs.version;
|
||||
hash = "sha256-+UsKRBe+lp/LdsmK/W11wCt2RypEryA5eBPb01OKCJw=";
|
||||
hash = "sha256-DH00tENXdCdNcGPXPGzZsU3RVYQ0VBe1QLvbgEg/G6k=";
|
||||
};
|
||||
|
||||
cargoBuildFlags = [ "--package=ruff" ];
|
||||
|
||||
cargoHash = "sha256-y1sKf+KXya/K+WUiIE357U6DXh/d+AQgj0SQIi1gpUw=";
|
||||
cargoHash = "sha256-RmK14NMPbhoRVLwIF5GXdGQg2AnMH20JGx7XF4HO+wY=";
|
||||
|
||||
nativeBuildInputs = [ installShellFiles ];
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "strace";
|
||||
version = "7.0";
|
||||
version = "7.1";
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://strace.io/files/${finalAttrs.version}/strace-${finalAttrs.version}.tar.xz";
|
||||
hash = "sha256-bJJBm+Py7FYLMXKKRlIhfFmGTIZCunsbN3GxsBOtB0s=";
|
||||
hash = "sha256-gXQ+zypbRBhrL1A4r9yL7aflxwrtFbT7+8xuns4kSQ8=";
|
||||
};
|
||||
|
||||
separateDebugInfo = true;
|
||||
|
||||
@@ -743,11 +743,6 @@ fn handle_modified_unit(
|
||||
// This unit should be restarted instead of stopped and started.
|
||||
units_to_restart.insert(unit.to_string(), ());
|
||||
record_unit(&restart_list, unit);
|
||||
// Remove from units to reload so we don't restart and reload
|
||||
if units_to_reload.contains_key(unit) {
|
||||
units_to_reload.remove(unit);
|
||||
unrecord_unit(&reload_list, unit);
|
||||
}
|
||||
} else {
|
||||
// If this unit is socket-activated, then stop the socket unit(s) as well, and
|
||||
// restart the socket(s) instead of the service.
|
||||
@@ -769,10 +764,17 @@ fn handle_modified_unit(
|
||||
};
|
||||
|
||||
if sockets.is_empty() {
|
||||
sockets.push(format!("{base_name}.socket"));
|
||||
// For a templated instance (`foo@bar.service`), `base_name`
|
||||
// includes the trailing `@`; the implicitly-associated socket
|
||||
// is `foo.socket`, so strip it.
|
||||
let socket_base = base_name.strip_suffix('@').unwrap_or(base_name);
|
||||
sockets.push(format!("{socket_base}.socket"));
|
||||
}
|
||||
|
||||
for socket in &sockets {
|
||||
let socket_in_new_config =
|
||||
toplevel.join(scope.etc_dir()).join(socket).exists();
|
||||
|
||||
if active_cur.contains_key(socket) {
|
||||
// We can now be sure this is a socket-activated unit
|
||||
|
||||
@@ -783,7 +785,7 @@ fn handle_modified_unit(
|
||||
}
|
||||
|
||||
// Only restart sockets that actually exist in new configuration:
|
||||
if toplevel.join(scope.etc_dir()).join(socket).exists() {
|
||||
if socket_in_new_config {
|
||||
if use_restart_as_stop_and_start {
|
||||
units_to_restart.insert(socket.to_string(), ());
|
||||
record_unit(&restart_list, socket);
|
||||
@@ -794,12 +796,9 @@ fn handle_modified_unit(
|
||||
|
||||
socket_activated = true;
|
||||
}
|
||||
|
||||
// Remove from units to reload so we don't restart and reload
|
||||
if units_to_reload.contains_key(unit) {
|
||||
units_to_reload.remove(unit);
|
||||
unrecord_unit(&reload_list, unit);
|
||||
}
|
||||
} else if socket_in_new_config {
|
||||
// Transitioning to socket activation; let the socket start it.
|
||||
socket_activated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -828,11 +827,11 @@ fn handle_modified_unit(
|
||||
} else {
|
||||
units_to_stop.insert(unit.to_string(), ());
|
||||
}
|
||||
// Remove from units to reload so we don't restart and reload
|
||||
if units_to_reload.contains_key(unit) {
|
||||
units_to_reload.remove(unit);
|
||||
unrecord_unit(&reload_list, unit);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from units to reload so we don't restart and reload
|
||||
if units_to_reload.remove(unit).is_some() {
|
||||
unrecord_unit(&reload_list, unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
rustPlatform.buildRustPackage (finalAttrs: {
|
||||
pname = "ty";
|
||||
version = "0.0.49";
|
||||
version = "0.0.52";
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
@@ -25,7 +25,7 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
repo = "ty";
|
||||
tag = finalAttrs.version;
|
||||
fetchSubmodules = true;
|
||||
hash = "sha256-IKeoskueujGYFjhUd3V7iwKwZjFZqG3OYfe36S6J2aw=";
|
||||
hash = "sha256-p9fTzQ4DYvnwrtLdpSTekBV4ZbR1KETR8dfsbp8CDpo=";
|
||||
};
|
||||
|
||||
# For Darwin platforms, remove the integration test for file notifications,
|
||||
@@ -39,7 +39,7 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
|
||||
cargoBuildFlags = [ "--package=ty" ];
|
||||
|
||||
cargoHash = "sha256-y1sKf+KXya/K+WUiIE357U6DXh/d+AQgj0SQIi1gpUw=";
|
||||
cargoHash = "sha256-NUIdYOeyRsR/ZQueEXshYdWTnSeQiRjZRRi2ag8Dm48=";
|
||||
|
||||
nativeBuildInputs = [ installShellFiles ];
|
||||
buildInputs = [ rust-jemalloc-sys ];
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
"lts": true
|
||||
},
|
||||
"6.18": {
|
||||
"version": "6.18.35",
|
||||
"hash": "sha256:0dpjprjzc4w44kw49jcgx1ffrm6gxn2gsnsz3hhmw4hr4a9h51pp",
|
||||
"version": "6.18.36",
|
||||
"hash": "sha256:0kn4r43lnd5nb5c298b30030qyaxv05s7k40n9si1j3iyk4qdazv",
|
||||
"lts": true
|
||||
},
|
||||
"7.0": {
|
||||
|
||||
+37
-31
@@ -146,14 +146,14 @@ optionalAttrs allowAliases aliases
|
||||
runCommand name
|
||||
{
|
||||
nativeBuildInputs = [ jq ];
|
||||
value = toJSON value;
|
||||
inherit value;
|
||||
preferLocalBuild = true;
|
||||
__structuredAttrs = true;
|
||||
}
|
||||
# NIX_ATTRS_JSON_FILE won't have `value` if it's null, but jq returns null for missing properties anyway
|
||||
# jsonNull test keeps this in check
|
||||
''
|
||||
valuePath="$TMPDIR/value"
|
||||
printf "%s" "$value" > "$valuePath"
|
||||
jq . "$valuePath" > $out
|
||||
jq .value "$NIX_ATTRS_JSON_FILE" > $out
|
||||
''
|
||||
) { };
|
||||
|
||||
@@ -171,14 +171,16 @@ optionalAttrs allowAliases aliases
|
||||
runCommand name
|
||||
{
|
||||
nativeBuildInputs = [ remarshal_0_17 ];
|
||||
value = toJSON value;
|
||||
inherit value;
|
||||
preferLocalBuild = true;
|
||||
__structuredAttrs = true;
|
||||
}
|
||||
''
|
||||
valuePath="$TMPDIR/value"
|
||||
printf "%s" "$value" > "$valuePath"
|
||||
json2yaml "$valuePath" "$out"
|
||||
json2yaml ${
|
||||
# attributes with null values are omitted from the JSON with structured attrs
|
||||
# yaml_1_1Null test keeps this in check
|
||||
if value == null then ''<(echo "null")'' else ''--unwrap value "$NIX_ATTRS_JSON_FILE"''
|
||||
} "$out"
|
||||
''
|
||||
) { };
|
||||
|
||||
@@ -196,14 +198,16 @@ optionalAttrs allowAliases aliases
|
||||
runCommand name
|
||||
{
|
||||
nativeBuildInputs = [ remarshal ];
|
||||
value = toJSON value;
|
||||
inherit value;
|
||||
preferLocalBuild = true;
|
||||
__structuredAttrs = true;
|
||||
}
|
||||
''
|
||||
valuePath="$TMPDIR/value"
|
||||
printf "%s" "$value" > "$valuePath"
|
||||
json2yaml "$valuePath" "$out"
|
||||
json2yaml ${
|
||||
# attributes with null values are omitted from the JSON with structured attrs
|
||||
# yaml_1_2Null test keeps this in check
|
||||
if value == null then ''<(echo "null")'' else ''--unwrap value "$NIX_ATTRS_JSON_FILE"''
|
||||
} "$out"
|
||||
''
|
||||
) { };
|
||||
|
||||
@@ -958,8 +962,10 @@ optionalAttrs allowAliases aliases
|
||||
python3
|
||||
black
|
||||
];
|
||||
imports = toJSON (value._imports or [ ]);
|
||||
value = toJSON (removeAttrs value [ "_imports" ]);
|
||||
imports = value._imports or [ ];
|
||||
# value must be an attrset, type would verify that,
|
||||
# otherwise removeAttrs will fail.
|
||||
value = removeAttrs value [ "_imports" ];
|
||||
pythonGen = pkgs.writeText "pythonGen" ''
|
||||
import json
|
||||
import os
|
||||
@@ -982,26 +988,20 @@ optionalAttrs allowAliases aliases
|
||||
else:
|
||||
return repr(value)
|
||||
|
||||
with open(os.environ["importsPath"], "r") as f:
|
||||
imports = json.load(f)
|
||||
if imports is not None:
|
||||
for i in imports:
|
||||
with open(os.environ["NIX_ATTRS_JSON_FILE"], "r") as f:
|
||||
attrs = json.load(f)
|
||||
if attrs["imports"] is not None:
|
||||
for i in attrs["imports"]:
|
||||
print(f"import {i}")
|
||||
print()
|
||||
|
||||
with open(os.environ["valuePath"], "r") as f:
|
||||
for key, value in json.load(f).items():
|
||||
for key, value in attrs["value"].items():
|
||||
print(f"{key} = {recursive_repr(value)}")
|
||||
'';
|
||||
preferLocalBuild = true;
|
||||
__structuredAttrs = true;
|
||||
}
|
||||
''
|
||||
export importsPath="$TMPDIR/imports"
|
||||
printf "%s" "$imports" > "$importsPath"
|
||||
export valuePath="$TMPDIR/value"
|
||||
printf "%s" "$value" > "$valuePath"
|
||||
cat "$valuePath"
|
||||
python3 "$pythonGen" > $out
|
||||
black $out
|
||||
''
|
||||
@@ -1015,7 +1015,13 @@ optionalAttrs allowAliases aliases
|
||||
}:
|
||||
if format == "badgerfish" then
|
||||
{
|
||||
type = serializableValueWith { typeName = "XML"; };
|
||||
type =
|
||||
attrsOf (serializableValueWith {
|
||||
typeName = "XML";
|
||||
})
|
||||
// {
|
||||
description = "XML value";
|
||||
};
|
||||
|
||||
generate =
|
||||
name: value:
|
||||
@@ -1031,14 +1037,16 @@ optionalAttrs allowAliases aliases
|
||||
python3Packages.xmltodict
|
||||
libxml2Python
|
||||
];
|
||||
value = toJSON value;
|
||||
inherit value;
|
||||
pythonGen = pkgs.writeText "pythonGen" ''
|
||||
import json
|
||||
import os
|
||||
import xmltodict
|
||||
|
||||
with open(os.environ["valuePath"], "r") as f:
|
||||
print(xmltodict.unparse(json.load(f), full_document=${
|
||||
with open(os.environ["NIX_ATTRS_JSON_FILE"], "r") as f:
|
||||
value = json.load(f).get("value")
|
||||
assert type(value) is dict, "value must be an attrset"
|
||||
print(xmltodict.unparse(value, full_document=${
|
||||
if withHeader then "True" else "False"
|
||||
}, pretty=True, indent=" " * 2))
|
||||
'';
|
||||
@@ -1046,8 +1054,6 @@ optionalAttrs allowAliases aliases
|
||||
__structuredAttrs = true;
|
||||
}
|
||||
''
|
||||
export valuePath="$TMPDIR/value"
|
||||
printf "%s" "$value" > "$valuePath"
|
||||
python3 "$pythonGen" > $out
|
||||
xmllint $out > /dev/null
|
||||
''
|
||||
|
||||
@@ -3,10 +3,6 @@
|
||||
pkgs,
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
toJSON
|
||||
;
|
||||
|
||||
inherit (lib.types)
|
||||
serializableValueWith
|
||||
;
|
||||
@@ -25,12 +21,12 @@ in
|
||||
(pkgs.python3.withPackages (ps: [ ps.configobj ]))
|
||||
];
|
||||
|
||||
valuesJSON = toJSON value;
|
||||
inherit value;
|
||||
__structuredAttrs = true;
|
||||
strictDeps = true;
|
||||
}
|
||||
''
|
||||
printf "%s" "$valuesJSON" | python3 ${./generate.py} > "$out"
|
||||
python3 ${./generate.py} > "$out"
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from configobj import ConfigObj
|
||||
|
||||
config = ConfigObj(interpolation=False, encoding="UTF8")
|
||||
config.update(json.load(sys.stdin))
|
||||
with open(os.environ["NIX_ATTRS_JSON_FILE"]) as f:
|
||||
value = json.load(f).get("value")
|
||||
config.update(value)
|
||||
config.write(sys.stdout.buffer)
|
||||
|
||||
@@ -142,6 +142,14 @@ runBuildTests {
|
||||
'';
|
||||
};
|
||||
|
||||
jsonNull = shouldPass {
|
||||
format = formats.json { };
|
||||
input = null;
|
||||
expected = ''
|
||||
null
|
||||
'';
|
||||
};
|
||||
|
||||
yaml_1_1Atoms = shouldPass {
|
||||
format = formats.yaml_1_1 { };
|
||||
input = {
|
||||
@@ -176,6 +184,15 @@ runBuildTests {
|
||||
'';
|
||||
};
|
||||
|
||||
yaml_1_1Null = shouldPass {
|
||||
format = formats.yaml_1_1 { };
|
||||
input = null;
|
||||
expected = ''
|
||||
null
|
||||
...
|
||||
'';
|
||||
};
|
||||
|
||||
yaml_1_2Atoms = shouldPass {
|
||||
format = formats.yaml_1_2 { };
|
||||
input = {
|
||||
@@ -210,6 +227,16 @@ runBuildTests {
|
||||
'';
|
||||
};
|
||||
|
||||
yaml_1_2Null = shouldPass {
|
||||
format = formats.yaml_1_2 { };
|
||||
input = null;
|
||||
# nixfmt insists on removing indentation, so force it with ${" "}
|
||||
expected = ''
|
||||
|
||||
${" "}null
|
||||
'';
|
||||
};
|
||||
|
||||
iniAtoms = shouldPass {
|
||||
format = formats.ini { };
|
||||
input = {
|
||||
@@ -884,6 +911,14 @@ runBuildTests {
|
||||
'';
|
||||
};
|
||||
|
||||
cdnNull = shouldPass {
|
||||
format = formats.cdn { };
|
||||
input = null;
|
||||
expected = ''
|
||||
null: null
|
||||
'';
|
||||
};
|
||||
|
||||
# This test is responsible for
|
||||
# 1. testing type coercions
|
||||
# 2. providing a more readable example test
|
||||
@@ -994,6 +1029,14 @@ runBuildTests {
|
||||
'';
|
||||
};
|
||||
|
||||
luaNull = shouldPass {
|
||||
format = formats.lua { };
|
||||
input = null;
|
||||
expected = ''
|
||||
return nil
|
||||
'';
|
||||
};
|
||||
|
||||
nixConfAtoms = shouldPass {
|
||||
format = formats.nixConf {
|
||||
package = pkgs.nix;
|
||||
@@ -1019,6 +1062,15 @@ runBuildTests {
|
||||
'';
|
||||
};
|
||||
|
||||
nixConfNull = shouldFail {
|
||||
format = formats.nixConf {
|
||||
package = pkgs.nix;
|
||||
version = pkgs.nix.version;
|
||||
extraOptions = "ignore-try = false";
|
||||
};
|
||||
input = null;
|
||||
};
|
||||
|
||||
phpAtoms = shouldPass rec {
|
||||
format = formats.php { finalVariable = "config"; };
|
||||
input = {
|
||||
@@ -1048,6 +1100,16 @@ runBuildTests {
|
||||
'';
|
||||
};
|
||||
|
||||
phpNull = shouldPass {
|
||||
format = formats.php { finalVariable = "config"; };
|
||||
input = null;
|
||||
expected = ''
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
$config = null;
|
||||
'';
|
||||
};
|
||||
|
||||
pythonVars = shouldPass (
|
||||
let
|
||||
format = formats.pythonVars { };
|
||||
@@ -1105,6 +1167,11 @@ runBuildTests {
|
||||
}
|
||||
);
|
||||
|
||||
pythonVarsNull = shouldFail {
|
||||
format = formats.pythonVars { };
|
||||
input = null;
|
||||
};
|
||||
|
||||
phpReturn = shouldPass {
|
||||
format = formats.php { };
|
||||
input = {
|
||||
@@ -1150,6 +1217,11 @@ runBuildTests {
|
||||
'';
|
||||
};
|
||||
|
||||
xmlNull = shouldFail {
|
||||
format = formats.xml { };
|
||||
input = null;
|
||||
};
|
||||
|
||||
PlistGenerate = shouldPass {
|
||||
format = formats.plist { };
|
||||
input = {
|
||||
@@ -1225,6 +1297,17 @@ runBuildTests {
|
||||
</plist>'';
|
||||
};
|
||||
|
||||
PlistNull = shouldPass {
|
||||
format = formats.plist { };
|
||||
input = null;
|
||||
expected = ''
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
|
||||
</plist>'';
|
||||
};
|
||||
|
||||
hcl1Atoms = shouldPass {
|
||||
format = formats.hcl1 { };
|
||||
input = {
|
||||
|
||||
Reference in New Issue
Block a user