modules/homebrew: add onActivation.cleanup "check" mode
Closes #1032 Add `"check"` to the `onActivation.cleanup` enum. When set, nix-darwin runs `brew bundle cleanup` during system checks to detect Homebrew packages that are installed but not present in the generated Brewfile. If extra packages are found, activation fails with a list of them and remediation steps. Unlike `"uninstall"` and `"zap"`, the `"check"` mode never removes packages -- it only reports. This runs during both `darwin-rebuild check` and `darwin-rebuild switch`, matching the behavior of all other system checks.
This commit is contained in:
parent
ca6f8609c3
commit
c68f5d1387
4 changed files with 66 additions and 9 deletions
|
|
@ -76,29 +76,36 @@ let
|
||||||
onActivationOptions = { config, ... }: {
|
onActivationOptions = { config, ... }: {
|
||||||
options = {
|
options = {
|
||||||
cleanup = mkOption {
|
cleanup = mkOption {
|
||||||
type = types.enum [ "none" "uninstall" "zap" ];
|
type = types.enum [ "none" "check" "uninstall" "zap" ];
|
||||||
default = "none";
|
default = "none";
|
||||||
example = "uninstall";
|
example = "uninstall";
|
||||||
description = ''
|
description = ''
|
||||||
This option manages what happens to formulae installed by Homebrew, that aren't present in
|
This option manages what happens to packages installed by Homebrew that aren't present in
|
||||||
the Brewfile generated by this module, during {command}`nix-darwin` system
|
the Brewfile generated by this module, during {command}`nix-darwin` system
|
||||||
activation.
|
activation.
|
||||||
|
|
||||||
When set to `"none"` (the default), formulae not present in the generated
|
When set to `"none"` (the default), packages not present in the generated
|
||||||
Brewfile are left installed.
|
Brewfile are left installed.
|
||||||
|
|
||||||
|
When set to `"check"`, {command}`nix-darwin` verifies during system activation that no
|
||||||
|
Homebrew packages (taps, formulae, casks, etc.) are installed that aren't present in the
|
||||||
|
generated Brewfile. If extra packages are found, activation fails with a list of them.
|
||||||
|
Note that when this check fails during {command}`darwin-rebuild switch`, the entire
|
||||||
|
system activation is aborted and no other configuration changes will be applied until
|
||||||
|
the issue is resolved.
|
||||||
|
|
||||||
When set to `"uninstall"`, {command}`nix-darwin` invokes
|
When set to `"uninstall"`, {command}`nix-darwin` invokes
|
||||||
{command}`brew bundle [install]` with the {command}`--cleanup` flag. This
|
{command}`brew bundle [install]` with the {command}`--cleanup` flag. This
|
||||||
uninstalls all formulae not listed in generated Brewfile, i.e.,
|
uninstalls all packages not listed in the generated Brewfile, i.e.,
|
||||||
{command}`brew uninstall` is run for those formulae.
|
{command}`brew uninstall` is run for those packages.
|
||||||
|
|
||||||
When set to `"zap"`, {command}`nix-darwin` invokes
|
When set to `"zap"`, {command}`nix-darwin` invokes
|
||||||
{command}`brew bundle [install]` with the {command}`--cleanup --zap`
|
{command}`brew bundle [install]` with the {command}`--cleanup --zap`
|
||||||
flags. This uninstalls all formulae not listed in the generated Brewfile, and if the
|
flags. This uninstalls all packages not listed in the generated Brewfile, and if the
|
||||||
formula is a cask, removes all files associated with that cask. In other words,
|
package is a cask, removes all files associated with that cask. In other words,
|
||||||
{command}`brew uninstall --zap` is run for all those formulae.
|
{command}`brew uninstall --zap` is run for all those packages.
|
||||||
|
|
||||||
If you plan on exclusively using {command}`nix-darwin` to manage formulae
|
If you plan on exclusively using {command}`nix-darwin` to manage packages
|
||||||
installed by Homebrew, you probably want to set this option to
|
installed by Homebrew, you probably want to set this option to
|
||||||
`"uninstall"` or `"zap"`.
|
`"uninstall"` or `"zap"`.
|
||||||
'';
|
'';
|
||||||
|
|
@ -879,6 +886,33 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
system.checks.text = mkIf (cfg.enable && cfg.onActivation.cleanup == "check") ''
|
||||||
|
if [ -f "${cfg.prefix}/bin/brew" ]; then
|
||||||
|
homebrewCleanupExitCode=0
|
||||||
|
homebrewCleanupResult=$(PATH="${cfg.prefix}/bin:${lib.makeBinPath [ pkgs.mas ]}:$PATH" \
|
||||||
|
sudo \
|
||||||
|
--preserve-env=PATH \
|
||||||
|
--user=${escapeShellArg cfg.user} \
|
||||||
|
--set-home \
|
||||||
|
env HOMEBREW_NO_AUTO_UPDATE=1 \
|
||||||
|
brew bundle cleanup --file='${brewfileFile}' 2>&1) || homebrewCleanupExitCode=$?
|
||||||
|
if [ "$homebrewCleanupExitCode" -eq 1 ]; then
|
||||||
|
printf >&2 '\e[1;31merror: found Homebrew packages not listed in the Brewfile, aborting activation\e[0m\n'
|
||||||
|
printf >&2 '%s\n' "$homebrewCleanupResult"
|
||||||
|
printf >&2 '\n'
|
||||||
|
printf >&2 'To fix this, either:\n'
|
||||||
|
printf >&2 ' - Add the listed packages to your nix-darwin Homebrew configuration\n'
|
||||||
|
printf >&2 ' - Remove them by running: brew bundle cleanup --force\n'
|
||||||
|
printf >&2 ' - Set homebrew.onActivation.cleanup to "uninstall" or "zap"\n'
|
||||||
|
exit 2
|
||||||
|
elif [ "$homebrewCleanupExitCode" -ne 0 ]; then
|
||||||
|
printf >&2 '\e[1;31merror: brew bundle cleanup failed, aborting activation\e[0m\n'
|
||||||
|
printf >&2 '%s\n' "$homebrewCleanupResult"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
system.activationScripts.homebrew.text = mkIf cfg.enable ''
|
system.activationScripts.homebrew.text = mkIf cfg.enable ''
|
||||||
# Homebrew Bundle
|
# Homebrew Bundle
|
||||||
echo >&2 "Homebrew bundle..."
|
echo >&2 "Homebrew bundle..."
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ in {
|
||||||
tests.environment-path = makeTest ./tests/environment-path.nix;
|
tests.environment-path = makeTest ./tests/environment-path.nix;
|
||||||
tests.environment-terminfo = makeTest ./tests/environment-terminfo.nix;
|
tests.environment-terminfo = makeTest ./tests/environment-terminfo.nix;
|
||||||
tests.homebrew = makeTest ./tests/homebrew.nix;
|
tests.homebrew = makeTest ./tests/homebrew.nix;
|
||||||
|
tests.homebrew-cleanup-check = makeTest ./tests/homebrew-cleanup-check.nix;
|
||||||
tests.homebrew-shell-integration = makeTest ./tests/homebrew-shell-integration.nix;
|
tests.homebrew-shell-integration = makeTest ./tests/homebrew-shell-integration.nix;
|
||||||
tests.launchd-daemons = makeTest ./tests/launchd-daemons.nix;
|
tests.launchd-daemons = makeTest ./tests/launchd-daemons.nix;
|
||||||
tests.launchd-setenv = makeTest ./tests/launchd-setenv.nix;
|
tests.launchd-setenv = makeTest ./tests/launchd-setenv.nix;
|
||||||
|
|
|
||||||
19
tests/homebrew-cleanup-check.nix
Normal file
19
tests/homebrew-cleanup-check.nix
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{ config, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
homebrew.enable = true;
|
||||||
|
homebrew.user = "test-homebrew-user";
|
||||||
|
homebrew.onActivation.cleanup = "check";
|
||||||
|
|
||||||
|
test = ''
|
||||||
|
echo "checking that cleanup check is present in system checks" >&2
|
||||||
|
grep 'brew bundle cleanup --file=' ${config.out}/activate
|
||||||
|
|
||||||
|
echo "checking that brew bundle command does not have --cleanup flag" >&2
|
||||||
|
if echo "${config.homebrew.onActivation.brewBundleCmd}" | grep -F -- '--cleanup' > /dev/null; then
|
||||||
|
echo "Expected no --cleanup flag in brewBundleCmd"
|
||||||
|
echo "Actual: ${config.homebrew.onActivation.brewBundleCmd}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
|
@ -128,5 +128,8 @@ in
|
||||||
|
|
||||||
echo "checking that shell integration is absent by default" >&2
|
echo "checking that shell integration is absent by default" >&2
|
||||||
(! grep 'brew shellenv' ${config.out}/etc/zshrc)
|
(! grep 'brew shellenv' ${config.out}/etc/zshrc)
|
||||||
|
|
||||||
|
echo "checking that cleanup check is absent by default" >&2
|
||||||
|
(! grep 'brew bundle cleanup --file=' ${config.out}/activate)
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue