Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The Plan, phase 1 #1341

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ jobs:
nix_path: nixpkgs=channel:${{ env.NIXPKGS_BRANCH }}
- name: Install channels
run: |
nix-channel --add https://nixos.org/channels/${{ env.NIXPKGS_BRANCH }} nixpkgs
nix-channel --update
sudo nix-channel --add https://nixos.org/channels/${{ env.NIXPKGS_BRANCH }} nixpkgs
sudo nix-channel --update
- name: Install nix-darwin
run: |
sudo mkdir -p /etc/nix-darwin
Expand All @@ -61,7 +61,7 @@ jobs:
/" \
/etc/nix-darwin/configuration.nix

nix run .#darwin-rebuild -- switch \
sudo nix run .#darwin-rebuild -- switch \
-I darwin=. \
-I darwin-config=/etc/nix-darwin/configuration.nix
- name: Switch to new configuration
Expand All @@ -72,17 +72,17 @@ jobs:
"s/pkgs.vim/pkgs.hello/" \
/etc/nix-darwin/configuration.nix

darwin-rebuild switch
sudo darwin-rebuild switch

hello
- name: Test uninstallation of nix-darwin
run: |
# We need to specify `--extra-experimental-features` because `experimental-features` is set by
# `cachix/install-nix-action` but not by our default config above
nix run .#darwin-uninstaller \
sudo nix run .#darwin-uninstaller \
--extra-experimental-features "nix-command flakes" \
--override-input nixpkgs nixpkgs/${{ env.NIXPKGS_BRANCH }}
nix run .#darwin-uninstaller.tests.uninstaller \
sudo nix run .#darwin-uninstaller.tests.uninstaller \
--extra-experimental-features "nix-command flakes" \
--override-input nixpkgs nixpkgs/${{ env.NIXPKGS_BRANCH }}

Expand Down Expand Up @@ -112,7 +112,7 @@ jobs:
's/nixpkgs.hostPlatform = "aarch64-darwin";/nixpkgs.hostPlatform = "'$(nix eval --expr builtins.currentSystem --impure --raw)'";/' \
flake.nix
popd
nix run .#darwin-rebuild -- switch \
sudo nix run .#darwin-rebuild -- switch \
--override-input nix-darwin . \
--override-input nixpkgs nixpkgs/${{ env.NIXPKGS_BRANCH }}
- name: Switch to new configuration
Expand All @@ -123,12 +123,12 @@ jobs:
"s/pkgs.vim/pkgs.hello/" \
/etc/nix-darwin/flake.nix

darwin-rebuild switch \
sudo darwin-rebuild switch \
--override-input nix-darwin . \
--override-input nixpkgs nixpkgs/${{ env.NIXPKGS_BRANCH }}

hello
- name: Test uninstallation of nix-darwin
run: |
nix run .#darwin-uninstaller --override-input nixpkgs nixpkgs/${{ env.NIXPKGS_BRANCH }}
nix run .#darwin-uninstaller.tests.uninstaller --override-input nixpkgs nixpkgs/${{ env.NIXPKGS_BRANCH }}
sudo nix run .#darwin-uninstaller --override-input nixpkgs nixpkgs/${{ env.NIXPKGS_BRANCH }}
sudo nix run .#darwin-uninstaller.tests.uninstaller --override-input nixpkgs nixpkgs/${{ env.NIXPKGS_BRANCH }}
27 changes: 27 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
2025-01-30
- Previously, some nix-darwin options applied to the user running
`darwin-rebuild`. As part of a long‐term migration to make
nix-darwin focus on system‐wide activation and support first‐class
multi‐user setups, all system activation now runs as `root`, and
these options instead apply to the `system.primaryUser` user.

You will get an evaluation error if you are using any options to
which this applies.

To continue using these options, set `system.primaryUser` to the name
of the user you have been using to run `darwin-rebuild`. In the long
run, this setting will be deprecated and removed after all the
functionality it is relevant for has been adjusted to allow
specifying the relevant user separately, moved under the
`users.users.*` namespace, or migrated to Home Manager.

Accordingly, `darwin-rebuild` must now be run as root, the
`system.activationScripts.{extraUserActivation,preUserActivation,
postUserActivation}` settings have been removed, and all activation
scripts are now executed as `root` – be careful if you override any
of them.

If you run into any unexpected issues with the migration, please
open an issue at <https://github.com/LnL7/nix-darwin/issues/new>
and include as much information as possible.

2025-01-29
- There is now a `nix.enable` toggle to disable management of the Nix
installation. Nix installation management has been made more
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,17 +98,17 @@ Unlike NixOS, `nix-darwin` does not have an installer, you can just run `darwin-

```bash
# To use Nixpkgs unstable:
nix run nix-darwin/master#darwin-rebuild -- switch
sudo nix run nix-darwin/master#darwin-rebuild -- switch
# To use Nixpkgs 24.11:
nix run nix-darwin/nix-darwin-24.11#darwin-rebuild -- switch
sudo nix run nix-darwin/nix-darwin-24.11#darwin-rebuild -- switch
```

### Step 3. Using `nix-darwin`

After installing, you can run `darwin-rebuild` to apply changes to your system:

```bash
darwin-rebuild switch
sudo darwin-rebuild switch
```

#### Using flake inputs
Expand Down Expand Up @@ -155,15 +155,15 @@ To install `nix-darwin`, you can just run `darwin-rebuild switch` to install nix

```bash
nix-build '<darwin>' -A darwin-rebuild
./result/bin/darwin-rebuild switch -I darwin-config=/etc/nix-darwin/configuration.nix
sudo ./result/bin/darwin-rebuild switch -I darwin-config=/etc/nix-darwin/configuration.nix
```

### Step 4. Using `nix-darwin`

After installing, you can run `darwin-rebuild` to apply changes to your system:

```bash
darwin-rebuild switch
sudo darwin-rebuild switch
```

### Step 5. Updating `nix-darwin`
Expand All @@ -186,13 +186,13 @@ The documentation is also available as manpages by running `man 5 configuration.
To run the latest version of the uninstaller, you can run the following command:

```
nix --extra-experimental-features "nix-command flakes" run nix-darwin#darwin-uninstaller
sudo nix --extra-experimental-features "nix-command flakes" run nix-darwin#darwin-uninstaller
```

If that command doesn't work for you, you can try the locally installed uninstaller:

```
darwin-uninstaller
sudo darwin-uninstaller
```

## Tests
Expand All @@ -218,7 +218,7 @@ flag can also be used to override darwin-config or nixpkgs, for more
information on the `-I` flag look at the nix-build [manpage](https://nixos.org/manual/nix/stable/command-ref/nix-build.html).

```bash
darwin-rebuild switch -I darwin=.
sudo darwin-rebuild switch -I darwin=.
```

If you're adding a module, please add yourself to `meta.maintainers`, for example
Expand Down
16 changes: 13 additions & 3 deletions modules/environment/default.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{ config, lib, pkgs, ... }:
{ options, config, lib, pkgs, ... }:

with lib;

Expand Down Expand Up @@ -75,15 +75,15 @@ in
else if config.system.stateVersion >= 6 then
"/etc/nix-darwin/configuration.nix"
else
"$HOME/.nixpkgs/darwin-configuration.nix";
"${config.system.primaryUserHome}/.nixpkgs/darwin-configuration.nix";
defaultText = literalExpression ''
if config.nixpkgs.flake.setNixPath then
# Don’t set this for flake‐based systems.
null
else if config.system.stateVersion >= 6 then
"/etc/nix-darwin/configuration.nix"
else
"$HOME/.nixpkgs/darwin-configuration.nix"
"''${config.system.primaryUserHome}/.nixpkgs/darwin-configuration.nix"
'';
description = ''
The path of the darwin configuration.nix used to configure the system,
Expand Down Expand Up @@ -175,6 +175,16 @@ in

config = {

# This is horrible, sorry.
system.requiresPrimaryUser = mkIf (
config.nix.enable
&& !config.nixpkgs.flake.setNixPath
&& config.system.stateVersion < 6
&& options.environment.darwinConfig.highestPrio == (mkOptionDefault {}).priority
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hate that I can't think of a better way to check that this option wasn't changed from the default

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only way I've done it, too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it’s awful and I hate it. But I hate not giving good error messages when doing complicated migrations even more.

) [
"environment.darwinConfig"
];

environment.systemPath = mkMerge [
[ (makeBinPath cfg.profiles) ]
(mkOrder 1200 [ "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin" ])
Expand Down
2 changes: 2 additions & 0 deletions modules/examples/lnl.nix
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{ config, lib, inputs, pkgs, ... }:

{
system.primaryUser = "lnl";

system.defaults.NSGlobalDomain.AppleKeyboardUIMode = 3;
system.defaults.NSGlobalDomain.ApplePressAndHoldEnabled = false;
system.defaults.NSGlobalDomain.InitialKeyRepeat = 10;
Expand Down
18 changes: 18 additions & 0 deletions modules/homebrew.nix
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,17 @@ in
This module also provides a few options for modifying how Homebrew commands behave when
you manually invoke them, under [](#opt-homebrew.global)'';

user = mkOption {
type = types.str;
default = config.system.primaryUser;
defaultText = literalExpression "config.system.primaryUser";
description = ''
The user that owns the Homebrew installation. In most cases
this should be the normal user account that you installed
Homebrew as.
'';
};

brewPrefix = mkOption {
type = types.str;
default = if pkgs.stdenv.hostPlatform.isAarch64 then "/opt/homebrew/bin" else "/usr/local/bin";
Expand Down Expand Up @@ -764,6 +775,10 @@ in
(mkIf (options.homebrew.autoUpdate.isDefined || options.homebrew.cleanup.isDefined) "The `homebrew' module no longer upgrades outdated formulae and apps by default during `nix-darwin' system activation. To enable upgrading, set `homebrew.onActivation.upgrade = true'.")
];

system.requiresPrimaryUser = mkIf (cfg.enable && options.homebrew.user.highestPrio == (mkOptionDefault {}).priority) [
"homebrew.enable"
];

homebrew.brews =
optional (cfg.whalebrews != [ ]) "whalebrew";

Expand All @@ -786,6 +801,9 @@ in
echo >&2 "Homebrew bundle..."
if [ -f "${cfg.brewPrefix}/brew" ]; then
PATH="${cfg.brewPrefix}:${lib.makeBinPath [ pkgs.mas ]}:$PATH" \
sudo \
--user=${escapeShellArg cfg.user} \
--set-home \
${cfg.onActivation.brewBundleCmd}
else
echo -e "\e[1;31merror: Homebrew is not installed, skipping...\e[0m" >&2
Expand Down
23 changes: 22 additions & 1 deletion modules/launchd/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,16 @@ in

launchd.user.agents = mkOption {
default = {};
type = types.attrsOf (types.submodule serviceOptions);
type = types.attrsOf (types.submodule [
serviceOptions
({ name, ... }: {
options.managedBy = lib.mkOption {
type = lib.types.str;
internal = true;
default = lib.showOption [ "launchd" "user" "agents" name ];
};
})
]);
description = ''
Definition of per-user launchd agents.

Expand All @@ -187,6 +196,18 @@ in

config = {

system.requiresPrimaryUser =
lib.map (
name:
lib.showOption [
"launchd"
"user"
"envVariables"
name
]
) (attrNames cfg.user.envVariables)
++ lib.map ({ managedBy, ... }: managedBy) (attrValues cfg.user.agents);

environment.launchAgents = mapAttrs' toEnvironmentText cfg.agents;
environment.launchDaemons = mapAttrs' toEnvironmentText cfg.daemons;

Expand Down
1 change: 1 addition & 0 deletions modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
./security/sudo.nix
./system
./system/base.nix
./system/primary-user.nix
./system/checks.nix
./system/activation-scripts.nix
./system/applications.nix
Expand Down
13 changes: 10 additions & 3 deletions modules/nix/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -825,11 +825,18 @@ in

# Not in NixOS module
nix.nixPath = mkIf (config.system.stateVersion < 2) (mkDefault [
"darwin=$HOME/.nix-defexpr/darwin"
"darwin-config=$HOME/.nixpkgs/darwin-configuration.nix"
"darwin=${config.system.primaryUserHome}/.nix-defexpr/darwin"
"darwin-config=${config.system.primaryUserHome}/.nixpkgs/darwin-configuration.nix"
"/nix/var/nix/profiles/per-user/root/channels"
]);

system.requiresPrimaryUser = mkIf (
config.system.stateVersion < 2
&& options.nix.nixPath.highestPrio == (mkDefault {}).priotity
) [
"nix.nixPath"
];

# Set up the environment variables for running Nix.
environment.variables = cfg.envVars // { NIX_PATH = cfg.nixPath; };

Expand Down Expand Up @@ -869,7 +876,7 @@ in
#
# TODO: Maybe this could use a more general file placement mechanism
# to express that we want it deleted and know only one hash?
system.activationScripts.etcChecks.text = mkAfter ''
system.activationScripts.checks.text = mkAfter ''
nixCustomConfKnownSha256Hashes=(
# v0.33.0
6787fade1cf934f82db554e78e1fc788705c2c5257fddf9b59bdd963ca6fec63
Expand Down
1 change: 1 addition & 0 deletions modules/nix/nix-darwin.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ let
inherit (config.system) profile;
inherit (config.environment) systemPath;
nixPath = lib.optionalString config.nix.enable (lib.concatStringsSep ":" config.nix.nixPath);
nixPackage = if config.nix.enable then config.nix.package else null;
};

darwin-uninstaller = pkgs.callPackage ../../pkgs/darwin-uninstaller { };
Expand Down
44 changes: 42 additions & 2 deletions modules/services/activate-system/default.nix
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
{ config, lib, pkgs, ... }:

let
activationPath =
lib.makeBinPath (
[
pkgs.gnugrep
pkgs.coreutils
] ++ lib.optionals config.nix.enable [ config.nix.package ]
)
+ lib.optionalString (!config.nix.enable) ''
$(
# If `nix.enable` is off, there might be an unmanaged Nix
# installation (say in `/nix/var/nix/profiles/default`) that
# activation scripts (such as Home Manager) want to find on the
# `$PATH`. Search for it directly to avoid polluting the
# activation script environment with everything on the
# `environment.systemPath`.
if nixEnvPath=$(
PATH="${config.environment.systemPath}" command -v nix-env
); then
printf ':'
${lib.getExe' pkgs.coreutils "dirname"} -- "$(
${lib.getExe' pkgs.coreutils "readlink"} \
--canonicalize-missing \
-- "$nixEnvPath"
)"
fi
)''
+ ":/usr/bin:/bin:/usr/sbin:/sbin";
in

{
imports = [
(lib.mkRemovedOptionModule [ "services" "activate-system" "enable" ] "The `activate-system` service is now always enabled as it is necessary for a working `nix-darwin` setup.")
Expand All @@ -10,7 +40,17 @@
script = ''
set -e
set -o pipefail
export PATH="${pkgs.gnugrep}/bin:${pkgs.coreutils}/bin:@out@/sw/bin:/usr/bin:/bin:/usr/sbin:/sbin"

PATH="${activationPath}"

export PATH
export USER=root
export LOGNAME=root
export HOME=~root
export MAIL=/var/mail/root
export SHELL=$BASH
export LANG=C
export LC_CTYPE=UTF-8

systemConfig=$(cat ${config.system.profile}/systemConfig)

Expand All @@ -25,7 +65,7 @@
ln -sfn /run/current-system /nix/var/nix/gcroots/current-system
fi

${config.system.activationScripts.etcChecks.text}
${config.system.activationScripts.checks.text}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The one thing I am concerned about here is if checks has stuff that needs to be run in a graphical context. Based on a quick search through our in-tree checks it seems like this change would cause errors for the activation daemon from modules/users/default.nix in some cases, it might cause errors for our other checks, and might for out-of-tree checks if people were assuming that checks would only run in a graphical session.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The activation daemon only activates system configurations that were previously current. So in theory it should never be trying to delete users and so on. What other checks do you think might be problematic here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, good point. I don't have any problematic checks I can think of, and they should be read-only anyway, so I'm good with this.

${config.system.activationScripts.etc.text}
${config.system.activationScripts.keyboard.text}
'';
Expand Down
Loading