From e182d8dff6bd3b0913ae6531c6abae3ed1e38364 Mon Sep 17 00:00:00 2001 From: Emily Date: Tue, 28 Jan 2025 18:40:29 +0000 Subject: [PATCH] nix: add `nix.enable` option to disable Nix management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is an equivalent of the `nix.enable` option from NixOS and Home Manager. On NixOS, it mostly serves to allow building fixed‐configuration systems without any Nix installation at all. It should work for that purpose with nix-darwin too, and the implementation is largely the same, but the main use case is more similar to the Home Manager option: to allow the use of nix-darwin with an unmanaged system installation of Nix, including when there is another service expecting to manage it, as with Determinate. By providing an escape hatch to opt out of Nix management entirely, this will also allow us to consolidate and simplify our existing Nix installation management, by being more opinionated about things like taking ownership of the daemon and the build users. Porting one option from NixOS lets us drop two that only ever existed in nix-darwin and reduce overall complexity. --- modules/nix/default.nix | 52 +++++++++++++++++++++-- modules/services/nix-daemon.nix | 2 +- modules/system/checks.nix | 9 ++-- pkgs/darwin-uninstaller/configuration.nix | 12 +----- pkgs/darwin-uninstaller/default.nix | 9 ++-- release.nix | 1 + tests/nix-enable.nix | 14 ++++++ 7 files changed, 78 insertions(+), 21 deletions(-) create mode 100644 tests/nix-enable.nix diff --git a/modules/nix/default.nix b/modules/nix/default.nix index b373e77..39820da 100644 --- a/modules/nix/default.nix +++ b/modules/nix/default.nix @@ -134,6 +134,26 @@ let namedPaths ++ searchPaths; }; + handleUnmanaged = managedConfig: mkMerge [ + (mkIf cfg.enable managedConfig) + (mkIf (!cfg.enable) { + system.activationScripts.nix-daemon.text = '' + # Restore unmanaged Nix daemon if present + unmanagedNixProfile=/nix/var/nix/profiles/default + if [[ + -e /run/current-system/Library/LaunchDaemons/org.nixos.nix-daemon.plist + && -e $unmanagedNixProfile/Library/LaunchDaemons/org.nixos.nix-daemon.plist + ]]; then + printf >&2 'restoring unmanaged Nix daemon...\n' + cp \ + "$unmanagedNixProfile/Library/LaunchDaemons/org.nixos.nix-daemon.plist" \ + /Library/LaunchDaemons + launchctl load -w /Library/LaunchDaemons/org.nixos.nix-daemon.plist + fi + ''; + }) + ]; + in { @@ -144,7 +164,6 @@ in in [ # Only ever in NixOS - (mkRemovedOptionModule [ "nix" "enable" ] "No `nix-darwin` equivalent to this NixOS option.") (mkRemovedOptionModule [ "nix" "daemonCPUSchedPolicy" ] (altOption "nix.daemonProcessType")) (mkRemovedOptionModule [ "nix" "daemonIOSchedClass" ] (altOption "nix.daemonProcessType")) (mkRemovedOptionModule [ "nix" "daemonIOSchedPriority" ] (altOption "nix.daemonIOLowPriority")) @@ -165,9 +184,36 @@ in nix = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to enable Nix. + + Disabling this will stop nix-darwin from managing the + installed version of Nix, the nix-daemon launchd daemon, and + the settings in {file}`/etc/nix/nix.conf`. + + This allows you to use nix-darwin without it taking over your + system installation of Nix. Some nix-darwin functionality + that relies on managing the Nix installation, like the + `nix.*` options to adjust Nix settings or configure a Linux + builder, will be unavailable. You will also have to upgrade + Nix yourself, as nix-darwin will no longer do so. + + ::: {.warning} + If you have already removed your global system installation + of Nix, this will break nix-darwin and you will have to + reinstall Nix to fix it. + ::: + ''; + }; + package = mkOption { type = types.package; - default = pkgs.nix; + default = warnIf (!cfg.enable) + "nix.package: accessed when `nix.enable` is off; this is a bug" + pkgs.nix; defaultText = literalExpression "pkgs.nix"; description = '' This option specifies the Nix package instance to use throughout the system. @@ -678,7 +724,7 @@ in ###### implementation - config = { + config = handleUnmanaged { environment.systemPackages = [ nixPackage diff --git a/modules/services/nix-daemon.nix b/modules/services/nix-daemon.nix index ffc7e65..df3fa31 100644 --- a/modules/services/nix-daemon.nix +++ b/modules/services/nix-daemon.nix @@ -10,7 +10,7 @@ in options = { services.nix-daemon.enable = mkOption { type = types.bool; - default = true; + default = config.nix.enable; description = "Whether to enable the nix-daemon service."; }; diff --git a/modules/system/checks.nix b/modules/system/checks.nix index 7fbe159..cc8048d 100644 --- a/modules/system/checks.nix +++ b/modules/system/checks.nix @@ -303,15 +303,16 @@ in options = { system.checks.verifyNixPath = mkOption { type = types.bool; - default = true; + default = config.nix.enable; description = "Whether to run the NIX_PATH validation checks."; }; system.checks.verifyBuildUsers = mkOption { type = types.bool; default = - (config.nix.useDaemon && !(config.nix.settings.auto-allocate-uids or false)) - || config.nix.configureBuildUsers; + config.nix.enable && + ((config.nix.useDaemon && !(config.nix.settings.auto-allocate-uids or false)) + || config.nix.configureBuildUsers); description = "Whether to run the Nix build users validation checks."; }; @@ -336,7 +337,7 @@ in (mkIf cfg.verifyBuildUsers buildUsers) (mkIf cfg.verifyBuildUsers preSequoiaBuildUsers) (mkIf config.nix.configureBuildUsers buildGroupID) - nixDaemon + (mkIf config.nix.enable nixDaemon) nixStore (mkIf (config.nix.gc.automatic && config.nix.gc.user == null) nixGarbageCollector) (mkIf (config.nix.optimise.automatic && config.nix.optimise.user == null) nixStoreOptimiser) diff --git a/pkgs/darwin-uninstaller/configuration.nix b/pkgs/darwin-uninstaller/configuration.nix index 56ab228..ce6be6c 100644 --- a/pkgs/darwin-uninstaller/configuration.nix +++ b/pkgs/darwin-uninstaller/configuration.nix @@ -12,8 +12,8 @@ with lib; launchd.daemons = mkForce {}; launchd.user.agents = mkForce {}; - # Don't try to reload `nix-daemon` - nix.useDaemon = mkForce false; + # Restore any unmanaged `nix-daemon`. + nix.enable = false; system.activationScripts.postUserActivation.text = mkAfter '' nix-channel --remove darwin || true @@ -30,14 +30,6 @@ with lib; rm /etc/static fi - # If the Nix Store is owned by root then we're on a multi-user system - if [[ -O /nix/store ]]; then - if [[ -e /nix/var/nix/profiles/default/Library/LaunchDaemons/org.nixos.nix-daemon.plist ]]; then - sudo cp /nix/var/nix/profiles/default/Library/LaunchDaemons/org.nixos.nix-daemon.plist /Library/LaunchDaemons/org.nixos.nix-daemon.plist - sudo launchctl load -w /Library/LaunchDaemons/org.nixos.nix-daemon.plist - fi - fi - # grep will return 1 when no lines matched which makes this line fail with `set -eo pipefail` dscl . -list /Users UserShell | { grep "\s/run/" || true; } | awk '{print $1}' | while read -r user; do shell=$(dscl . -read /Users/"$user" UserShell) diff --git a/pkgs/darwin-uninstaller/default.nix b/pkgs/darwin-uninstaller/default.nix index 0214652..6b43bcf 100644 --- a/pkgs/darwin-uninstaller/default.nix +++ b/pkgs/darwin-uninstaller/default.nix @@ -31,8 +31,11 @@ in writeShellApplication { echo >&2 " - remove /Applications/Nix Apps symlink" echo >&2 " - cleanup static /etc files" echo >&2 " - disable and remove all launchd services managed by nix-darwin" - if [[ $(stat -f '%Su' /nix/store) == "root" ]]; then - echo >&2 " - restore nix-daemon service from nix installer as this is a multi-user install" + if [[ + -e /run/current-system/Library/LaunchDaemons/org.nixos.nix-daemon.plist + && -e /nix/var/nix/profiles/default/Library/LaunchDaemons/org.nixos.nix-daemon.plist + ]]; then + echo >&2 " - restore nix-daemon service from the Nix installer" fi echo >&2 @@ -87,7 +90,7 @@ in writeShellApplication { launchctl print system/org.nixos.nix-daemon pgrep -l nix-daemon test -e /Library/LaunchDaemons/org.nixos.nix-daemon.plist - [[ "$(shasum -a 256 /Library/LaunchDaemons/org.nixos.nix-daemon.plist | awk '{print $1}')" == "$(shasum -a 256 /Library/LaunchDaemons/org.nixos.nix-daemon.plist | awk '{print $1}')" ]] + [[ "$(shasum -a 256 /Library/LaunchDaemons/org.nixos.nix-daemon.plist | awk '{print $1}')" == "$(shasum -a 256 /nix/var/nix/profiles/default/Library/LaunchDaemons/org.nixos.nix-daemon.plist | awk '{print $1}')" ]] nix-store --store daemon -q --hash ${stdenv.shell} fi echo >&2 ok diff --git a/release.nix b/release.nix index b3e2df7..52b3c2a 100644 --- a/release.nix +++ b/release.nix @@ -88,6 +88,7 @@ in { tests.launchd-setenv = makeTest ./tests/launchd-setenv.nix; tests.networking-hostname = makeTest ./tests/networking-hostname.nix; tests.networking-networkservices = makeTest ./tests/networking-networkservices.nix; + tests.nix-enable = makeTest ./tests/nix-enable.nix; tests.nixpkgs-overlays = makeTest ./tests/nixpkgs-overlays.nix; tests.programs-ssh = makeTest ./tests/programs-ssh.nix; tests.programs-tmux = makeTest ./tests/programs-tmux.nix; diff --git a/tests/nix-enable.nix b/tests/nix-enable.nix new file mode 100644 index 0000000..4e7a178 --- /dev/null +++ b/tests/nix-enable.nix @@ -0,0 +1,14 @@ +{ config, ... }: + +{ + nix.enable = false; + nix.package = throw "`nix.package` used when `nix.enable` is turned off"; + + test = '' + printf >&2 'checking for unexpected Nix binary in /sw/bin\n' + [[ -e ${config.out}/sw/bin/nix-env ]] && exit 1 + + printf >&2 'checking for unexpected nix-daemon plist in /Library/LaunchDaemons\n' + [[ -e ${config.out}/Library/LaunchDaemons/org.nixos.nix-daemon.plist ]] && exit 1 + ''; +}