From c3bddd3e915a4a7da75f6b76045ff4a9e17b0fe2 Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Mon, 7 Dec 2020 18:14:48 -0800 Subject: [PATCH 01/18] Add Homebrew Bundle module --- modules/module-list.nix | 1 + modules/programs/brew-bundle.nix | 202 ++++++++++++++++++++++++++ modules/system/activation-scripts.nix | 1 + 3 files changed, 204 insertions(+) create mode 100644 modules/programs/brew-bundle.nix diff --git a/modules/module-list.nix b/modules/module-list.nix index d7ba55091..bb7459ece 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -59,6 +59,7 @@ ./services/yabai ./services/nextdns ./programs/bash + ./programs/brew-bundle.nix ./programs/fish.nix ./programs/gnupg.nix ./programs/man.nix diff --git a/modules/programs/brew-bundle.nix b/modules/programs/brew-bundle.nix new file mode 100644 index 000000000..866ca8377 --- /dev/null +++ b/modules/programs/brew-bundle.nix @@ -0,0 +1,202 @@ +# Created by: https://github.com/malob +# Inspired by: https://github.com/lccambiaghi/nixpkgs/blob/main/modules/homebrew.nix +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.brew-bundle; + + brewfileSection = heading: type: entries: + if entries != [] then + "# ${heading}\n" + (concatMapStrings (name: "${type} \"${name}\"\n") entries) + "\n" + else ""; + + masBrewfileSection = entries: + if entries != {} then + "# Mac App Store apps\n" + + concatStringsSep "\n" (mapAttrsToList (name: id: ''mas "${name}", id: ${toString id}'') entries) + + "\n" + else ""; + + brewfile = pkgs.writeText "Brewfile" ( + (brewfileSection "Taps" "tap" cfg.taps) + + (brewfileSection "Brews" "brew" cfg.brews) + + (brewfileSection "Casks" "cask" cfg.casks) + + (masBrewfileSection cfg.masApps) + + (brewfileSection "Docker contrainers" "whalebrew" cfg.whalebrews) + + (if cfg.extraConfig != "" then "# Extra config\n" + cfg.extraConfig else "") + ); + + brew-bunble-options = + "--file='${brewfile}' --no-lock" + + (if cfg.cleanupType == "uninstall" || cfg.cleanupType == "zap" then " --cleanup" else "") + + (if cfg.cleanupType == "zap" then " --zap" else ""); + +in + +{ + options.programs.brew-bundle = { + enable = mkEnableOption '' + Enables configuring your Brewfile, and installing/updating the formulas therein via + the brew bundle command, using nix-darwin. + + Note that enabling this option does not install Homebrew. See the Homebrew website for + installation instructions: + https://brew.sh + ''; + + cleanupType = mkOption { + type = with types; enum [ "none" "uninstall" "zap" ]; + default = "uninstall"; + example = "none"; + description = '' + This option manages what happens to formulas installed by Homebrew, that aren't present in + the Brewfile generated by this module. + + When set to "none" (the default), formulas not present in the generated + Brewfile are left installed. + + When set to "uninstall", nix-darwin invokes + brew bundle install with the --cleanup flag. This + uninstalls all formulas not listed in generate Brewfile, i.e., + brew uninstall is run for those formulas. + + When set to "zap", nix-darwin invokes + brew bundle install with the --cleanup --zap + flags. This uninstalls all forumalas not listed in the generated Brewfile, and if the + formula is a cask, removes all files associated with the cask. In other words, + brew uninstall --zap is run for all those formulas. + + If you plan on exclusively using nix-darwin to manage formulas installed + by Homebrew, you probably want to set this option to "uninstall" or + "zap". + ''; + }; + + setNoLockEnvvar = mkOption { + type = types.bool; + default = true; + description = '' + Sets the HOMEBREW_BUNDLE_NO_LOCK enviroment variable, by adding it to + , so that lock files aren't generated when/if you run + the brew bundle command yourself. + ''; + }; + + setBrewfileEnvvar = mkOption { + type = types.bool; + default = true; + description = '' + Sets the HOMEBREW_BUNDLE_FILE enviroment variable to the path of the + Brewfile in the Nix store that this module generates, by adding it to + . + + With this option enabled, brew bundle commands will automatically use + the Brewfile in the Nix store that this module generates. + ''; + }; + + taps = mkOption { + type = with types; listOf str; + default = []; + example = [ "homebrew/cask-fonts" ]; + description = "Homebrew formula repositories to tap"; + }; + + brews = mkOption { + type = with types; listOf str; + default = []; + example = [ "mas" ]; + description = "Homebrew brews to install"; + }; + + casks = mkOption { + type = with types; listOf str; + default = []; + example = [ "hammerspoon" "virtualbox" ]; + description = "Homebrew casks to install"; + }; + + masApps = mkOption { + type = with types; attrsOf int; + default = {}; + example = { + "1Password" = 1107421413; + Xcode = 497799835; + }; + description = '' + Applications to install from Mac App Store using mas. + + When this option is set to a non-empty list, "mas" is automatically added + to . + + Note that you need to be signed into the Mac App Store for mas to + successfully install and upgrade applications, and that unfortunately apps removed from this + option will not be uninstalled automatically even if + is set to "uninstall" + or "zap" (this is currently a limitation of Homebrew Bundle). + + For more information on mas see: + https://github.com/mas-cli/mas + ''; + }; + + whalebrews = mkOption { + type = with types; listOf str; + default = []; + example = [ "whalebrew/wget" ]; + description = '' + Docker images to install using whalebrew. + + When this option is set to a non-empty list, "whalebrew" is automatically + added to . + + For more information on whalebrew see: + https://github.com/whalebrew/whalebrew + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + example = '' + # 'brew tap' with custom Git URL + tap "user/tap-repo", "https://user@bitbucket.org/user/homebrew-tap-repo.git" + + # set arguments for all 'brew cask install' commands + cask_args appdir: "~/Applications", require_sha: true + + # 'brew install --with-rmtp', 'brew services restart' on version changes + brew "denji/nginx/nginx-full", args: ["with-rmtp"], restart_service: :changed + # 'brew install', always 'brew services restart', 'brew link', 'brew unlink mysql' (if it is installed) + brew "mysql@5.6", restart_service: true, link: true, conflicts_with: ["mysql"] + + # 'brew install --with-rmtp', 'brew services restart' on version changes + brew "denji/nginx/nginx-full", args: ["with-rmtp"], restart_service: :changed + # 'brew install', always 'brew services restart', 'brew link', 'brew unlink mysql' (if it is installed) + brew "mysql@5.6", restart_service: true, link: true, conflicts_with: ["mysql"] + ''; + description = "Extra lines to be added verbatim to the generated Brewfile."; + }; + }; + + config = { + programs.brew-bundle.brews = + optional (cfg.masApps != {}) "mas" ++ + optional (cfg.whalebrews != []) "whalebrew"; + + environment.variables = mkIf cfg.enable ( + (if cfg.setNoLockEnvvar then { HOMEBREW_BUNDLE_NO_LOCK = "1"; } else {}) // + (if cfg.setBrewfileEnvvar then { HOMEBREW_BUNDLE_FILE = "${brewfile}"; } else {}) + ); + + system.activationScripts.brew-bundle.text = mkIf cfg.enable '' + # Homebrew Bundle + echo >&2 "Homebrew bundle..." + PATH=/usr/local/bin:$PATH brew update > /dev/null + PATH=/usr/local/bin:$PATH brew bundle ${brew-bunble-options} + ''; + }; + +} diff --git a/modules/system/activation-scripts.nix b/modules/system/activation-scripts.nix index a9aac25be..cd7fe8ce0 100644 --- a/modules/system/activation-scripts.nix +++ b/modules/system/activation-scripts.nix @@ -65,6 +65,7 @@ in ${cfg.activationScripts.networking.text} ${cfg.activationScripts.keyboard.text} ${cfg.activationScripts.fonts.text} + ${cfg.activationScripts.brew-bundle.text} ${cfg.activationScripts.postActivation.text} From 680c3e0c17470470d6c9807828869c0fe9c3e701 Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Tue, 8 Dec 2020 10:17:09 -0800 Subject: [PATCH 02/18] Add assertion checking that Homebrew is installed --- modules/programs/brew-bundle.nix | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/modules/programs/brew-bundle.nix b/modules/programs/brew-bundle.nix index 866ca8377..35a09e3db 100644 --- a/modules/programs/brew-bundle.nix +++ b/modules/programs/brew-bundle.nix @@ -182,6 +182,19 @@ in }; config = { + assertions = mkIf cfg.enable [ + { + assertion = builtins.pathExists /usr/local/bin/brew; + message = '' + Homebrew not installed. + + Please install Homebrew yourself before using the programs.brew-bundle module. + + See installation instructions at: https://brew.sh + ''; + } + ]; + programs.brew-bundle.brews = optional (cfg.masApps != {}) "mas" ++ optional (cfg.whalebrews != []) "whalebrew"; From 31b0d5cb59a25fd383b9d7cb838925d30e7a4289 Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Tue, 8 Dec 2020 10:33:46 -0800 Subject: [PATCH 03/18] Move brew-bundle activation to user --- modules/system/activation-scripts.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/system/activation-scripts.nix b/modules/system/activation-scripts.nix index cd7fe8ce0..a194bdfd7 100644 --- a/modules/system/activation-scripts.nix +++ b/modules/system/activation-scripts.nix @@ -65,7 +65,6 @@ in ${cfg.activationScripts.networking.text} ${cfg.activationScripts.keyboard.text} ${cfg.activationScripts.fonts.text} - ${cfg.activationScripts.brew-bundle.text} ${cfg.activationScripts.postActivation.text} @@ -106,6 +105,7 @@ in ${cfg.activationScripts.extraUserActivation.text} ${cfg.activationScripts.userDefaults.text} ${cfg.activationScripts.userLaunchd.text} + ${cfg.activationScripts.brew-bundle.text} ${cfg.activationScripts.postUserActivation.text} From ef8d9630cac09e32bbf9a83e2d423a0e176abef4 Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Tue, 8 Dec 2020 11:42:15 -0800 Subject: [PATCH 04/18] Fix brew-bundle.extraConfig example --- modules/programs/brew-bundle.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/programs/brew-bundle.nix b/modules/programs/brew-bundle.nix index 35a09e3db..209cd3dae 100644 --- a/modules/programs/brew-bundle.nix +++ b/modules/programs/brew-bundle.nix @@ -172,10 +172,10 @@ in # 'brew install', always 'brew services restart', 'brew link', 'brew unlink mysql' (if it is installed) brew "mysql@5.6", restart_service: true, link: true, conflicts_with: ["mysql"] - # 'brew install --with-rmtp', 'brew services restart' on version changes - brew "denji/nginx/nginx-full", args: ["with-rmtp"], restart_service: :changed - # 'brew install', always 'brew services restart', 'brew link', 'brew unlink mysql' (if it is installed) - brew "mysql@5.6", restart_service: true, link: true, conflicts_with: ["mysql"] + # 'brew cask install --appdir=~/my-apps/Applications' + cask "firefox", args: { appdir: "~/my-apps/Applications" } + # 'brew cask install' only if '/usr/libexec/java_home --failfast' fails + cask "java" unless system "/usr/libexec/java_home --failfast" ''; description = "Extra lines to be added verbatim to the generated Brewfile."; }; From fcb9659b203b17a6920a44fa33d97e7e009c17ac Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Tue, 8 Dec 2020 12:22:27 -0800 Subject: [PATCH 05/18] Improve brew-bundle module documentation --- modules/programs/brew-bundle.nix | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/modules/programs/brew-bundle.nix b/modules/programs/brew-bundle.nix index 209cd3dae..33e07b34a 100644 --- a/modules/programs/brew-bundle.nix +++ b/modules/programs/brew-bundle.nix @@ -38,18 +38,17 @@ in { options.programs.brew-bundle = { enable = mkEnableOption '' - Enables configuring your Brewfile, and installing/updating the formulas therein via + configuring your Brewfile, and installing/updating the formulas therein via the brew bundle command, using nix-darwin. Note that enabling this option does not install Homebrew. See the Homebrew website for - installation instructions: - https://brew.sh + installation instructions: https://brew.sh ''; cleanupType = mkOption { type = with types; enum [ "none" "uninstall" "zap" ]; - default = "uninstall"; - example = "none"; + default = "none"; + example = "uninstall"; description = '' This option manages what happens to formulas installed by Homebrew, that aren't present in the Brewfile generated by this module. @@ -128,8 +127,8 @@ in description = '' Applications to install from Mac App Store using mas. - When this option is set to a non-empty list, "mas" is automatically added - to . + When this option is used, "mas" is automatically added to + . Note that you need to be signed into the Mac App Store for mas to successfully install and upgrade applications, and that unfortunately apps removed from this @@ -137,8 +136,7 @@ in is set to "uninstall" or "zap" (this is currently a limitation of Homebrew Bundle). - For more information on mas see: - https://github.com/mas-cli/mas + For more information on mas see: https://github.com/mas-cli/mas ''; }; @@ -149,8 +147,8 @@ in description = '' Docker images to install using whalebrew. - When this option is set to a non-empty list, "whalebrew" is automatically - added to . + When this option is used, "whalebrew" is automatically added to + . For more information on whalebrew see: https://github.com/whalebrew/whalebrew From 102a09dc16f8443c9f72c01407434bb0836a75f0 Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Thu, 10 Dec 2020 11:06:34 -0800 Subject: [PATCH 06/18] Add brew-bundle.noAutoUpdate with true as default --- modules/programs/brew-bundle.nix | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/modules/programs/brew-bundle.nix b/modules/programs/brew-bundle.nix index 33e07b34a..c5939d5e1 100644 --- a/modules/programs/brew-bundle.nix +++ b/modules/programs/brew-bundle.nix @@ -28,8 +28,10 @@ let (if cfg.extraConfig != "" then "# Extra config\n" + cfg.extraConfig else "") ); - brew-bunble-options = - "--file='${brewfile}' --no-lock" + + brew-bundle-command = + "HOMEBREW_NO_AUTO_UPDATE=" + + (if cfg.noAutoUpdate then "1" else "0") + + " brew bundle --file='${brewfile}' --no-lock" + (if cfg.cleanupType == "uninstall" || cfg.cleanupType == "zap" then " --cleanup" else "") + (if cfg.cleanupType == "zap" then " --zap" else ""); @@ -45,8 +47,19 @@ in installation instructions: https://brew.sh ''; + noAutoUpdate = mkOption { + type = types.bool; + default = true; + example = false; + description = '' + Sets the HOMEBREW_NO_AUTO_UPDATE environment variable when running the + brew bundle command. The default is true so that + repeated invocations of darwin-rebuild switch are idempotent. + ''; + }; + cleanupType = mkOption { - type = with types; enum [ "none" "uninstall" "zap" ]; + type = types.enum [ "none" "uninstall" "zap" ]; default = "none"; example = "uninstall"; description = '' @@ -205,8 +218,7 @@ in system.activationScripts.brew-bundle.text = mkIf cfg.enable '' # Homebrew Bundle echo >&2 "Homebrew bundle..." - PATH=/usr/local/bin:$PATH brew update > /dev/null - PATH=/usr/local/bin:$PATH brew bundle ${brew-bunble-options} + PATH=/usr/local/bin:$PATH ${brew-bundle-command} ''; }; From a38892c6c86dff99b7354d7bbb52e4edf71c4720 Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Mon, 14 Dec 2020 16:06:41 -0800 Subject: [PATCH 07/18] Rename brew-bunble.cleanupType to cleanup --- modules/programs/brew-bundle.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/programs/brew-bundle.nix b/modules/programs/brew-bundle.nix index c5939d5e1..0d4380de7 100644 --- a/modules/programs/brew-bundle.nix +++ b/modules/programs/brew-bundle.nix @@ -32,8 +32,8 @@ let "HOMEBREW_NO_AUTO_UPDATE=" + (if cfg.noAutoUpdate then "1" else "0") + " brew bundle --file='${brewfile}' --no-lock" + - (if cfg.cleanupType == "uninstall" || cfg.cleanupType == "zap" then " --cleanup" else "") + - (if cfg.cleanupType == "zap" then " --zap" else ""); + (if cfg.cleanup == "uninstall" || cfg.cleanup == "zap" then " --cleanup" else "") + + (if cfg.cleanup == "zap" then " --zap" else ""); in @@ -58,7 +58,7 @@ in ''; }; - cleanupType = mkOption { + cleanup = mkOption { type = types.enum [ "none" "uninstall" "zap" ]; default = "none"; example = "uninstall"; @@ -146,7 +146,7 @@ in Note that you need to be signed into the Mac App Store for mas to successfully install and upgrade applications, and that unfortunately apps removed from this option will not be uninstalled automatically even if - is set to "uninstall" + is set to "uninstall" or "zap" (this is currently a limitation of Homebrew Bundle). For more information on mas see: https://github.com/mas-cli/mas From df06dc470f1b4f04ecbb4c69872c1bdc10ab283d Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Mon, 14 Dec 2020 19:09:58 -0800 Subject: [PATCH 08/18] Update names of options that set user env vars in brew-bundle module --- modules/programs/brew-bundle.nix | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/modules/programs/brew-bundle.nix b/modules/programs/brew-bundle.nix index 0d4380de7..295a07657 100644 --- a/modules/programs/brew-bundle.nix +++ b/modules/programs/brew-bundle.nix @@ -86,26 +86,28 @@ in ''; }; - setNoLockEnvvar = mkOption { + userConfig.brewfile = mkOption { type = types.bool; default = true; description = '' - Sets the HOMEBREW_BUNDLE_NO_LOCK enviroment variable, by adding it to - , so that lock files aren't generated when/if you run - the brew bundle command yourself. + When enabled, when you manually invoke brew bundle, it will automatically + use the Brewfile in the Nix store that this module generates. + + Sets the HOMEBREW_BUNDLE_FILE enviroment variable to the path of the + Brewfile in the Nix store that this module generates, by adding it to + . ''; }; - setBrewfileEnvvar = mkOption { + userConfig.noLock = mkOption { type = types.bool; default = true; description = '' - Sets the HOMEBREW_BUNDLE_FILE enviroment variable to the path of the - Brewfile in the Nix store that this module generates, by adding it to - . + When enabled, lock files aren't generated when you manually invoke + brew bundle. - With this option enabled, brew bundle commands will automatically use - the Brewfile in the Nix store that this module generates. + Sets the HOMEBREW_BUNDLE_NO_LOCK enviroment variable, by adding it to + . ''; }; @@ -211,8 +213,8 @@ in optional (cfg.whalebrews != []) "whalebrew"; environment.variables = mkIf cfg.enable ( - (if cfg.setNoLockEnvvar then { HOMEBREW_BUNDLE_NO_LOCK = "1"; } else {}) // - (if cfg.setBrewfileEnvvar then { HOMEBREW_BUNDLE_FILE = "${brewfile}"; } else {}) + (if cfg.userConfig.brewfile then { HOMEBREW_BUNDLE_FILE = "${brewfile}"; } else {}) // + (if cfg.userConfig.noLock then { HOMEBREW_BUNDLE_NO_LOCK = "1"; } else {}) ); system.activationScripts.brew-bundle.text = mkIf cfg.enable '' From a2146feaf624584472fd9b0ea5b57f6f846c2334 Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Mon, 14 Dec 2020 19:28:31 -0800 Subject: [PATCH 09/18] Change noAutoUpdate option to autoUpdate in brew-bundle module --- modules/programs/brew-bundle.nix | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/modules/programs/brew-bundle.nix b/modules/programs/brew-bundle.nix index 295a07657..d5ba88e80 100644 --- a/modules/programs/brew-bundle.nix +++ b/modules/programs/brew-bundle.nix @@ -29,9 +29,8 @@ let ); brew-bundle-command = - "HOMEBREW_NO_AUTO_UPDATE=" + - (if cfg.noAutoUpdate then "1" else "0") + - " brew bundle --file='${brewfile}' --no-lock" + + (if cfg.autoUpdate then "" else "HOMEBREW_NO_AUTO_UPDATE=1 ") + + "brew bundle --file='${brewfile}' --no-lock" + (if cfg.cleanup == "uninstall" || cfg.cleanup == "zap" then " --cleanup" else "") + (if cfg.cleanup == "zap" then " --zap" else ""); @@ -47,14 +46,13 @@ in installation instructions: https://brew.sh ''; - noAutoUpdate = mkOption { + autoUpdate = mkOption { type = types.bool; - default = true; - example = false; + default = false; description = '' - Sets the HOMEBREW_NO_AUTO_UPDATE environment variable when running the - brew bundle command. The default is true so that - repeated invocations of darwin-rebuild switch are idempotent. + When enabled, Homebrew is allowed to auto-update during nix-darwin + activation. The default is false so that repeated invocations of + darwin-rebuild switch are idempotent. ''; }; From e1425db70d27980293623675af0ca93431edec95 Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Thu, 17 Dec 2020 13:03:57 -0800 Subject: [PATCH 10/18] Move programs.brew-bundle to homebrew --- .../{programs/brew-bundle.nix => homebrew.nix} | 16 ++++++++-------- modules/module-list.nix | 2 +- modules/system/activation-scripts.nix | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) rename modules/{programs/brew-bundle.nix => homebrew.nix} (94%) diff --git a/modules/programs/brew-bundle.nix b/modules/homebrew.nix similarity index 94% rename from modules/programs/brew-bundle.nix rename to modules/homebrew.nix index d5ba88e80..2d142b039 100644 --- a/modules/programs/brew-bundle.nix +++ b/modules/homebrew.nix @@ -5,7 +5,7 @@ with lib; let - cfg = config.programs.brew-bundle; + cfg = config.homebrew; brewfileSection = heading: type: entries: if entries != [] then @@ -37,7 +37,7 @@ let in { - options.programs.brew-bundle = { + options.homebrew = { enable = mkEnableOption '' configuring your Brewfile, and installing/updating the formulas therein via the brew bundle command, using nix-darwin. @@ -141,12 +141,12 @@ in Applications to install from Mac App Store using mas. When this option is used, "mas" is automatically added to - . + . Note that you need to be signed into the Mac App Store for mas to successfully install and upgrade applications, and that unfortunately apps removed from this option will not be uninstalled automatically even if - is set to "uninstall" + is set to "uninstall" or "zap" (this is currently a limitation of Homebrew Bundle). For more information on mas see: https://github.com/mas-cli/mas @@ -161,7 +161,7 @@ in Docker images to install using whalebrew. When this option is used, "whalebrew" is automatically added to - . + . For more information on whalebrew see: https://github.com/whalebrew/whalebrew @@ -199,14 +199,14 @@ in message = '' Homebrew not installed. - Please install Homebrew yourself before using the programs.brew-bundle module. + Please install Homebrew yourself before using the module. See installation instructions at: https://brew.sh ''; } ]; - programs.brew-bundle.brews = + homebrew.brews = optional (cfg.masApps != {}) "mas" ++ optional (cfg.whalebrews != []) "whalebrew"; @@ -215,7 +215,7 @@ in (if cfg.userConfig.noLock then { HOMEBREW_BUNDLE_NO_LOCK = "1"; } else {}) ); - system.activationScripts.brew-bundle.text = mkIf cfg.enable '' + system.activationScripts.homebrew.text = mkIf cfg.enable '' # Homebrew Bundle echo >&2 "Homebrew bundle..." PATH=/usr/local/bin:$PATH ${brew-bundle-command} diff --git a/modules/module-list.nix b/modules/module-list.nix index bb7459ece..447d07576 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -59,7 +59,6 @@ ./services/yabai ./services/nextdns ./programs/bash - ./programs/brew-bundle.nix ./programs/fish.nix ./programs/gnupg.nix ./programs/man.nix @@ -69,6 +68,7 @@ ./programs/tmux.nix ./programs/vim.nix ./programs/zsh + ./homebrew.nix ./users ./users/nixbld ] diff --git a/modules/system/activation-scripts.nix b/modules/system/activation-scripts.nix index a194bdfd7..346fb97ce 100644 --- a/modules/system/activation-scripts.nix +++ b/modules/system/activation-scripts.nix @@ -105,7 +105,7 @@ in ${cfg.activationScripts.extraUserActivation.text} ${cfg.activationScripts.userDefaults.text} ${cfg.activationScripts.userLaunchd.text} - ${cfg.activationScripts.brew-bundle.text} + ${cfg.activationScripts.homebrew.text} ${cfg.activationScripts.postUserActivation.text} From 9961b72463f0f0ba60f435424117d8ac98e70e8d Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Thu, 17 Dec 2020 14:42:07 -0800 Subject: [PATCH 11/18] Make better use of optional(s) functions in homebrew module --- modules/homebrew.nix | 46 +++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/modules/homebrew.nix b/modules/homebrew.nix index 2d142b039..f67945fcc 100644 --- a/modules/homebrew.nix +++ b/modules/homebrew.nix @@ -7,32 +7,30 @@ with lib; let cfg = config.homebrew; - brewfileSection = heading: type: entries: - if entries != [] then - "# ${heading}\n" + (concatMapStrings (name: "${type} \"${name}\"\n") entries) + "\n" - else ""; - - masBrewfileSection = entries: - if entries != {} then - "# Mac App Store apps\n" + - concatStringsSep "\n" (mapAttrsToList (name: id: ''mas "${name}", id: ${toString id}'') entries) + - "\n" - else ""; + brewfileSection = heading: type: entries: optionalString (entries != []) + "# ${heading}\n" + (concatMapStrings (name: "${type} \"${name}\"\n") entries) + "\n"; + + masBrewfileSection = entries: optionalString (entries != {}) ( + "# Mac App Store apps\n" + + concatStringsSep "\n" (mapAttrsToList (name: id: ''mas "${name}", id: ${toString id}'') entries) + + "\n" + ); brewfile = pkgs.writeText "Brewfile" ( - (brewfileSection "Taps" "tap" cfg.taps) + - (brewfileSection "Brews" "brew" cfg.brews) + - (brewfileSection "Casks" "cask" cfg.casks) + - (masBrewfileSection cfg.masApps) + - (brewfileSection "Docker contrainers" "whalebrew" cfg.whalebrews) + - (if cfg.extraConfig != "" then "# Extra config\n" + cfg.extraConfig else "") + brewfileSection "Taps" "tap" cfg.taps + + brewfileSection "Brews" "brew" cfg.brews + + brewfileSection "Casks" "cask" cfg.casks + + masBrewfileSection cfg.masApps + + brewfileSection "Docker contrainers" "whalebrew" cfg.whalebrews + + optionalString (cfg.extraConfig != "") ("# Extra config\n" + cfg.extraConfig) ); - brew-bundle-command = - (if cfg.autoUpdate then "" else "HOMEBREW_NO_AUTO_UPDATE=1 ") + - "brew bundle --file='${brewfile}' --no-lock" + - (if cfg.cleanup == "uninstall" || cfg.cleanup == "zap" then " --cleanup" else "") + - (if cfg.cleanup == "zap" then " --zap" else ""); + brew-bundle-command = concatStringsSep " " ( + optional (!cfg.autoUpdate) "HOMEBREW_NO_AUTO_UPDATE=1" ++ + [ "brew bundle --file='${brewfile}' --no-lock" ] ++ + optional (cfg.cleanup == "uninstall" || cfg.cleanup == "zap") "--cleanup" ++ + optional (cfg.cleanup == "zap") "--zap" + ); in @@ -211,8 +209,8 @@ in optional (cfg.whalebrews != []) "whalebrew"; environment.variables = mkIf cfg.enable ( - (if cfg.userConfig.brewfile then { HOMEBREW_BUNDLE_FILE = "${brewfile}"; } else {}) // - (if cfg.userConfig.noLock then { HOMEBREW_BUNDLE_NO_LOCK = "1"; } else {}) + optionalAttrs cfg.userConfig.brewfile { HOMEBREW_BUNDLE_FILE = "${brewfile}"; } // + optionalAttrs cfg.userConfig.noLock { HOMEBREW_BUNDLE_NO_LOCK = "1"; } ); system.activationScripts.homebrew.text = mkIf cfg.enable '' From 6b561009825e70fee1624a636566f0bc233b80a3 Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Thu, 17 Dec 2020 16:54:29 -0800 Subject: [PATCH 12/18] Move Homebrew installation check to activation script --- modules/homebrew.nix | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/modules/homebrew.nix b/modules/homebrew.nix index f67945fcc..330006ad1 100644 --- a/modules/homebrew.nix +++ b/modules/homebrew.nix @@ -31,7 +31,6 @@ let optional (cfg.cleanup == "uninstall" || cfg.cleanup == "zap") "--cleanup" ++ optional (cfg.cleanup == "zap") "--zap" ); - in { @@ -191,19 +190,6 @@ in }; config = { - assertions = mkIf cfg.enable [ - { - assertion = builtins.pathExists /usr/local/bin/brew; - message = '' - Homebrew not installed. - - Please install Homebrew yourself before using the module. - - See installation instructions at: https://brew.sh - ''; - } - ]; - homebrew.brews = optional (cfg.masApps != {}) "mas" ++ optional (cfg.whalebrews != []) "whalebrew"; @@ -216,8 +202,11 @@ in system.activationScripts.homebrew.text = mkIf cfg.enable '' # Homebrew Bundle echo >&2 "Homebrew bundle..." - PATH=/usr/local/bin:$PATH ${brew-bundle-command} + if [ -f /usr/local/bin/brew ]; then + PATH=/usr/local/bin:$PATH ${brew-bundle-command} + else + echo -e "\e[1;31merror: Homebrew is not installed, skipping...\e[0m" >&2 + fi ''; }; - } From 7fd183c5d2ac0e68395cedd6395329479c108ab3 Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Fri, 18 Dec 2020 11:52:03 -0800 Subject: [PATCH 13/18] Remove homebrew.userConfig options and cleanup docs --- modules/homebrew.nix | 61 +++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 40 deletions(-) diff --git a/modules/homebrew.nix b/modules/homebrew.nix index 330006ad1..fff0ca2b9 100644 --- a/modules/homebrew.nix +++ b/modules/homebrew.nix @@ -1,5 +1,4 @@ # Created by: https://github.com/malob -# Inspired by: https://github.com/lccambiaghi/nixpkgs/blob/main/modules/homebrew.nix { config, lib, pkgs, ... }: with lib; @@ -39,6 +38,13 @@ in configuring your Brewfile, and installing/updating the formulas therein via the brew bundle command, using nix-darwin. + When enabled, the HOMEBREW_BUNDLE_FILE and + HOMEBREW_BUNDLE_NO_LOCK environment variables are added to + , so that when if/when you run + brew bundle yourself, it will reference the Brewfile generated by this + module in the store by default, and skip generating a lockfile (which would fail, since + lockfiles are generated in the same directory as the Brewfile). + Note that enabling this option does not install Homebrew. See the Homebrew website for installation instructions: https://brew.sh ''; @@ -65,14 +71,14 @@ in Brewfile are left installed. When set to "uninstall", nix-darwin invokes - brew bundle install with the --cleanup flag. This + brew bundle [install] with the --cleanup flag. This uninstalls all formulas not listed in generate Brewfile, i.e., brew uninstall is run for those formulas. When set to "zap", nix-darwin invokes - brew bundle install with the --cleanup --zap - flags. This uninstalls all forumalas not listed in the generated Brewfile, and if the - formula is a cask, removes all files associated with the cask. In other words, + brew bundle [install] with the --cleanup --zap + flags. This uninstalls all formulas not listed in the generated Brewfile, and if the + formula is a cask, removes all files associated with that cask. In other words, brew uninstall --zap is run for all those formulas. If you plan on exclusively using nix-darwin to manage formulas installed @@ -81,54 +87,29 @@ in ''; }; - userConfig.brewfile = mkOption { - type = types.bool; - default = true; - description = '' - When enabled, when you manually invoke brew bundle, it will automatically - use the Brewfile in the Nix store that this module generates. - - Sets the HOMEBREW_BUNDLE_FILE enviroment variable to the path of the - Brewfile in the Nix store that this module generates, by adding it to - . - ''; - }; - - userConfig.noLock = mkOption { - type = types.bool; - default = true; - description = '' - When enabled, lock files aren't generated when you manually invoke - brew bundle. - - Sets the HOMEBREW_BUNDLE_NO_LOCK enviroment variable, by adding it to - . - ''; - }; - taps = mkOption { type = with types; listOf str; default = []; example = [ "homebrew/cask-fonts" ]; - description = "Homebrew formula repositories to tap"; + description = "Homebrew formula repositories to tap."; }; brews = mkOption { type = with types; listOf str; default = []; example = [ "mas" ]; - description = "Homebrew brews to install"; + description = "Homebrew brews to install."; }; casks = mkOption { type = with types; listOf str; default = []; example = [ "hammerspoon" "virtualbox" ]; - description = "Homebrew casks to install"; + description = "Homebrew casks to install."; }; masApps = mkOption { - type = with types; attrsOf int; + type = with types; attrsOf ints.positive; default = {}; example = { "1Password" = 1107421413; @@ -146,7 +127,7 @@ in is set to "uninstall" or "zap" (this is currently a limitation of Homebrew Bundle). - For more information on mas see: https://github.com/mas-cli/mas + For more information on mas see: https://github.com/mas-cli/mas. ''; }; @@ -161,7 +142,7 @@ in . For more information on whalebrew see: - https://github.com/whalebrew/whalebrew + https://github.com/whalebrew/whalebrew. ''; }; @@ -194,10 +175,10 @@ in optional (cfg.masApps != {}) "mas" ++ optional (cfg.whalebrews != []) "whalebrew"; - environment.variables = mkIf cfg.enable ( - optionalAttrs cfg.userConfig.brewfile { HOMEBREW_BUNDLE_FILE = "${brewfile}"; } // - optionalAttrs cfg.userConfig.noLock { HOMEBREW_BUNDLE_NO_LOCK = "1"; } - ); + environment.variables = mkIf cfg.enable { + HOMEBREW_BUNDLE_FILE = "${brewfile}"; + HOMEBREW_BUNDLE_NO_LOCK = "1"; + }; system.activationScripts.homebrew.text = mkIf cfg.enable '' # Homebrew Bundle From 48449fbc0e160036250550cd3ddc2b44aaae0038 Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Fri, 18 Dec 2020 12:51:31 -0800 Subject: [PATCH 14/18] Add CHANGELOG entry --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 05c5f44d9..3caea3174 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +2020-12-18 +- Added `homebrew` module, to manage formulas installed by Homebrew via `brew bundle`. + 2020-10-25 - The option environment.variables.SHELL is no longer set automatically when, eg. programs.zsh.enable is configured. From c61d6591602b14105a779ad4f695f37437c49468 Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Mon, 28 Dec 2020 10:45:30 -0800 Subject: [PATCH 15/18] Fix typo in homebrew module Co-authored-by: Scott Day --- modules/homebrew.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/homebrew.nix b/modules/homebrew.nix index fff0ca2b9..ac89cf669 100644 --- a/modules/homebrew.nix +++ b/modules/homebrew.nix @@ -20,7 +20,7 @@ let brewfileSection "Brews" "brew" cfg.brews + brewfileSection "Casks" "cask" cfg.casks + masBrewfileSection cfg.masApps + - brewfileSection "Docker contrainers" "whalebrew" cfg.whalebrews + + brewfileSection "Docker containers" "whalebrew" cfg.whalebrews + optionalString (cfg.extraConfig != "") ("# Extra config\n" + cfg.extraConfig) ); From 2a0b9a9f60a3d3eaca57492f1a8d66082da370ea Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Wed, 30 Dec 2020 16:42:31 -0800 Subject: [PATCH 16/18] Add options back in for setting global Homebrew variables --- CHANGELOG | 2 +- modules/homebrew.nix | 43 ++++++++++++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3caea3174..18b6e6be8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,4 @@ -2020-12-18 +2020-12-30 - Added `homebrew` module, to manage formulas installed by Homebrew via `brew bundle`. 2020-10-25 diff --git a/modules/homebrew.nix b/modules/homebrew.nix index ac89cf669..5088f3c24 100644 --- a/modules/homebrew.nix +++ b/modules/homebrew.nix @@ -38,13 +38,6 @@ in configuring your Brewfile, and installing/updating the formulas therein via the brew bundle command, using nix-darwin. - When enabled, the HOMEBREW_BUNDLE_FILE and - HOMEBREW_BUNDLE_NO_LOCK environment variables are added to - , so that when if/when you run - brew bundle yourself, it will reference the Brewfile generated by this - module in the store by default, and skip generating a lockfile (which would fail, since - lockfiles are generated in the same directory as the Brewfile). - Note that enabling this option does not install Homebrew. See the Homebrew website for installation instructions: https://brew.sh ''; @@ -87,6 +80,34 @@ in ''; }; + global.brewfile = mkOption { + type = types.bool; + default = false; + description = '' + When enabled, when you manually invoke brew bundle, it will + automatically use the Brewfile in the Nix store that this module generates. + + Sets the HOMEBREW_BUNDLE_FILE environment variable to the path of the + Brewfile in the Nix store that this module generates, by adding it to + . + ''; + }; + + global.noLock = mkOption { + type = types.bool; + default = false; + description = '' + When enabled, lockfiles aren't generated when you manually invoke + brew bundle [install]. This is often desirable when + is enabled, since + brew bundle [install] will try to write the lockfile in the Nix store, + and complain that it can't (though the command will run successfully regardless). + + Sets the HOMEBREW_BUNDLE_NO_LOCK environment variable, by adding it to + . + ''; + }; + taps = mkOption { type = with types; listOf str; default = []; @@ -175,10 +196,10 @@ in optional (cfg.masApps != {}) "mas" ++ optional (cfg.whalebrews != []) "whalebrew"; - environment.variables = mkIf cfg.enable { - HOMEBREW_BUNDLE_FILE = "${brewfile}"; - HOMEBREW_BUNDLE_NO_LOCK = "1"; - }; + environment.variables = mkIf cfg.enable ( + optionalAttrs cfg.global.brewfile { HOMEBREW_BUNDLE_FILE = "${brewfile}"; } // + optionalAttrs cfg.global.noLock { HOMEBREW_BUNDLE_NO_LOCK = "1"; } + ); system.activationScripts.homebrew.text = mkIf cfg.enable '' # Homebrew Bundle From acc906d9824992443566e826f358b9ef943c3468 Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Sat, 16 Jan 2021 12:39:01 -0800 Subject: [PATCH 17/18] Update changelog and fix indentation. --- CHANGELOG | 2 +- modules/homebrew.nix | 52 ++++++++++++++++++++++---------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 18b6e6be8..1675b3e0f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,4 @@ -2020-12-30 +2021-01-16 - Added `homebrew` module, to manage formulas installed by Homebrew via `brew bundle`. 2020-10-25 diff --git a/modules/homebrew.nix b/modules/homebrew.nix index 5088f3c24..c3524d9f4 100644 --- a/modules/homebrew.nix +++ b/modules/homebrew.nix @@ -81,32 +81,32 @@ in }; global.brewfile = mkOption { - type = types.bool; - default = false; - description = '' - When enabled, when you manually invoke brew bundle, it will - automatically use the Brewfile in the Nix store that this module generates. - - Sets the HOMEBREW_BUNDLE_FILE environment variable to the path of the - Brewfile in the Nix store that this module generates, by adding it to - . - ''; - }; - - global.noLock = mkOption { - type = types.bool; - default = false; - description = '' - When enabled, lockfiles aren't generated when you manually invoke - brew bundle [install]. This is often desirable when - is enabled, since - brew bundle [install] will try to write the lockfile in the Nix store, - and complain that it can't (though the command will run successfully regardless). - - Sets the HOMEBREW_BUNDLE_NO_LOCK environment variable, by adding it to - . - ''; - }; + type = types.bool; + default = false; + description = '' + When enabled, when you manually invoke brew bundle, it will automatically + use the Brewfile in the Nix store that this module generates. + + Sets the HOMEBREW_BUNDLE_FILE environment variable to the path of the + Brewfile in the Nix store that this module generates, by adding it to + . + ''; + }; + + global.noLock = mkOption { + type = types.bool; + default = false; + description = '' + When enabled, lockfiles aren't generated when you manually invoke + brew bundle [install]. This is often desirable when + is enabled, since + brew bundle [install] will try to write the lockfile in the Nix store, + and complain that it can't (though the command will run successfully regardless). + + Sets the HOMEBREW_BUNDLE_NO_LOCK environment variable, by adding it to + . + ''; + }; taps = mkOption { type = with types; listOf str; From 23cb959893b56d526941bc7300acd6d69505f897 Mon Sep 17 00:00:00 2001 From: Malo Bourgon Date: Sat, 16 Jan 2021 15:15:29 -0800 Subject: [PATCH 18/18] Fix indentation again --- modules/homebrew.nix | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/modules/homebrew.nix b/modules/homebrew.nix index c3524d9f4..d67f5b2a0 100644 --- a/modules/homebrew.nix +++ b/modules/homebrew.nix @@ -84,12 +84,12 @@ in type = types.bool; default = false; description = '' - When enabled, when you manually invoke brew bundle, it will automatically - use the Brewfile in the Nix store that this module generates. + When enabled, when you manually invoke brew bundle, it will automatically + use the Brewfile in the Nix store that this module generates. - Sets the HOMEBREW_BUNDLE_FILE environment variable to the path of the - Brewfile in the Nix store that this module generates, by adding it to - . + Sets the HOMEBREW_BUNDLE_FILE environment variable to the path of the + Brewfile in the Nix store that this module generates, by adding it to + . ''; }; @@ -97,14 +97,14 @@ in type = types.bool; default = false; description = '' - When enabled, lockfiles aren't generated when you manually invoke - brew bundle [install]. This is often desirable when - is enabled, since - brew bundle [install] will try to write the lockfile in the Nix store, - and complain that it can't (though the command will run successfully regardless). - - Sets the HOMEBREW_BUNDLE_NO_LOCK environment variable, by adding it to - . + When enabled, lockfiles aren't generated when you manually invoke + brew bundle [install]. This is often desirable when + is enabled, since + brew bundle [install] will try to write the lockfile in the Nix store, + and complain that it can't (though the command will run successfully regardless). + + Sets the HOMEBREW_BUNDLE_NO_LOCK environment variable, by adding it to + . ''; };