Compare commits
111
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57a3171f94 | ||
|
|
c1403be257 | ||
|
|
b4cccbd4bc | ||
|
|
1543ae0852 | ||
|
|
a4cf1d1085 | ||
|
|
d5bd9cd77a | ||
|
|
b2217f8051 | ||
|
|
08920bcfd1 | ||
|
|
320cbf535b | ||
|
|
deadc7204c | ||
|
|
a1fa429e94 | ||
|
|
d8a6661f78 | ||
|
|
5138eaf896 | ||
|
|
e636bf1664 | ||
|
|
ee9c7b96c9 | ||
|
|
cd7cf09aa3 | ||
|
|
ee20edc445 | ||
|
|
bb9c29c193 | ||
|
|
08278afff6 | ||
|
|
aabb2037ed | ||
|
|
0bddd7a5ed | ||
|
|
9f8122dd2b | ||
|
|
818b88b75f | ||
|
|
d0d0978f34 | ||
|
|
ace757665e | ||
|
|
d9ffa378a6 | ||
|
|
b317d77bbf | ||
|
|
f73cbf1f65 | ||
|
|
958c16ba9a | ||
|
|
4bcdd687ca | ||
|
|
3f0f0ece39 | ||
|
|
57ff7cbd20 | ||
|
|
6a771120d6 | ||
|
|
f8531f95fe | ||
|
|
7c3d11b160 | ||
|
|
8073b91aa3 | ||
|
|
ae3e2b18d3 | ||
|
|
82325d90a1 | ||
|
|
56c666e108 | ||
|
|
3fe4b4fb3c | ||
|
|
426b6e8f02 | ||
|
|
905fe60936 | ||
|
|
4ec530e8b5 | ||
|
|
1e107a7b92 | ||
|
|
09b3575c2d | ||
|
|
8c62fba085 | ||
|
|
d0e2383e3f | ||
|
|
b1737791a9 | ||
|
|
1e2d8fbb37 | ||
|
|
3510d049d3 | ||
|
|
8f6396c0dc | ||
|
|
a0a51c56f0 | ||
|
|
06648f4902 | ||
|
|
ec2e2c72e7 | ||
|
|
5176e2f4b4 | ||
|
|
df49e56fd6 | ||
|
|
2fec379474 | ||
|
|
c1d952849a | ||
|
|
2fa8900609 | ||
|
|
da529ac9e4 | ||
|
|
52d0615161 | ||
|
|
e6efc7c131 | ||
|
|
3bfa436c19 | ||
|
|
72a7e97c84 | ||
|
|
6a7fdcd583 | ||
|
|
ebe39ab3fa | ||
|
|
aff4c008ce | ||
|
|
6d789c5a41 | ||
|
|
6c5a56295d | ||
|
|
a43b4091db | ||
|
|
e0ffd55e7a | ||
|
|
c68f5d1387 | ||
|
|
ca6f8609c3 | ||
|
|
8c29e146dd | ||
|
|
24531016d8 | ||
|
|
65cfcebaa2 | ||
|
|
3479b795aa | ||
|
|
cbe4a600d4 | ||
|
|
c65c24c87c | ||
|
|
a3fd89f1bb | ||
|
|
36815b4852 | ||
|
|
7c952d9a52 | ||
|
|
fdbfb1dc1b | ||
|
|
0d7874ef7e | ||
|
|
53dd29f381 | ||
|
|
131e68e07e | ||
|
|
0fc4e7ac67 | ||
|
|
05a5979906 | ||
|
|
8b720b9662 | ||
|
|
6d323f4ffd | ||
|
|
7b1d394e7d | ||
|
|
48124872b6 | ||
|
|
9f48ffaca1 | ||
|
|
3ab1648f50 | ||
|
|
e5e7b6e878 | ||
|
|
c31afa6e76 | ||
|
|
8cecf9c5c5 | ||
|
|
f0c8e1f6fe | ||
|
|
d70b24c2a8 | ||
|
|
0b53d57d3a | ||
|
|
c2b36207f2 | ||
|
|
eb05ef6d65 | ||
|
|
adc6bed3ad | ||
|
|
c496b15409 | ||
|
|
5fb45ece61 | ||
|
|
bfe00257dc | ||
|
|
9b628e171b | ||
|
|
a58dd30d2b | ||
|
|
8393ede275 | ||
|
|
7e22bf538a | ||
|
|
000ec99b5a |
@@ -1,3 +1,43 @@
|
||||
2026-05-16
|
||||
- The reversed split-window key bindings previously generated by
|
||||
`programs.tmux.enableSensible` are no longer emitted when
|
||||
`system.stateVersion` is 7 or later, so tmux uses its conventional
|
||||
behavior: `%` splits the current pane horizontally and `"` splits it
|
||||
vertically.
|
||||
|
||||
Existing configurations with `system.stateVersion` 6 or earlier keep
|
||||
the previous reversed bindings. You can explicitly choose either
|
||||
behavior with `programs.tmux.reverseSplitBindings`.
|
||||
|
||||
2026-02-10
|
||||
- Major changes to `homebrew` module
|
||||
|
||||
`homebrew.brewPrefix` was renamed to `homebrew.prefix`, and its semantics
|
||||
changed: the old option pointed to the bin directory (e.g.,
|
||||
`/opt/homebrew/bin`), while the new option points to the Homebrew prefix
|
||||
(e.g., `/opt/homebrew`), matching `brew --prefix`.
|
||||
|
||||
`homebrew.whalebrews` was removed. Whalebrew support was removed from
|
||||
Homebrew Bundle in Homebrew 4.7.0 (Nov 2025), so `whalebrew` entries in a
|
||||
Brewfile now cause `brew bundle` to fail.
|
||||
|
||||
`homebrew.global.lockfiles` and `homebrew.global.noLock` no longer have any
|
||||
effect. Homebrew Bundle removed lockfile support in Homebrew 4.4.0 (Oct 2024).
|
||||
|
||||
`homebrew.onActivation.cleanup` now supports a `"check"` mode, which checks
|
||||
for unlisted packages and aborts activation if any are found, without
|
||||
removing them.
|
||||
|
||||
Shell integration options were added: `homebrew.enableBashIntegration`,
|
||||
`homebrew.enableFishIntegration`, and `homebrew.enableZshIntegration`.
|
||||
|
||||
New Brewfile entry types were added: `homebrew.goPackages`,
|
||||
`homebrew.cargoPackages`, and `homebrew.vscode`.
|
||||
|
||||
New options were added for brews: `postinstall`, `link = "overwrite"`, and
|
||||
`restart_service = "always"`. The `postinstall` option was also added for
|
||||
casks.
|
||||
|
||||
2025-01-30
|
||||
- Previously, some nix-darwin options applied to the user running
|
||||
`darwin-rebuild`. As part of a long‐term migration to make
|
||||
@@ -116,7 +156,7 @@
|
||||
|
||||
`nix.daemonIONice` was renamed to `nix.daemonIOLowPriority`, and
|
||||
`nix.daemonNiceLevel` was removed in favor a new option
|
||||
`nix.nix.daemonProcessType`.
|
||||
`nix.daemonProcessType`.
|
||||
|
||||
2021-01-16
|
||||
- Added `homebrew` module, to manage formulas installed by Homebrew via `brew bundle`.
|
||||
|
||||
@@ -13,20 +13,9 @@ nix-darwin is built up around [Nixpkgs](https://github.com/NixOS/nixpkgs), quite
|
||||
|
||||
The only prerequisite is a Nix implementation; both Nix and Lix are supported.
|
||||
|
||||
As the official Nix installer does not include an automated uninstaller, and manual uninstallation on macOS is a complex process, we recommend using one of the following installers instead:
|
||||
|
||||
* The [Nix installer from Determinate Systems](https://github.com/DeterminateSystems/nix-installer?tab=readme-ov-file#determinate-nix-installer) is only recommended for use with flake-based setups.
|
||||
It can install one of two distributions of Nix:
|
||||
|
||||
* To install the **recommended** vanilla upstream [Nix](https://nixos.org), you will need to explicitly pass the `--prefer-upstream-nix` flag to the installer.
|
||||
|
||||
* When run without the `--prefer-upstream-nix` flag, it will install the [Determinate](https://docs.determinate.systems/) distribution.
|
||||
As Determinate manages the Nix installation itself, you will need to set `nix.enable = false;` in your configuration to disable nix-darwin’s own Nix management.
|
||||
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.
|
||||
|
||||
* The [Lix installer](https://lix.systems/install/#on-any-other-linuxmacos-system) supports both flake-based and channel-based setups.
|
||||
|
||||
As the official Nix installer does not include an automated uninstaller, and manual uninstallation on macOS is a complex process, we recommend using the [Lix installer](https://lix.systems/install/#on-any-other-linuxmacos-system), which supports both flake-based and channel-based setups.
|
||||
|
||||
The installer you use doesn't affect which Nix interpreter your system will use later on. nix-darwin manages the Nix installation by default and will default to upstream Nix. If you wish to use Lix instead of Nix, set `nix.package = pkgs.lix` in your configuration.
|
||||
|
||||
## Getting started
|
||||
|
||||
@@ -50,8 +39,8 @@ cd /etc/nix-darwin
|
||||
|
||||
# To use Nixpkgs unstable:
|
||||
nix flake init -t nix-darwin/master
|
||||
# To use Nixpkgs 25.05:
|
||||
nix flake init -t nix-darwin/nix-darwin-25.05
|
||||
# To use Nixpkgs 26.05:
|
||||
nix flake init -t nix-darwin/nix-darwin-26.05
|
||||
|
||||
sed -i '' "s/simple/$(scutil --get LocalHostName)/" flake.nix
|
||||
```
|
||||
@@ -71,9 +60,9 @@ Add the following to `flake.nix` in the same folder as `configuration.nix`:
|
||||
description = "John's darwin system";
|
||||
|
||||
inputs = {
|
||||
# Use `github:NixOS/nixpkgs/nixpkgs-25.05-darwin` to use Nixpkgs 25.05.
|
||||
# Use `github:NixOS/nixpkgs/nixpkgs-26.05-darwin` to use Nixpkgs 26.05.
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
# Use `github:nix-darwin/nix-darwin/nix-darwin-25.05` to use Nixpkgs 25.05.
|
||||
# Use `github:nix-darwin/nix-darwin/nix-darwin-26.05` to use Nixpkgs 26.05.
|
||||
nix-darwin.url = "github:nix-darwin/nix-darwin/master";
|
||||
nix-darwin.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
@@ -99,8 +88,8 @@ Unlike NixOS, `nix-darwin` does not have an installer, you can just run `darwin-
|
||||
```bash
|
||||
# To use Nixpkgs unstable:
|
||||
sudo nix run nix-darwin/master#darwin-rebuild -- switch
|
||||
# To use Nixpkgs 25.05:
|
||||
sudo nix run nix-darwin/nix-darwin-25.05#darwin-rebuild -- switch
|
||||
# To use Nixpkgs 26.05:
|
||||
sudo nix run nix-darwin/nix-darwin-26.05#darwin-rebuild -- switch
|
||||
```
|
||||
|
||||
### Step 3. Using `nix-darwin`
|
||||
@@ -143,8 +132,8 @@ Copy the [simple](./modules/examples/simple.nix) example to `/etc/nix-darwin/con
|
||||
```bash
|
||||
# If you use Nixpkgs unstable (the default):
|
||||
sudo nix-channel --add https://github.com/nix-darwin/nix-darwin/archive/master.tar.gz darwin
|
||||
# If you use Nixpkgs 25.05:
|
||||
sudo nix-channel --add https://github.com/nix-darwin/nix-darwin/archive/nix-darwin-25.05.tar.gz darwin
|
||||
# If you use Nixpkgs 26.05:
|
||||
sudo nix-channel --add https://github.com/nix-darwin/nix-darwin/archive/nix-darwin-26.05.tar.gz darwin
|
||||
|
||||
sudo nix-channel --update
|
||||
```
|
||||
@@ -177,9 +166,11 @@ sudo nix-channel --update
|
||||
|
||||
## Documentation
|
||||
|
||||
`darwin-help` will open up a local copy of the reference documentation, it can also be found online [here](https://nix-darwin.github.io/nix-darwin/manual/index.html).
|
||||
The reference documentation is available:
|
||||
|
||||
The documentation is also available as manpages by running `man 5 configuration.nix`.
|
||||
* Online: [nix-darwin reference](https://nix-darwin.github.io/nix-darwin/manual/index.html)
|
||||
* Locally in your browser via the `darwin-help` command
|
||||
* As a manual page via `man 5 configuration.nix`
|
||||
|
||||
## Uninstalling
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
# Set up Nix only on SSH connections
|
||||
# See: https://github.com/DeterminateSystems/nix-installer/pull/714
|
||||
if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ] && [ -n "${SSH_CONNECTION:-}" ] && [ "${SHLVL:-0}" -eq 1 ]; then
|
||||
. '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
|
||||
fi
|
||||
# End Nix
|
||||
@@ -0,0 +1,3 @@
|
||||
# Written by https://github.com/NixOS/nix-installer
|
||||
# The contents below are based on options specified at installation time.
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Generated by https://github.com/NixOS/nix-installer
|
||||
# See `/nix/nix-installer --version` for the version details.
|
||||
|
||||
extra-experimental-features = nix-command flakes
|
||||
always-allow-substitutes = true
|
||||
bash-prompt-prefix = (nix:$name)\040
|
||||
max-jobs = auto
|
||||
extra-nix-path = nixpkgs=flake:nixpkgs
|
||||
|
||||
!include nix.custom.conf
|
||||
@@ -0,0 +1,11 @@
|
||||
# Generated by https://install.lix.systems/.
|
||||
# See `/nix/lix-installer --version` for the version details.
|
||||
|
||||
extra-experimental-features = nix-command
|
||||
always-allow-substitutes = true
|
||||
extra-trusted-substituters = https://cache.lix.systems
|
||||
extra-trusted-public-keys = cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o=
|
||||
bash-prompt-prefix = (nix:$name)\040
|
||||
max-jobs = auto
|
||||
|
||||
!include nix.custom.conf
|
||||
@@ -0,0 +1,3 @@
|
||||
# Written by https://install.lix.systems/.
|
||||
# The contents below are based on options specified at installation time.
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# Generated by https://install.lix.systems/.
|
||||
# See `/nix/lix-installer --version` for the version details.
|
||||
|
||||
extra-experimental-features = nix-command flakes
|
||||
always-allow-substitutes = true
|
||||
extra-trusted-substituters = https://cache.lix.systems
|
||||
extra-trusted-public-keys = cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o=
|
||||
bash-prompt-prefix = (nix:$name)\040
|
||||
max-jobs = auto
|
||||
extra-nix-path = nixpkgs=flake:nixpkgs
|
||||
|
||||
!include nix.custom.conf
|
||||
@@ -94,8 +94,7 @@ in rec {
|
||||
--stylesheet highlightjs/mono-blue.css \
|
||||
--script ./highlightjs/highlight.pack.js \
|
||||
--script ./highlightjs/loader.js \
|
||||
--toc-depth 1 \
|
||||
--chunk-toc-depth 1 \
|
||||
--sidebar-depth 1 \
|
||||
./manual.md \
|
||||
$dst/index.html
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
options.flake.darwinConfigurations = lib.mkOption {
|
||||
type = lib.types.lazyAttrsOf lib.types.raw;
|
||||
default = { };
|
||||
description = "Darwin system configurations";
|
||||
};
|
||||
}
|
||||
Generated
+3
-3
@@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1747728033,
|
||||
"narHash": "sha256-NnXFQu7g4LnvPIPfJmBuZF7LFy/fey2g2+LCzjQhTUk=",
|
||||
"lastModified": 1783279667,
|
||||
"narHash": "sha256-/NAkDSsve+GNM0Bt6tleJdCGfsTlK89nPjkVOzZMo0s=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "2f9173bde1d3fbf1ad26ff6d52f952f9e9da52ea",
|
||||
"rev": "f205b5574fd0cb7da5b702a2da51507b7f4fdd1b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
darwin-uninstaller = prev.callPackage ./pkgs/darwin-uninstaller { };
|
||||
};
|
||||
|
||||
flakeModules.default = ./flake-module.nix;
|
||||
|
||||
darwinModules.hydra = ./modules/examples/hydra.nix;
|
||||
darwinModules.lnl = ./modules/examples/lnl.nix;
|
||||
darwinModules.simple = ./modules/examples/simple.nix;
|
||||
|
||||
@@ -42,16 +42,17 @@
|
||||
with pkgs.pkgsBuildBuild;
|
||||
[
|
||||
alacritty
|
||||
alacritty-graphics
|
||||
ghostty-bin
|
||||
kitty
|
||||
mtm
|
||||
rio
|
||||
rxvt-unicode-unwrapped
|
||||
rxvt-unicode-unwrapped-emoji
|
||||
st
|
||||
termite
|
||||
tmux
|
||||
wezterm
|
||||
] ++ lib.optional (pkgs ? ghostty-bin) ghostty-bin
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ in
|
||||
description = ''
|
||||
Shell script code called during global environment initialisation
|
||||
after all variables and profileVariables have been set.
|
||||
This code is asumed to be shell-independent, which means you should
|
||||
This code is assumed to be shell-independent, which means you should
|
||||
stick to pure sh without sh word split.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -50,8 +50,6 @@
|
||||
pkgs.jq
|
||||
pkgs.ripgrep
|
||||
pkgs.shellcheck
|
||||
|
||||
pkgs.qes
|
||||
];
|
||||
|
||||
services.yabai.enable = true;
|
||||
|
||||
+334
-115
@@ -12,7 +12,7 @@ let
|
||||
|
||||
mkBrewfileSectionString = heading: entries: optionalString (entries != [ ]) ''
|
||||
# ${heading}
|
||||
${concatMapStringsSep "\n" (v: v.brewfileLine or v) entries}
|
||||
${concatStringsSep "\n" (unique (map (v: v.brewfileLine or v) entries))}
|
||||
|
||||
'';
|
||||
|
||||
@@ -28,9 +28,23 @@ let
|
||||
mkBrewfileLineOptionsListString = attrs:
|
||||
concatStringsSep ", " (mapAttrsToList (n: v: "${n}: ${v}") attrs);
|
||||
|
||||
# Renders a Brewfile option that can be either a bool or a Ruby symbol (e.g. `:overwrite`).
|
||||
mkBrewfileLineBoolOrSymbolString = name: config: sCfg:
|
||||
optionalString (hasAttr name sCfg) (
|
||||
", ${name}: " + (
|
||||
if isBool config.${name} then sCfg.${name}
|
||||
else ":${config.${name}}"
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
# Option and submodule helper functions ----------------------------------------------------------
|
||||
|
||||
mkShellIntegrationOption = shell: mkEnableOption ''
|
||||
Homebrew ${shell} shell integration, which sets up Homebrew's environment
|
||||
and shell completions
|
||||
'';
|
||||
|
||||
mkNullOrBoolOption = args: mkOption (args // {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
@@ -62,29 +76,36 @@ let
|
||||
onActivationOptions = { config, ... }: {
|
||||
options = {
|
||||
cleanup = mkOption {
|
||||
type = types.enum [ "none" "uninstall" "zap" ];
|
||||
type = types.enum [ "none" "check" "uninstall" "zap" ];
|
||||
default = "none";
|
||||
example = "uninstall";
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
{command}`brew bundle [install]` with the {command}`--cleanup` flag. This
|
||||
uninstalls all formulae not listed in generated Brewfile, i.e.,
|
||||
{command}`brew uninstall` is run for those formulae.
|
||||
uninstalls all packages not listed in the generated Brewfile, i.e.,
|
||||
{command}`brew uninstall` is run for those packages.
|
||||
|
||||
When set to `"zap"`, {command}`nix-darwin` invokes
|
||||
{command}`brew bundle [install]` with the {command}`--cleanup --zap`
|
||||
flags. This uninstalls all formulae not listed in the generated Brewfile, and if the
|
||||
formula is a cask, removes all files associated with that cask. In other words,
|
||||
{command}`brew uninstall --zap` is run for all those formulae.
|
||||
flags. This uninstalls all packages not listed in the generated Brewfile, and if the
|
||||
package is a cask, removes all files associated with that cask. In other words,
|
||||
{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
|
||||
`"uninstall"` or `"zap"`.
|
||||
'';
|
||||
@@ -97,7 +118,7 @@ let
|
||||
{command}`nix-darwin` system activation. The default is `false`
|
||||
so that repeated invocations of {command}`darwin-rebuild switch` are idempotent.
|
||||
|
||||
Note that Homebrew auto-updates when it's been more then 5 minutes since it last updated.
|
||||
Note that Homebrew auto-updates when it's been more than 5 minutes since it last updated.
|
||||
|
||||
Although auto-updating is disabled by default during system activation, note that Homebrew
|
||||
will auto-update when you manually invoke certain Homebrew commands. To modify this
|
||||
@@ -121,6 +142,26 @@ let
|
||||
activation.
|
||||
'';
|
||||
};
|
||||
extraEnv = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = { };
|
||||
example = {
|
||||
HOMEBREW_NO_ENV_HINTS = "1";
|
||||
HOMEBREW_NO_ANALYTICS = "1";
|
||||
};
|
||||
description = ''
|
||||
Extra environment variables to set when {command}`nix-darwin` invokes
|
||||
{command}`brew bundle [install]` during system checks and activation.
|
||||
|
||||
Useful for setting Homebrew's `HOMEBREW_NO_*` variables (e.g.,
|
||||
`HOMEBREW_NO_ENV_HINTS`, `HOMEBREW_NO_ANALYTICS`, `HOMEBREW_NO_UPDATE_REPORT_NEW`)
|
||||
that aren't inherited from the user's shell environment because activation runs
|
||||
under sudo.
|
||||
|
||||
Each entry is prepended to the {command}`brew bundle` invocation in the form
|
||||
`KEY=VALUE`, alongside `HOMEBREW_NO_AUTO_UPDATE=1` when applicable.
|
||||
'';
|
||||
};
|
||||
extraFlags = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
@@ -131,17 +172,31 @@ let
|
||||
'';
|
||||
};
|
||||
|
||||
brewBundleCmd = mkInternalOption { type = types.str; };
|
||||
brewBundleCmd = mkInternalOption { type = types.functionTo types.str; };
|
||||
};
|
||||
|
||||
config = {
|
||||
brewBundleCmd = concatStringsSep " " (
|
||||
optional (!config.autoUpdate) "HOMEBREW_NO_AUTO_UPDATE=1"
|
||||
brewBundleCmd = { onlyCheck }: concatStringsSep " " (
|
||||
[
|
||||
''PATH="${cfg.prefix}/bin:${lib.makeBinPath [ pkgs.mas ]}:$PATH"''
|
||||
"sudo"
|
||||
"--preserve-env=PATH"
|
||||
"--user=${escapeShellArg cfg.user}"
|
||||
"--set-home"
|
||||
"env"
|
||||
]
|
||||
++ optional (onlyCheck || !config.autoUpdate) "HOMEBREW_NO_AUTO_UPDATE=1"
|
||||
++ mapAttrsToList (k: v: "${k}=${escapeShellArg v}") config.extraEnv
|
||||
++ [ "brew bundle --file='${brewfileFile}'" ]
|
||||
++ optional (!config.upgrade) "--no-upgrade"
|
||||
++ optional (config.cleanup == "uninstall") "--cleanup"
|
||||
++ optional (config.cleanup == "zap") "--cleanup --zap"
|
||||
++ config.extraFlags
|
||||
++ (
|
||||
if onlyCheck then
|
||||
[ "cleanup 2>&1" ]
|
||||
else
|
||||
optional (!config.upgrade) "--no-upgrade"
|
||||
++ optional (config.cleanup == "uninstall") "--force-cleanup"
|
||||
++ optional (config.cleanup == "zap") "--zap --force-cleanup"
|
||||
++ config.extraFlags
|
||||
)
|
||||
);
|
||||
};
|
||||
};
|
||||
@@ -155,14 +210,6 @@ let
|
||||
Whether to enable Homebrew to automatically use the Brewfile that this module generates in
|
||||
the Nix store, when you manually invoke {command}`brew bundle`.
|
||||
|
||||
Enabling this option will change the default value of
|
||||
[](#opt-homebrew.global.lockfiles) to `false` since, with
|
||||
this option enabled, {command}`brew bundle [install]` will default to using the
|
||||
Brewfile that this module generates in the Nix store, unless you explicitly point it at
|
||||
another Brewfile using the `--file` flag. As a result, it will try to
|
||||
write the lockfile in the Nix store, and complain that it can't (though the command will
|
||||
run successfully regardless).
|
||||
|
||||
Implementation note: when enabled, this option sets the
|
||||
`HOMEBREW_BUNDLE_FILE` environment variable to the path of the Brewfile
|
||||
that this module generates in the Nix store, by adding it to
|
||||
@@ -178,7 +225,7 @@ let
|
||||
{command}`brew tap`, and {command}`brew bundle [install]`.
|
||||
|
||||
Note that Homebrew auto-updates when you manually invoke commands like the ones mentioned
|
||||
above if it's been more then 5 minutes since it last updated.
|
||||
above if it's been more than 5 minutes since it last updated.
|
||||
|
||||
You may want to consider disabling this option if you have
|
||||
[](#opt-homebrew.onActivation.upgrade) enabled, and
|
||||
@@ -191,31 +238,13 @@ let
|
||||
[](#opt-environment.variables).
|
||||
'';
|
||||
};
|
||||
lockfiles = mkOption {
|
||||
type = types.bool;
|
||||
default = !config.brewfile;
|
||||
defaultText = literalExpression "!config.homebrew.global.brewfile";
|
||||
description = ''
|
||||
Whether to enable Homebrew to generate lockfiles when you manually invoke
|
||||
{command}`brew bundle [install]`.
|
||||
|
||||
This option will default to `false` if
|
||||
[](#opt-homebrew.global.brewfile) is enabled since, with that option enabled,
|
||||
{command}`brew bundle [install]` will default to using the Brewfile that this
|
||||
module generates in the Nix store, unless you explicitly point it at another Brewfile
|
||||
using the `--file` flag. As a result, it will try to write the
|
||||
lockfile in the Nix store, and complain that it can't (though the command will run
|
||||
successfully regardless).
|
||||
|
||||
Implementation note: when disabled, this option sets the
|
||||
`HOMEBREW_BUNDLE_NO_LOCK` environment variable, by adding it to
|
||||
[](#opt-environment.variables).
|
||||
'';
|
||||
};
|
||||
|
||||
# The `noLock` option was replaced by `lockfiles`. Due to `homebrew.global` being a submodule,
|
||||
# we can't use `mkRemovedOptionModule`, so we leave this option definition here, and trigger
|
||||
# and error message with an assertion below if it's set by the user.
|
||||
# `noLock` was the original option; `lockfiles` replaced it (with inverted semantics).
|
||||
# Both are now dead: Homebrew Bundle removed lockfile support in Homebrew 4.4.0
|
||||
# (Oct 2024), so the `HOMEBREW_BUNDLE_NO_LOCK` env var and `--no-lock` CLI flag are
|
||||
# ignored. We keep both definitions with null defaults to detect explicit user
|
||||
# configuration and emit a warning below. We can't use `mkRemovedOptionModule` because
|
||||
# `homebrew.global` is a submodule.
|
||||
lockfiles = mkOption { visible = false; default = null; };
|
||||
noLock = mkOption { visible = false; default = null; };
|
||||
|
||||
homebrewEnvironmentVariables = mkInternalOption { type = types.attrs; };
|
||||
@@ -225,7 +254,6 @@ let
|
||||
homebrewEnvironmentVariables = {
|
||||
HOMEBREW_BUNDLE_FILE = mkIf config.brewfile "${brewfileFile}";
|
||||
HOMEBREW_NO_AUTO_UPDATE = mkIf (!config.autoUpdate) "1";
|
||||
HOMEBREW_BUNDLE_NO_LOCK = mkIf (!config.lockfiles) "1";
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -253,6 +281,25 @@ let
|
||||
description = ''
|
||||
Whether to auto-update the tap even if it is not hosted on GitHub. By default, only taps
|
||||
hosted on GitHub are auto-updated (for performance reasons).
|
||||
|
||||
Note: Homebrew Bundle accepts this option in Brewfile syntax but may silently ignore it
|
||||
during installation. See [the Homebrew Bundle source](https://github.com/Homebrew/brew/tree/master/Library/Homebrew/bundle)
|
||||
for current behavior.
|
||||
'';
|
||||
};
|
||||
trusted = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether to trust this tap during {command}`nix-darwin` system activation, by adding the
|
||||
`trusted: true` option to its {command}`brew bundle` Brewfile entry.
|
||||
|
||||
Homebrew 6.0.0 enabled `HOMEBREW_REQUIRE_TAP_TRUST` by default, which refuses to
|
||||
load formulae/casks from non-official taps that haven't been trusted, aborting activation.
|
||||
Set this to `true` for non-official taps you control so their formulae and casks are
|
||||
installed during activation. Official taps are always trusted, so this has no effect only
|
||||
them.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -268,7 +315,8 @@ let
|
||||
"tap ${sCfg.name}"
|
||||
+ optionalString (sCfg ? clone_target) ", ${sCfg.clone_target}"
|
||||
+ optionalString (sCfg ? force_auto_update)
|
||||
", force_auto_update: ${sCfg.force_auto_update}";
|
||||
", force_auto_update: ${sCfg.force_auto_update}"
|
||||
+ optionalString config.trusted ", trusted: true";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -385,19 +433,34 @@ let
|
||||
};
|
||||
require_sha = mkNullOrBoolOption {
|
||||
description = ''
|
||||
Whether to require cask(s) to have a checksum.
|
||||
Whether to require casks to have a checksum.
|
||||
|
||||
Homebrew's default is `false`.
|
||||
'';
|
||||
};
|
||||
no_quarantine = mkNullOrBoolOption {
|
||||
description = "Whether to disable quarantining of downloads.";
|
||||
description = ''
|
||||
Whether to disable quarantining of downloads.
|
||||
|
||||
Note: this option is deprecated in Homebrew and may be removed in a
|
||||
future release. See [Homebrew/brew#20755](https://github.com/Homebrew/brew/issues/20755).
|
||||
|
||||
Homebrew's default is `false`.
|
||||
'';
|
||||
};
|
||||
no_binaries = mkNullOrBoolOption {
|
||||
description = "Whether to disable linking of helper executables.";
|
||||
description = ''
|
||||
Whether to disable linking of helper executables.
|
||||
|
||||
Homebrew's default is `false`.
|
||||
'';
|
||||
};
|
||||
ignore_dependencies = mkNullOrBoolOption {
|
||||
description = "Ignore casks dependencies in case you manage them extrenally";
|
||||
description = ''
|
||||
Whether to ignore cask dependencies, e.g., when you manage them externally.
|
||||
|
||||
Homebrew's default is `false`.
|
||||
'';
|
||||
};
|
||||
|
||||
brewfileLine = mkInternalOption { type = types.nullOr types.str; };
|
||||
@@ -424,7 +487,7 @@ let
|
||||
type = with types; nullOr (listOf str);
|
||||
default = null;
|
||||
description = ''
|
||||
Arguments flags to pass to {command}`brew install`. Values should not include the
|
||||
Argument flags to pass to {command}`brew install`. Values should not include the
|
||||
leading `"--"`.
|
||||
'';
|
||||
};
|
||||
@@ -437,12 +500,14 @@ let
|
||||
'';
|
||||
};
|
||||
restart_service = mkOption {
|
||||
type = with types; nullOr (either bool (enum [ "changed" ]));
|
||||
type = with types; nullOr (either bool (enum [ "changed" "always" ]));
|
||||
default = null;
|
||||
description = ''
|
||||
Whether to run {command}`brew services restart` for the formula and register it to
|
||||
launch at login (or boot). If set to `"changed"`, the service will only
|
||||
be restarted on version changes.
|
||||
be restarted when the formula is newly installed or upgraded. If set to
|
||||
`"always"`, the service will be restarted on every {command}`brew bundle`
|
||||
run, even if nothing changed.
|
||||
|
||||
Homebrew's default is `false`.
|
||||
'';
|
||||
@@ -450,17 +515,53 @@ let
|
||||
start_service = mkNullOrBoolOption {
|
||||
description = ''
|
||||
Whether to run {command}`brew services start` for the formula and register it to
|
||||
launch at login (or boot).
|
||||
launch at login (or boot). Unlike {option}`restart_service`, this only starts
|
||||
the service if it is not currently running, without restarting an already-running
|
||||
service.
|
||||
|
||||
Homebrew's default is `false`.
|
||||
'';
|
||||
};
|
||||
link = mkNullOrBoolOption {
|
||||
link = mkOption {
|
||||
type = with types; nullOr (either bool (enum [ "overwrite" ]));
|
||||
default = null;
|
||||
description = ''
|
||||
Whether to link the formula to the Homebrew prefix. When this option is
|
||||
`null`, Homebrew will use it's default behavior which is to link the
|
||||
formula if it's currently unlinked and not keg-only, and to unlink the formula if it's
|
||||
currently linked and keg-only.
|
||||
Whether to link the formula to the Homebrew prefix. When set to `"overwrite"`,
|
||||
existing symlinks will be overwritten ({command}`brew link --overwrite`). When this
|
||||
option is `null`, Homebrew will use its default behavior, which is to link the formula
|
||||
if it's currently unlinked and not keg-only, and to unlink the formula if it's currently
|
||||
linked and keg-only.
|
||||
'';
|
||||
};
|
||||
postinstall = mkNullOrStrOption {
|
||||
description = ''
|
||||
A shell command to run after the formula is installed or upgraded. The command is passed
|
||||
to the system shell and only executes when the formula actually changed (was freshly
|
||||
installed or upgraded), not on every {command}`brew bundle` run.
|
||||
'';
|
||||
};
|
||||
# `version_file` is intentionally not exposed: it writes the installed version to a file
|
||||
# path relative to the `brew bundle` working directory, which is not meaningful during
|
||||
# nix-darwin system activation.
|
||||
trusted = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
example = false;
|
||||
description = ''
|
||||
Whether to trust this formula during {command}`nix-darwin` system activation, by adding the
|
||||
`trusted: true` option to its {command}`brew bundle` Brewfile entry.
|
||||
|
||||
Homebrew 6.0.0 enabled `HOMEBREW_REQUIRE_TAP_TRUST` by default, which refuses to
|
||||
load formulae from non-official taps that haven't been trusted, aborting activation. Set
|
||||
this to `true` for a formula from a non-official tap you control so it is installed during
|
||||
activation.
|
||||
|
||||
This only takes effect when {option}`name` is a fully-qualified name (`user/repo/formula`),
|
||||
since only fully-qualified names map to a tap and can be trusted (and installed) on their
|
||||
own. When {option}`name` is a plain formula name, it is resolved through your tapped
|
||||
repositories, so trust must instead come from the containing tap being marked as trusted
|
||||
(see [](#opt-homebrew.taps)). Official taps are always trusted, so this has no effect on
|
||||
them.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -470,20 +571,15 @@ let
|
||||
config =
|
||||
let
|
||||
sCfg = mkProcessedSubmodConfig config;
|
||||
sCfgSubset = removeAttrs sCfg [ "name" "restart_service" ];
|
||||
sCfgSubset = removeAttrs sCfg [ "name" "restart_service" "link" "trusted" ];
|
||||
in
|
||||
{
|
||||
brewfileLine =
|
||||
"brew ${sCfg.name}"
|
||||
+ optionalString (sCfgSubset != { }) ", ${mkBrewfileLineOptionsListString sCfgSubset}"
|
||||
# We need to handle the `restart_service` option seperately since it can be either a bool
|
||||
# or `:changed` in the Brewfile.
|
||||
+ optionalString (sCfg ? restart_service) (
|
||||
", restart_service: " + (
|
||||
if isBool config.restart_service then sCfg.restart_service
|
||||
else ":${config.restart_service}"
|
||||
)
|
||||
);
|
||||
+ mkBrewfileLineBoolOrSymbolString "link" config sCfg
|
||||
+ mkBrewfileLineBoolOrSymbolString "restart_service" config sCfg
|
||||
+ optionalString config.trusted ", trusted: true";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -510,6 +606,34 @@ let
|
||||
itself.
|
||||
'';
|
||||
};
|
||||
postinstall = mkNullOrStrOption {
|
||||
description = ''
|
||||
A shell command to run after the cask is installed or upgraded. The command is passed to
|
||||
the system shell and only executes when the cask was actually installed or upgraded, not
|
||||
on every {command}`brew bundle` run.
|
||||
'';
|
||||
};
|
||||
trusted = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
example = false;
|
||||
description = ''
|
||||
Whether to trust this cask during {command}`nix-darwin` system activation, by adding the
|
||||
`trusted: true` option to its {command}`brew bundle` Brewfile entry.
|
||||
|
||||
Homebrew 6.0.0 enabled `HOMEBREW_REQUIRE_TAP_TRUST` by default, which refuses to
|
||||
load casks from non-official taps that haven't been trusted, silently skipping them. Set
|
||||
this to `true` for a cask from a non-official tap you control so it is installed during
|
||||
activation.
|
||||
|
||||
This only takes effect when {option}`name` is a fully-qualified name (`user/repo/cask`),
|
||||
since only fully-qualified names map to a tap and can be trusted (and installed) on their
|
||||
own. When {option}`name` is a plain cask name, it is resolved through your tapped
|
||||
repositories, so trust must instead come from the containing tap being marked as trusted
|
||||
(see [](#opt-homebrew.taps)). Official taps are always trusted, so this has no effect on
|
||||
them.
|
||||
'';
|
||||
};
|
||||
|
||||
brewfileLine = mkInternalOption { type = types.nullOr types.str; };
|
||||
};
|
||||
@@ -517,12 +641,13 @@ let
|
||||
config =
|
||||
let
|
||||
sCfg = mkProcessedSubmodConfig config;
|
||||
sCfgSubset = removeAttrs sCfg [ "name" ];
|
||||
sCfgSubset = removeAttrs sCfg [ "name" "trusted" ];
|
||||
in
|
||||
{
|
||||
brewfileLine =
|
||||
"cask ${sCfg.name}"
|
||||
+ optionalString (sCfgSubset != { }) ", ${mkBrewfileLineOptionsListString sCfgSubset}";
|
||||
+ optionalString (sCfgSubset != { }) ", ${mkBrewfileLineOptionsListString sCfgSubset}"
|
||||
+ optionalString config.trusted ", trusted: true";
|
||||
};
|
||||
};
|
||||
in
|
||||
@@ -533,21 +658,26 @@ in
|
||||
imports = [
|
||||
(mkRenamedOptionModule [ "homebrew" "autoUpdate" ] [ "homebrew" "onActivation" "autoUpdate" ])
|
||||
(mkRenamedOptionModule [ "homebrew" "cleanup" ] [ "homebrew" "onActivation" "cleanup" ])
|
||||
(mkRemovedOptionModule [ "homebrew" "brewPrefix" ] "`homebrew.brewPrefix` has been renamed to `homebrew.prefix` and its semantics changed: the old option pointed to the bin directory (e.g., `/opt/homebrew/bin`), while the new option points to the Homebrew prefix (e.g., `/opt/homebrew`), matching `brew --prefix`. Please replace `homebrew.brewPrefix` with `homebrew.prefix`, removing the trailing `/bin` if present.")
|
||||
(mkRemovedOptionModule [ "homebrew" "whalebrews" ] "Whalebrew support was removed from Homebrew Bundle in Homebrew 4.7.0 (Nov 2025). `whalebrew` entries in a Brewfile now cause `brew bundle` to fail. Please manage Whalebrew images directly using the `whalebrew` CLI.")
|
||||
];
|
||||
|
||||
options.homebrew = {
|
||||
enable = mkEnableOption ''
|
||||
{command}`nix-darwin` to manage installing/updating/upgrading Homebrew taps, formulae,
|
||||
and casks, as well as Mac App Store apps and Docker containers, using Homebrew Bundle.
|
||||
casks, Mac App Store apps, Visual Studio Code extensions, Go packages, and Cargo
|
||||
crates using Homebrew Bundle.
|
||||
|
||||
Note that enabling this option does not install Homebrew, see the Homebrew
|
||||
[website](https://brew.sh) for installation instructions.
|
||||
|
||||
Use the [](#opt-homebrew.brews), [](#opt-homebrew.casks),
|
||||
[](#opt-homebrew.masApps), and [](#opt-homebrew.whalebrews) options
|
||||
to list the Homebrew formulae, casks, Mac App Store apps, and Docker containers you'd like to
|
||||
install. Use the [](#opt-homebrew.taps) option, to make additional formula
|
||||
repositories available to Homebrew. This module uses those options (along with the
|
||||
[](#opt-homebrew.masApps), [](#opt-homebrew.vscode),
|
||||
[](#opt-homebrew.goPackages), and [](#opt-homebrew.cargoPackages) options to list
|
||||
the Homebrew formulae, casks, Mac App Store apps, Visual Studio Code extensions,
|
||||
Go packages, and Cargo crates you'd like to install. Use the
|
||||
[](#opt-homebrew.taps) option, to make additional formula repositories available to
|
||||
Homebrew. This module uses those options (along with the
|
||||
[](#opt-homebrew.caskArgs) options) to generate a Brewfile that
|
||||
{command}`nix-darwin` passes to the {command}`brew bundle` command during
|
||||
system activation.
|
||||
@@ -572,20 +702,27 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
brewPrefix = mkOption {
|
||||
prefix = mkOption {
|
||||
type = types.str;
|
||||
default = if pkgs.stdenv.hostPlatform.isAarch64 then "/opt/homebrew/bin" else "/usr/local/bin";
|
||||
default = if pkgs.stdenv.hostPlatform.isAarch64 then "/opt/homebrew" else "/usr/local";
|
||||
defaultText = literalExpression ''
|
||||
if pkgs.stdenv.hostPlatform.isAarch64 then "/opt/homebrew/bin"
|
||||
else "/usr/local/bin"
|
||||
if pkgs.stdenv.hostPlatform.isAarch64 then "/opt/homebrew"
|
||||
else "/usr/local"
|
||||
'';
|
||||
description = ''
|
||||
The path prefix where the {command}`brew` executable is located. This will be set to
|
||||
the correct value based on your system's platform, and should only need to be changed if you
|
||||
manually installed Homebrew in a non-standard location.
|
||||
The Homebrew prefix directory, i.e., the value that {command}`brew --prefix` returns.
|
||||
The default is automatically set based on your system's platform, and should only need
|
||||
to be changed if you manually installed Homebrew in a non-standard location.
|
||||
'';
|
||||
};
|
||||
|
||||
# These default to `false` (unlike direnv, which defaults to `true`) because existing users
|
||||
# likely already have `brew shellenv` in their dotfiles, and enabling by default would cause
|
||||
# duplicate evaluation.
|
||||
enableBashIntegration = mkShellIntegrationOption "Bash";
|
||||
enableFishIntegration = mkShellIntegrationOption "Fish";
|
||||
enableZshIntegration = mkShellIntegrationOption "Zsh";
|
||||
|
||||
onActivation = mkOption {
|
||||
type = types.submodule onActivationOptions;
|
||||
default = { };
|
||||
@@ -648,6 +785,8 @@ in
|
||||
description = ''
|
||||
Whether to always upgrade casks listed in [](#opt-homebrew.casks) regardless
|
||||
of whether it's unversioned or it updates itself.
|
||||
|
||||
Homebrew's default is `false`.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -674,6 +813,12 @@ in
|
||||
link = true;
|
||||
conflicts_with = [ "mysql" ];
|
||||
}
|
||||
|
||||
# `brew install`, run a post-install command on version changes
|
||||
{
|
||||
name = "postgresql@16";
|
||||
postinstall = "\''${HOMEBREW_PREFIX}/opt/postgresql@16/bin/postgres -D \''${HOMEBREW_PREFIX}/var/postgresql@16";
|
||||
}
|
||||
]
|
||||
'';
|
||||
description = ''
|
||||
@@ -705,6 +850,12 @@ in
|
||||
name = "opera";
|
||||
greedy = true;
|
||||
}
|
||||
|
||||
# `brew install --cask`, run a post-install command on install or upgrade
|
||||
{
|
||||
name = "google-cloud-sdk";
|
||||
postinstall = "\''${HOMEBREW_PREFIX}/bin/gcloud components update";
|
||||
}
|
||||
]
|
||||
'';
|
||||
description = ''
|
||||
@@ -739,21 +890,47 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
whalebrews = mkOption {
|
||||
vscode = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [ ];
|
||||
example = [ "whalebrew/wget" ];
|
||||
example = [ "golang.go" ];
|
||||
description = ''
|
||||
List of Docker images to install using {command}`whalebrew`.
|
||||
List of Visual Studio Code extensions to install using Homebrew Bundle.
|
||||
|
||||
When this option is used, `"whalebrew"` is automatically added to
|
||||
[](#opt-homebrew.brews).
|
||||
A compatible editor (Visual Studio Code, VSCodium, Cursor, or VS Code Insiders)
|
||||
must be available. If none is found, Homebrew will attempt to install
|
||||
`visual-studio-code` automatically.
|
||||
|
||||
For more information on {command}`whalebrew` see:
|
||||
[github.com/whalebrew/whalebrew](https://github.com/whalebrew/whalebrew).
|
||||
For more information on {command}`code` see:
|
||||
[VSCode Extension Marketplace](https://code.visualstudio.com/docs/editor/extension-marketplace).
|
||||
'';
|
||||
};
|
||||
|
||||
goPackages = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [ ];
|
||||
example = [ "github.com/charmbracelet/crush" ];
|
||||
description = ''
|
||||
List of Go packages to install using {command}`go install`.
|
||||
|
||||
Homebrew will automatically install the {command}`go` formula if it is not already
|
||||
installed.
|
||||
'';
|
||||
};
|
||||
|
||||
cargoPackages = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [ ];
|
||||
example = [ "ripgrep" ];
|
||||
description = ''
|
||||
List of Rust packages to install using {command}`cargo install`.
|
||||
|
||||
Homebrew will automatically install the {command}`rust` formula if it is not already
|
||||
installed.
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
@@ -766,7 +943,7 @@ in
|
||||
|
||||
brewfile = mkInternalOption {
|
||||
type = types.str;
|
||||
description = "String reprensentation of the generated Brewfile useful for debugging.";
|
||||
description = "String representation of the generated Brewfile useful for debugging.";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -775,22 +952,16 @@ in
|
||||
|
||||
config = {
|
||||
|
||||
assertions = [
|
||||
# See comment above `homebrew.global.noLock` option declaration for why this is required.
|
||||
{ assertion = cfg.global.noLock == null; message = "The option `homebrew.global.noLock' was removed, use `homebrew.global.lockfiles' in it's place."; }
|
||||
];
|
||||
|
||||
warnings = [
|
||||
(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'.")
|
||||
(mkIf (cfg.global.noLock != null || cfg.global.lockfiles != null) "The options `homebrew.global.noLock' and `homebrew.global.lockfiles' have been deprecated. Homebrew Bundle removed lockfile support in Homebrew 4.4.0 (Oct 2024), so these options no longer have any effect. Please remove them from your configuration.")
|
||||
(mkIf (hasSuffix "/bin" cfg.prefix) "`homebrew.prefix` should be the Homebrew prefix directory (e.g., `/opt/homebrew`), not the bin directory. The value should match what `brew --prefix` returns. Did you mean to remove the trailing `/bin`?")
|
||||
];
|
||||
|
||||
system.requiresPrimaryUser = mkIf (cfg.enable && options.homebrew.user.highestPrio == (mkOptionDefault {}).priority) [
|
||||
"homebrew.enable"
|
||||
];
|
||||
|
||||
homebrew.brews =
|
||||
optional (cfg.whalebrews != [ ]) "whalebrew";
|
||||
|
||||
homebrew.brewfile =
|
||||
"# Created by `nix-darwin`'s `homebrew` module\n\n"
|
||||
+ mkBrewfileSectionString "Taps" cfg.taps
|
||||
@@ -800,25 +971,73 @@ in
|
||||
+ mkBrewfileSectionString "Casks" cfg.casks
|
||||
+ mkBrewfileSectionString "Mac App Store apps"
|
||||
(mapAttrsToList (n: id: ''mas "${n}", id: ${toString id}'') cfg.masApps)
|
||||
+ mkBrewfileSectionString "Docker containers" (map (v: ''whalebrew "${v}"'') cfg.whalebrews)
|
||||
+ mkBrewfileSectionString "Visual Studio Code extensions" (map (v: ''vscode "${v}"'') cfg.vscode)
|
||||
+ mkBrewfileSectionString "Go packages" (map (v: ''go "${v}"'') cfg.goPackages)
|
||||
+ mkBrewfileSectionString "Cargo packages" (map (v: ''cargo "${v}"'') cfg.cargoPackages)
|
||||
+ optionalString (cfg.extraConfig != "") ("# Extra config\n" + cfg.extraConfig);
|
||||
|
||||
environment.variables = mkIf cfg.enable cfg.global.homebrewEnvironmentVariables;
|
||||
|
||||
programs = mkIf cfg.enable {
|
||||
bash.interactiveShellInit = mkIf cfg.enableBashIntegration ''
|
||||
eval "$(${cfg.prefix}/bin/brew shellenv bash)"
|
||||
if [[ -r "${cfg.prefix}/etc/profile.d/bash_completion.sh" ]]; then
|
||||
source "${cfg.prefix}/etc/profile.d/bash_completion.sh"
|
||||
else
|
||||
for COMPLETION in "${cfg.prefix}/etc/bash_completion.d/"*; do
|
||||
[[ -r "$COMPLETION" ]] && source "$COMPLETION"
|
||||
done
|
||||
fi
|
||||
'';
|
||||
|
||||
zsh.interactiveShellInit = mkIf cfg.enableZshIntegration ''
|
||||
eval "$(${cfg.prefix}/bin/brew shellenv zsh)"
|
||||
'';
|
||||
|
||||
fish.interactiveShellInit = mkIf cfg.enableFishIntegration ''
|
||||
eval (${cfg.prefix}/bin/brew shellenv fish)
|
||||
if test -d "${cfg.prefix}/share/fish/completions"
|
||||
set -p fish_complete_path "${cfg.prefix}/share/fish/completions"
|
||||
end
|
||||
if test -d "${cfg.prefix}/share/fish/vendor_completions.d"
|
||||
set -p fish_complete_path "${cfg.prefix}/share/fish/vendor_completions.d"
|
||||
end
|
||||
'';
|
||||
};
|
||||
|
||||
system.checks.text = mkIf (cfg.enable && cfg.onActivation.cleanup == "check") ''
|
||||
if [ -f "${cfg.prefix}/bin/brew" ]; then
|
||||
homebrewCleanupExitCode=0
|
||||
homebrewCleanupResult=$(${cfg.onActivation.brewBundleCmd { onlyCheck = true; }}) || 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 ''
|
||||
# Homebrew Bundle
|
||||
echo >&2 "Homebrew bundle..."
|
||||
if [ -f "${cfg.brewPrefix}/brew" ]; then
|
||||
PATH="${cfg.brewPrefix}:${lib.makeBinPath [ pkgs.mas ]}:$PATH" \
|
||||
sudo \
|
||||
--preserve-env=PATH \
|
||||
--user=${escapeShellArg cfg.user} \
|
||||
--set-home \
|
||||
env \
|
||||
${cfg.onActivation.brewBundleCmd}
|
||||
if [ -f "${cfg.prefix}/bin/brew" ]; then
|
||||
${cfg.onActivation.brewBundleCmd { onlyCheck = false; }}
|
||||
else
|
||||
echo -e "\e[1;31merror: Homebrew is not installed, skipping...\e[0m" >&2
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
meta.maintainers = [
|
||||
lib.maintainers.malo or "malo"
|
||||
];
|
||||
}
|
||||
|
||||
@@ -108,10 +108,12 @@
|
||||
./programs/_1password-gui.nix
|
||||
./programs/arqbackup.nix
|
||||
./programs/bash
|
||||
./programs/devenv.nix
|
||||
./programs/direnv.nix
|
||||
./programs/fish.nix
|
||||
./programs/gnupg.nix
|
||||
./programs/man.nix
|
||||
./programs/mas.nix
|
||||
./programs/info
|
||||
./programs/nix-index
|
||||
./programs/ssh.nix
|
||||
|
||||
@@ -18,6 +18,9 @@ let
|
||||
*${lib.escapeShellArg srv}*)
|
||||
networksetup -setdnsservers ${lib.escapeShellArgs ([ srv ] ++ (emptyList cfg.dns))}
|
||||
networksetup -setsearchdomains ${lib.escapeShellArgs ([ srv ] ++ (emptyList cfg.search))}
|
||||
${optionalString (cfg.dhcpClientId != null) ''
|
||||
networksetup -setdhcp ${lib.escapeShellArgs [ srv cfg.dhcpClientId ]}
|
||||
''}
|
||||
;;
|
||||
esac
|
||||
'') cfg.knownNetworkServices}
|
||||
@@ -133,6 +136,21 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
networking.dhcpClientId = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "my-client-id";
|
||||
description = ''
|
||||
The DHCP client identifier to use when requesting an IP address from a DHCP server.
|
||||
|
||||
If this option is set, it will be used by the system when requesting an IP address.
|
||||
If not set, no changes will be made.
|
||||
|
||||
Set to the string "empty" to clear any previously configured client ID
|
||||
and restore the system default behavior.
|
||||
'';
|
||||
};
|
||||
|
||||
networking.dns = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
@@ -162,6 +180,7 @@ in
|
||||
warnings = [
|
||||
(mkIf (cfg.knownNetworkServices == [] && cfg.dns != []) "networking.knownNetworkServices is empty, dns servers will not be configured.")
|
||||
(mkIf (cfg.knownNetworkServices == [] && cfg.search != []) "networking.knownNetworkServices is empty, dns searchdomains will not be configured.")
|
||||
(mkIf (cfg.knownNetworkServices == [] && cfg.dhcpClientId != null) "networking.knownNetworkServices is empty, dhcp client ID will not be configured.")
|
||||
];
|
||||
|
||||
system.activationScripts.networking.text = ''
|
||||
|
||||
+14
-4
@@ -757,6 +757,9 @@ in
|
||||
"6bb8d6b0dd16b44ee793a9b8382dac76c926e4c16ffb8ddd2bb4884d1ca3f811" # DeterminateSystems Nix installer 0.34.0
|
||||
"24797ac05542ff8b52910efc77870faa5f9e3275097227ea4e50c430a5f72916" # lix-installer 0.17.1 with flakes
|
||||
"b027b5cad320b5b8123d9d0db9f815c3f3921596c26dc3c471457098e4d3cc40" # lix-installer 0.17.1 without flakes
|
||||
"74ee0ae5ad21a1b101617685fd3d001f74a9466d9d763d92eb75b99cc740db91" # experimental official Nix installer 2.33.3
|
||||
"daa9d824601c088f52de3da176e14328ba41e7be3eb450fdf8b93c86f236f722" # lix-installer 3.95.0 (47bc300) with flakes
|
||||
"7659f39ef9ab9cdf50f8e6ae3476cbf3f27be6485500d1f225d45574d943a9f7" # lix-installer 3.95.0 (47bc300) without flakes
|
||||
];
|
||||
|
||||
environment.etc."nix/registry.json".text = builtins.toJSON {
|
||||
@@ -814,9 +817,12 @@ in
|
||||
{ assertion = config.users.groups ? "nixbld" -> config.users.groups.nixbld.members != []; message = "refusing to remove all members from nixbld group, this would break nix"; }
|
||||
|
||||
{
|
||||
# Should be fixed in Lix by https://gerrit.lix.systems/c/lix/+/2100
|
||||
# Should be fixed in Lix by https://gerrit.lix.systems/c/lix/+/2100, Nix by https://github.com/NixOS/nix/commit/d888846b68dd5fad998b84c5cb6246b1b63398cd
|
||||
# Lix 2.92.0 will set `VERSION_SUFFIX` to `""`; `lib.versionAtLeast "" "pre20241107"` will return `true`.
|
||||
assertion = cfg.settings.auto-optimise-store -> (cfg.package.pname == "lix" && (isNixAtLeast "2.92.0" && versionAtLeast (strings.removePrefix "-" cfg.package.VERSION_SUFFIX) "pre20241107"));
|
||||
assertion = cfg.settings.auto-optimise-store -> (
|
||||
(cfg.package.pname == "lix" && (isNixAtLeast "2.92.0" && versionAtLeast (strings.removePrefix "-" cfg.package.VERSION_SUFFIX) "pre20241107"))
|
||||
|| (cfg.package.pname == "nix" && ((isNixAtLeast "2.31.3" && !isNixAtLeast "2.32") || isNixAtLeast "2.32.5" || isNixAtLeast "2.33"))
|
||||
);
|
||||
message = "`nix.settings.auto-optimise-store` is known to corrupt the Nix Store, please use `nix.optimise.automatic` instead.";
|
||||
}
|
||||
];
|
||||
@@ -881,10 +887,14 @@ in
|
||||
# to express that we want it deleted and know only one hash?
|
||||
system.activationScripts.checks.text = mkAfter ''
|
||||
nixCustomConfKnownSha256Hashes=(
|
||||
# v0.33.0
|
||||
# DetSys v0.33.0
|
||||
6787fade1cf934f82db554e78e1fc788705c2c5257fddf9b59bdd963ca6fec63
|
||||
# v0.34.0
|
||||
# DetSys v0.34.0
|
||||
3bd68ef979a42070a44f8d82c205cfd8e8cca425d91253ec2c10a88179bb34aa
|
||||
# Nix 2.33.3
|
||||
71f7fdc9f6c9e55ca0f2e6f85137037d660b3224a34d59305e8530ca292bc734
|
||||
# Lix 2.95.1
|
||||
a6dee4985bf207d3bec6a3cee28aefb33e60f5d0a91d8c20bbd71b9dadb2e601
|
||||
)
|
||||
if [[ -e /etc/nix/nix.custom.conf ]]; then
|
||||
nixCustomConfSha256Output=$(shasum -a 256 /etc/nix/nix.custom.conf)
|
||||
|
||||
@@ -17,10 +17,13 @@ let
|
||||
mergeConfig =
|
||||
lhs_: rhs_:
|
||||
let
|
||||
lhs = optCall lhs_ { inherit pkgs; };
|
||||
rhs = optCall rhs_ { inherit pkgs; };
|
||||
lhs = optCall lhs_ { inherit lib pkgs; };
|
||||
rhs = optCall rhs_ { inherit lib pkgs; };
|
||||
in
|
||||
lib.recursiveUpdate lhs rhs
|
||||
// lib.optionalAttrs (lhs ? allowUnfreePackages) {
|
||||
allowUnfreePackages = lhs.allowUnfreePackages ++ (lib.attrByPath [ "allowUnfreePackages" ] [ ] rhs);
|
||||
}
|
||||
// lib.optionalAttrs (lhs ? packageOverrides) {
|
||||
packageOverrides =
|
||||
pkgs:
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.programs.devenv;
|
||||
|
||||
hook = shell: "${lib.getExe cfg.package} hook ${shell}";
|
||||
in
|
||||
{
|
||||
meta.maintainers = [
|
||||
lib.maintainers.domenkozar or "domenkozar"
|
||||
lib.maintainers.sandydoo or "sandydoo"
|
||||
lib.maintainers.anish or "anish"
|
||||
];
|
||||
|
||||
options.programs.devenv = {
|
||||
enable = lib.mkEnableOption "devenv, fast, declarative, reproducible and composable developer environments";
|
||||
|
||||
package = lib.mkPackageOption pkgs "devenv" { };
|
||||
|
||||
enableBashIntegration = lib.mkEnableOption "auto-activation of devenv environments in Bash" // {
|
||||
default = true;
|
||||
};
|
||||
|
||||
enableFishIntegration = lib.mkEnableOption "auto-activation of devenv environments in Fish" // {
|
||||
default = true;
|
||||
};
|
||||
|
||||
enableZshIntegration = lib.mkEnableOption "auto-activation of devenv environments in Zsh" // {
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
programs.bash.interactiveShellInit = lib.mkIf cfg.enableBashIntegration ''
|
||||
eval "$(${hook "bash"})"
|
||||
'';
|
||||
|
||||
programs.fish.interactiveShellInit = lib.mkIf cfg.enableFishIntegration ''
|
||||
${hook "fish"} | source
|
||||
'';
|
||||
|
||||
programs.zsh.interactiveShellInit = lib.mkIf cfg.enableZshIntegration ''
|
||||
eval "$(${hook "zsh"})"
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -5,6 +5,13 @@
|
||||
...
|
||||
}: let
|
||||
cfg = config.programs.direnv;
|
||||
enabledOption =
|
||||
x:
|
||||
lib.mkEnableOption x
|
||||
// {
|
||||
default = true;
|
||||
example = false;
|
||||
};
|
||||
format = pkgs.formats.toml {};
|
||||
in {
|
||||
meta.maintainers = [
|
||||
@@ -25,6 +32,16 @@ in {
|
||||
description = "The wrapped direnv package.";
|
||||
};
|
||||
|
||||
enableBashIntegration = enabledOption ''
|
||||
Bash integration
|
||||
'';
|
||||
enableZshIntegration = enabledOption ''
|
||||
Zsh integration
|
||||
'';
|
||||
enableFishIntegration = enabledOption ''
|
||||
Fish integration
|
||||
'';
|
||||
|
||||
direnvrcExtra = lib.mkOption {
|
||||
type = lib.types.lines;
|
||||
default = "";
|
||||
@@ -97,7 +114,7 @@ in {
|
||||
};
|
||||
};
|
||||
};
|
||||
zsh.interactiveShellInit = ''
|
||||
zsh.interactiveShellInit = lib.mkIf cfg.enableZshIntegration ''
|
||||
if ${lib.boolToString cfg.loadInNixShell} || printenv PATH | grep -vqc '/nix/store'; then
|
||||
eval "$(${lib.getExe cfg.finalPackage} hook zsh)"
|
||||
fi
|
||||
@@ -105,13 +122,13 @@ in {
|
||||
|
||||
#$NIX_GCROOT for "nix develop" https://github.com/NixOS/nix/blob/6db66ebfc55769edd0c6bc70fcbd76246d4d26e0/src/nix/develop.cc#L530
|
||||
#$IN_NIX_SHELL for "nix-shell"
|
||||
bash.interactiveShellInit = ''
|
||||
bash.interactiveShellInit = lib.mkIf cfg.enableBashIntegration ''
|
||||
if ${lib.boolToString cfg.loadInNixShell} || [ -z "$IN_NIX_SHELL$NIX_GCROOT$(printenv PATH | grep '/nix/store')" ] ; then
|
||||
eval "$(${lib.getExe cfg.finalPackage} hook bash)"
|
||||
fi
|
||||
'';
|
||||
|
||||
fish.interactiveShellInit = ''
|
||||
fish.interactiveShellInit = lib.mkIf cfg.enableFishIntegration ''
|
||||
if ${lib.boolToString cfg.loadInNixShell};
|
||||
or printenv PATH | grep -vqc '/nix/store';
|
||||
${lib.getExe cfg.finalPackage} hook fish | source
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (lib)
|
||||
getExe'
|
||||
mkIf
|
||||
mkOption
|
||||
mkPackageOption
|
||||
optionalString
|
||||
types
|
||||
;
|
||||
|
||||
cfg = config.programs.gnupg;
|
||||
|
||||
@@ -10,6 +21,8 @@ in
|
||||
|
||||
{
|
||||
options.programs.gnupg = {
|
||||
package = mkPackageOption pkgs "gnupg" { };
|
||||
|
||||
agent.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -29,9 +42,12 @@ in
|
||||
};
|
||||
|
||||
config = mkIf cfg.agent.enable {
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
launchd.user.agents.gnupg-agent.serviceConfig = {
|
||||
ProgramArguments = [
|
||||
"${pkgs.gnupg}/bin/gpg-connect-agent" "/bye"
|
||||
(getExe' cfg.package "gpg-connect-agent")
|
||||
"/bye"
|
||||
];
|
||||
RunAtLoad = cfg.agent.enableSSHSupport;
|
||||
KeepAlive.SuccessfulExit = false;
|
||||
@@ -40,12 +56,13 @@ in
|
||||
environment.extraInit = ''
|
||||
# Bind gpg-agent to this TTY if gpg commands are used.
|
||||
export GPG_TTY=$(tty)
|
||||
'' + (optionalString cfg.agent.enableSSHSupport ''
|
||||
''
|
||||
+ (optionalString cfg.agent.enableSSHSupport ''
|
||||
# SSH agent protocol doesn't support changing TTYs, so bind the agent
|
||||
# to every new TTY.
|
||||
${pkgs.gnupg}/bin/gpg-connect-agent --quiet updatestartuptty /bye > /dev/null 2>&1
|
||||
${getExe' cfg.package "gpg-connect-agent"} --quiet updatestartuptty /bye > /dev/null 2>&1
|
||||
|
||||
export SSH_AUTH_SOCK=$(${pkgs.gnupg}/bin/gpgconf --list-dirs agent-ssh-socket)
|
||||
export SSH_AUTH_SOCK=$(${getExe' cfg.package "gpgconf"} --list-dirs agent-ssh-socket)
|
||||
'');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
options,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (lib)
|
||||
attrValues
|
||||
concatStringsSep
|
||||
escapeShellArg
|
||||
getExe
|
||||
literalExpression
|
||||
mapAttrsToList
|
||||
mkEnableOption
|
||||
mkIf
|
||||
mkOption
|
||||
mkOptionDefault
|
||||
mkPackageOption
|
||||
optionalString
|
||||
types
|
||||
;
|
||||
|
||||
cfg = config.programs.mas;
|
||||
|
||||
apps = mapAttrsToList (name: id: { inherit name id; }) cfg.packages;
|
||||
|
||||
desiredIds = map (app: toString app.id) apps;
|
||||
homebrewIds = map toString (attrValues config.homebrew.masApps);
|
||||
|
||||
hasWork = cfg.update || cfg.packages != { } || cfg.cleanup || homebrewIds != [ ];
|
||||
|
||||
activationScript =
|
||||
if hasWork then
|
||||
''
|
||||
echo >&2 "setting up App Store apps (mas)..."
|
||||
|
||||
runAsUser() {
|
||||
sudo \
|
||||
--preserve-env=PATH \
|
||||
--set-home \
|
||||
--user=${escapeShellArg cfg.user} \
|
||||
"$@"
|
||||
}
|
||||
|
||||
listStatus=0
|
||||
listOutput=$(
|
||||
runAsUser ${getExe cfg.package} list 2>&1
|
||||
) || listStatus=$?
|
||||
|
||||
if (( listStatus != 0 )); then
|
||||
echo >&2 "warning: mas list failed (exit ''${listStatus}):"
|
||||
echo >&2 "''${listOutput}"
|
||||
if echo "''${listOutput}" | grep -qi "not signed in"; then
|
||||
echo >&2 "login required; skipping App Store installs/updates/cleanup"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Only emit cleanup-only shell variables when cleanup is enabled; otherwise shellcheck
|
||||
# treats them as unused and fails the activation script build.
|
||||
installedIds=()
|
||||
${if cfg.cleanup then
|
||||
''
|
||||
# Parse mas list output: "ID AppName (version)"
|
||||
declare -A installedApps
|
||||
while IFS= read -r line; do
|
||||
[[ -z "$line" ]] && continue
|
||||
line="''${line#"''${line%%[![:space:]]*}"}"
|
||||
id="''${line%% *}"
|
||||
rest="''${line#"$id"}"
|
||||
rest="''${rest#"''${rest%%[![:space:]]*}"}"
|
||||
name="''${rest% (*}"
|
||||
name="''${name%"''${name##*[![:space:]]}"}"
|
||||
[[ -n "$id" ]] && {
|
||||
installedIds+=( "$id" )
|
||||
installedApps["$id"]="$name"
|
||||
}
|
||||
done <<<"$listOutput"
|
||||
''
|
||||
else
|
||||
''
|
||||
while IFS= read -r line; do
|
||||
[[ -z "$line" ]] && continue
|
||||
line="''${line#"''${line%%[![:space:]]*}"}"
|
||||
id="''${line%% *}"
|
||||
[[ -n "$id" ]] && installedIds+=( "$id" )
|
||||
done <<<"$listOutput"
|
||||
''}
|
||||
|
||||
${optionalString cfg.update ''
|
||||
runAsUser ${getExe cfg.package} update || true
|
||||
''}
|
||||
|
||||
desiredIds=(
|
||||
${concatStringsSep "\n " desiredIds}
|
||||
)
|
||||
|
||||
is_installed() {
|
||||
local needle=$1
|
||||
for id in "''${installedIds[@]}"; do
|
||||
if [[ "$id" == "$needle" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
${optionalString (cfg.packages != { }) ''
|
||||
for appId in "''${desiredIds[@]}"; do
|
||||
if is_installed "$appId"; then
|
||||
continue
|
||||
fi
|
||||
runAsUser ${getExe cfg.package} install "$appId" || true
|
||||
done
|
||||
''}
|
||||
|
||||
${optionalString cfg.cleanup ''
|
||||
homebrewIds=(
|
||||
${concatStringsSep "\n " homebrewIds}
|
||||
)
|
||||
|
||||
keepIds=( "''${desiredIds[@]}" "''${homebrewIds[@]}" )
|
||||
|
||||
for installedId in "''${installedIds[@]}"; do
|
||||
keep=false
|
||||
for keepId in "''${keepIds[@]}"; do
|
||||
if [[ "$installedId" == "$keepId" ]]; then
|
||||
keep=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if ! $keep; then
|
||||
appName="''${installedApps[$installedId]:-$installedId}"
|
||||
echo >&2 "removing $appName from App Store"
|
||||
runAsUser ${getExe cfg.package} uninstall "$installedId" || true
|
||||
fi
|
||||
done
|
||||
''}
|
||||
''
|
||||
else
|
||||
"";
|
||||
in
|
||||
{
|
||||
options.programs.mas = {
|
||||
enable = mkEnableOption "managing Mac App Store apps with mas";
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = config.system.primaryUser;
|
||||
defaultText = literalExpression "config.system.primaryUser";
|
||||
description = ''
|
||||
The user account that runs {command}`mas`. This user must be signed into the Mac App Store
|
||||
for installs or updates to succeed.
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkPackageOption pkgs "mas" { };
|
||||
|
||||
packages = mkOption {
|
||||
type = types.attrsOf types.ints.positive;
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
{
|
||||
Xcode = 497799835;
|
||||
"1Password for Safari" = 1569813296;
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Applications to install from the Mac App Store. Attribute names are only for readability;
|
||||
values must be the numeric identifiers used by {command}`mas`.
|
||||
'';
|
||||
};
|
||||
|
||||
update = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to run {command}`mas update` during system activation in addition to installing the
|
||||
configured apps.
|
||||
'';
|
||||
};
|
||||
|
||||
cleanup = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to uninstall Mac App Store apps that are currently installed but not listed in
|
||||
{option}`programs.mas.packages`. Apps listed in {option}`homebrew.masApps` are also preserved.
|
||||
This runs before install/update; any app id not in either set will be removed.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
system.requiresPrimaryUser =
|
||||
mkIf (cfg.enable && options.programs.mas.user.highestPrio == (mkOptionDefault { }).priority)
|
||||
[
|
||||
"programs.mas.enable"
|
||||
];
|
||||
|
||||
environment.systemPackages = mkIf cfg.enable [ cfg.package ];
|
||||
|
||||
system.activationScripts.mas.text = mkIf cfg.enable activationScript;
|
||||
};
|
||||
}
|
||||
@@ -57,6 +57,17 @@ in
|
||||
description = "Enable sensible configuration options for tmux.";
|
||||
};
|
||||
|
||||
programs.tmux.reverseSplitBindings = mkOption {
|
||||
type = types.bool;
|
||||
default = config.system.stateVersion <= 6 && cfg.enableSensible;
|
||||
defaultText = literalExpression "config.system.stateVersion <= 6 && config.programs.tmux.enableSensible";
|
||||
example = true;
|
||||
description = ''
|
||||
Whether to reverse the `%` and `"` split-window key bindings
|
||||
emitted by the tmux module.
|
||||
'';
|
||||
};
|
||||
|
||||
programs.tmux.enableMouse = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -127,8 +138,6 @@ in
|
||||
set -s escape-time 0
|
||||
|
||||
bind c new-window -c '#{pane_current_path}'
|
||||
bind % split-window -v -c '#{pane_current_path}'
|
||||
bind '"' split-window -h -c '#{pane_current_path}'
|
||||
|
||||
# TODO: make these interactive
|
||||
bind C new-session
|
||||
@@ -138,6 +147,11 @@ in
|
||||
# set -g utf8 on
|
||||
'';
|
||||
|
||||
programs.tmux.tmuxOptions.splitBindings.text = mkIf cfg.reverseSplitBindings ''
|
||||
bind % split-window -v -c '#{pane_current_path}'
|
||||
bind '"' split-window -h -c '#{pane_current_path}'
|
||||
'';
|
||||
|
||||
programs.tmux.tmuxOptions.mouse.text = mkIf cfg.enableMouse ''
|
||||
set -g mouse on
|
||||
setw -g mouse on
|
||||
|
||||
@@ -260,6 +260,7 @@ in
|
||||
|
||||
environment.etc."zshenv".knownSha256Hashes = [
|
||||
"d07015be6875f134976fce84c6c7a77b512079c1c5f9594dfa65c70b7968b65f" # DeterminateSystems installer
|
||||
"4e8f7cb9b699511f4ba5f9d5f8de1c9f5efb5c607de88faf5f58b8b9cb38edbf" # experimental official Nix installer 2.33.3
|
||||
];
|
||||
|
||||
};
|
||||
|
||||
@@ -263,7 +263,7 @@ in
|
||||
|
||||
nodeRuntimes = mkOption {
|
||||
type = with types; nonEmptyListOf (enum [ "node20" "node24" ]);
|
||||
default = [ "node20" "node24" ];
|
||||
default = [ "node24" ];
|
||||
description = ''
|
||||
List of Node.js runtimes the runner should support.
|
||||
'';
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
let
|
||||
inherit (lib) any attrValues boolToString concatStringsSep escapeShellArg
|
||||
flatten flip getExe getExe' hasAttr hasPrefix mapAttrsToList mapAttrs' mkBefore
|
||||
mkDefault mkIf mkMerge nameValuePair optionalAttrs optionalString replaceStrings;
|
||||
flatten flip getExe getExe' hasPrefix mapAttrsToList mapAttrs' mkBefore
|
||||
mkDefault mkIf mkMerge nameValuePair optionalString replaceStrings;
|
||||
|
||||
mkSvcName = name: "github-runner-${name}";
|
||||
mkStateDir = cfg: "/var/lib/github-runners/${cfg.name}";
|
||||
mkLogDir = cfg: "/var/log/github-runners/${cfg.name}";
|
||||
mkWorkDir = cfg: if (cfg.workDir != null) then cfg.workDir else "/var/lib/github-runners/_work/${cfg.name}";
|
||||
mkWorkDir = cfg: if (cfg.workDir != null) then cfg.workDir else "/private/var/lib/github-runners/_work/${cfg.name}";
|
||||
in
|
||||
{
|
||||
config.assertions = flatten (
|
||||
@@ -54,7 +54,7 @@ in
|
||||
in
|
||||
{
|
||||
launchd = mkIf cfg.enable {
|
||||
text = mkBefore (''
|
||||
text = mkBefore ''
|
||||
echo >&2 "setting up GitHub Runner '${cfg.name}'..."
|
||||
|
||||
# shellcheck disable=SC2174
|
||||
@@ -70,7 +70,7 @@ in
|
||||
${getExe' pkgs.coreutils "mkdir"} -p -m u=rwx,g=rx,o= ${escapeShellArg (mkWorkDir cfg)}
|
||||
${getExe' pkgs.coreutils "chown"} ${user}:${group} ${escapeShellArg (mkWorkDir cfg)}
|
||||
''}
|
||||
'');
|
||||
'';
|
||||
};
|
||||
}));
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ in {
|
||||
];
|
||||
|
||||
options.services.jankyborders = {
|
||||
enable = mkEnableOption "Enable the jankyborders service.";
|
||||
enable = mkEnableOption "the jankyborders service.";
|
||||
|
||||
package = mkPackageOption pkgs "jankyborders" {};
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ in
|
||||
services.khd.i3Keybindings = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Wether to configure i3 style keybindings for kwm.";
|
||||
description = "Whether to configure i3 style keybindings for kwm.";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
let
|
||||
inherit (lib)
|
||||
escapeShellArg
|
||||
concatStringsSep
|
||||
escapeShellArgs
|
||||
getExe
|
||||
mkEnableOption
|
||||
mkIf
|
||||
@@ -104,7 +104,8 @@ in {
|
||||
]
|
||||
++ (map (collector: "--collector.${collector}") cfg.enabledCollectors)
|
||||
++ (map (collector: "--no-collector.${collector}") cfg.disabledCollectors)
|
||||
) + escapeShellArgs cfg.extraFlags;
|
||||
++ (map escapeShellArg cfg.extraFlags)
|
||||
);
|
||||
serviceConfig = let
|
||||
logPath = config.users.users._prometheus-node-exporter.home
|
||||
+ "/prometheus-node-exporter.log";
|
||||
|
||||
@@ -1,7 +1,72 @@
|
||||
{ config, lib, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.openssh;
|
||||
|
||||
hostKeyOpts = {
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "dsa" "ecdsa" "ed25519" "rsa" ];
|
||||
description = ''
|
||||
Key type passed to `ssh-keygen -t`.
|
||||
'';
|
||||
};
|
||||
|
||||
path = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
Path to the private key file.
|
||||
'';
|
||||
};
|
||||
|
||||
bits = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
Key size in bits. If `null`, `ssh-keygen` uses the default
|
||||
for the given key type (RSA=3072, ECDSA=256, ED25519=fixed).
|
||||
'';
|
||||
};
|
||||
|
||||
comment = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
description = ''
|
||||
Comment for the key, passed to `ssh-keygen -C`.
|
||||
|
||||
Defaults to an empty string to match Apple's built-in host key
|
||||
generation and avoid leaking the hostname.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hostKeysConfig = lib.concatMapStringsSep "\n"
|
||||
(k: "HostKey ${k.path}")
|
||||
cfg.hostKeys;
|
||||
|
||||
keygenScript = lib.concatMapStrings (k:
|
||||
let
|
||||
escapedPath = lib.escapeShellArg k.path;
|
||||
in ''
|
||||
if ! [[ -s ${escapedPath} ]]; then
|
||||
if ! [[ -L ${escapedPath} ]]; then
|
||||
rm -f ${escapedPath}
|
||||
fi
|
||||
|
||||
keygenArgs=(
|
||||
-t ${lib.escapeShellArg k.type}
|
||||
${lib.optionalString (k.bits != null) "-b ${toString k.bits}"}
|
||||
-C ${lib.escapeShellArg k.comment}
|
||||
-f ${escapedPath}
|
||||
-N ""
|
||||
)
|
||||
|
||||
mkdir -p "$(dirname ${escapedPath})"
|
||||
chmod 0755 "$(dirname ${escapedPath})"
|
||||
${lib.getExe' pkgs.openssh "ssh-keygen"} "''${keygenArgs[@]}"
|
||||
fi
|
||||
'') cfg.hostKeys;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
@@ -24,6 +89,22 @@ in
|
||||
See {manpage}`sshd_config(5)` for help.
|
||||
'';
|
||||
};
|
||||
|
||||
hostKeys = lib.mkOption {
|
||||
type = lib.types.listOf (lib.types.submodule hostKeyOpts);
|
||||
default = [
|
||||
{ type = "rsa"; path = "/etc/ssh/ssh_host_rsa_key"; }
|
||||
{ type = "ecdsa"; path = "/etc/ssh/ssh_host_ecdsa_key"; }
|
||||
{ type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; }
|
||||
];
|
||||
description = ''
|
||||
SSH host key declarations. Each entry specifies a key type and path.
|
||||
`HostKey` directives are written to the sshd configuration for each
|
||||
entry.
|
||||
|
||||
The default matches the keys that macOS automatically generates.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -41,6 +122,12 @@ in
|
||||
fi
|
||||
'');
|
||||
|
||||
environment.etc."ssh/sshd_config.d/099-host-keys.conf" = lib.mkIf (cfg.hostKeys != []) {
|
||||
text = hostKeysConfig;
|
||||
};
|
||||
|
||||
environment.etc."ssh/sshd_config.d/100-nix-darwin.conf".text = cfg.extraConfig;
|
||||
|
||||
system.activationScripts.openssh.text = lib.mkIf (cfg.hostKeys != []) keygenScript;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,11 +22,12 @@ in
|
||||
services.spacebar.enable = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
description = "Whether to enable the spacebar spacebar.";
|
||||
description = "Whether to enable the spacebar.";
|
||||
};
|
||||
|
||||
services.spacebar.package = mkOption {
|
||||
type = path;
|
||||
default = pkgs.spacebar;
|
||||
description = "The spacebar package to use.";
|
||||
};
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ let
|
||||
preDown = mkOption {
|
||||
type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
|
||||
default = "";
|
||||
description = "List of commadns to run before interface shutdown.";
|
||||
description = "List of commands to run before interface shutdown.";
|
||||
};
|
||||
|
||||
preUp = mkOption {
|
||||
|
||||
@@ -121,6 +121,7 @@ in
|
||||
${cfg.activationScripts.applications.text}
|
||||
${cfg.activationScripts.pam.text}
|
||||
${cfg.activationScripts.patches.text}
|
||||
${cfg.activationScripts.openssh.text}
|
||||
${cfg.activationScripts.etc.text}
|
||||
${cfg.activationScripts.defaults.text}
|
||||
${cfg.activationScripts.userDefaults.text}
|
||||
@@ -133,6 +134,7 @@ in
|
||||
${cfg.activationScripts.keyboard.text}
|
||||
${cfg.activationScripts.fonts.text}
|
||||
${cfg.activationScripts.nvram.text}
|
||||
${cfg.activationScripts.mas.text}
|
||||
${cfg.activationScripts.homebrew.text}
|
||||
|
||||
${cfg.activationScripts.postActivation.text}
|
||||
|
||||
@@ -252,7 +252,7 @@ let
|
||||
'';
|
||||
|
||||
homebrewInstalled = ''
|
||||
if [[ ! -f ${escapeShellArg config.homebrew.brewPrefix}/brew && -z "''${INSTALLING_HOMEBREW:-}" ]]; then
|
||||
if [[ ! -f ${escapeShellArg config.homebrew.prefix}/bin/brew && -z "''${INSTALLING_HOMEBREW:-}" ]]; then
|
||||
echo "[1;31merror: Using the homebrew module requires homebrew installed, aborting activation[0m" >&2
|
||||
echo "Homebrew doesn't seem to be installed. Please install homebrew separately." >&2
|
||||
echo "You can install homebrew using the following command:" >&2
|
||||
|
||||
@@ -41,6 +41,14 @@ with lib;
|
||||
'';
|
||||
};
|
||||
|
||||
system.defaults.screencapture.save-selections = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
Remember the selection window of the last screencapture. The default is true.
|
||||
'';
|
||||
};
|
||||
|
||||
system.defaults.screencapture.show-thumbnail = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
|
||||
@@ -38,6 +38,18 @@ in
|
||||
description = "Whether to swap the left Command key and left Alt key.";
|
||||
};
|
||||
|
||||
system.keyboard.swapRightCommandAndRightOption = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to swap the right Command key and right Option key.";
|
||||
};
|
||||
|
||||
system.keyboard.swapCapsLockAndEscape = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to swap the Caps Lock key and Escape key.";
|
||||
};
|
||||
|
||||
system.keyboard.swapLeftCtrlAndFn = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -64,6 +76,14 @@ in
|
||||
(mkIf cfg.remapCapsLockToControl { HIDKeyboardModifierMappingSrc = 30064771129; HIDKeyboardModifierMappingDst = 30064771296; })
|
||||
(mkIf cfg.remapCapsLockToEscape { HIDKeyboardModifierMappingSrc = 30064771129; HIDKeyboardModifierMappingDst = 30064771113; })
|
||||
(mkIf cfg.nonUS.remapTilde { HIDKeyboardModifierMappingSrc = 30064771172; HIDKeyboardModifierMappingDst = 30064771125; })
|
||||
(mkIf cfg.swapCapsLockAndEscape {
|
||||
HIDKeyboardModifierMappingSrc = 30064771129;
|
||||
HIDKeyboardModifierMappingDst = 30064771113;
|
||||
})
|
||||
(mkIf cfg.swapCapsLockAndEscape {
|
||||
HIDKeyboardModifierMappingSrc = 30064771113;
|
||||
HIDKeyboardModifierMappingDst = 30064771129;
|
||||
})
|
||||
(mkIf cfg.swapLeftCommandAndLeftAlt {
|
||||
HIDKeyboardModifierMappingSrc = 30064771299;
|
||||
HIDKeyboardModifierMappingDst = 30064771298;
|
||||
@@ -72,6 +92,14 @@ in
|
||||
HIDKeyboardModifierMappingSrc = 30064771298;
|
||||
HIDKeyboardModifierMappingDst = 30064771299;
|
||||
})
|
||||
(mkIf cfg.swapRightCommandAndRightOption {
|
||||
HIDKeyboardModifierMappingSrc = 30064771303;
|
||||
HIDKeyboardModifierMappingDst = 30064771302;
|
||||
})
|
||||
(mkIf cfg.swapRightCommandAndRightOption {
|
||||
HIDKeyboardModifierMappingSrc = 30064771302;
|
||||
HIDKeyboardModifierMappingDst = 30064771303;
|
||||
})
|
||||
(mkIf cfg.swapLeftCtrlAndFn {
|
||||
HIDKeyboardModifierMappingSrc = 30064771296;
|
||||
HIDKeyboardModifierMappingDst = 1095216660483;
|
||||
|
||||
@@ -51,7 +51,7 @@ in
|
||||
system.maxStateVersion = mkOption {
|
||||
internal = true;
|
||||
type = types.int;
|
||||
default = 6;
|
||||
default = 7;
|
||||
};
|
||||
|
||||
system.darwinLabel = mkOption {
|
||||
|
||||
@@ -3,19 +3,8 @@
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.time;
|
||||
|
||||
timeZone = optionalString (cfg.timeZone != null) ''
|
||||
if ! systemsetup -listtimezones | grep -q "^ ${cfg.timeZone}$"; then
|
||||
echo "${cfg.timeZone} is not a valid timezone. The command 'listtimezones' will show a list of valid time zones." >&2
|
||||
false
|
||||
fi
|
||||
systemsetup -settimezone "${cfg.timeZone}" 2>/dev/null 1>&2
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
|
||||
@@ -37,8 +26,12 @@ in
|
||||
system.activationScripts.time.text = mkIf (cfg.timeZone != null) ''
|
||||
# Set defaults
|
||||
echo "configuring time..." >&2
|
||||
|
||||
${timeZone}
|
||||
|
||||
if ! systemsetup -listtimezones | grep -q "^ ${cfg.timeZone}$"; then
|
||||
echo "${cfg.timeZone} is not a valid timezone. The command 'listtimezones' will show a list of valid time zones." >&2
|
||||
false
|
||||
fi
|
||||
systemsetup -settimezone "${cfg.timeZone}" 2>/dev/null 1>&2
|
||||
'';
|
||||
|
||||
};
|
||||
|
||||
@@ -203,7 +203,9 @@ in
|
||||
else
|
||||
homeDirectory=$(dscl . -read ${dsclUser} NFSHomeDirectory)
|
||||
homeDirectory=''${homeDirectory#NFSHomeDirectory: }
|
||||
if [[ ${escapeShellArg v.home} != "$homeDirectory" ]]; then
|
||||
configuredHomeDirectory=$(realpath ${escapeShellArg v.home})
|
||||
homeDirectory=$(realpath "$homeDirectory")
|
||||
if [[ "$configuredHomeDirectory" != "$homeDirectory" ]]; then
|
||||
printf >&2 '\e[1;31merror: config contains the wrong home directory for %s, aborting activation\e[0m\n' ${name}
|
||||
printf >&2 'nix-darwin does not support changing the home directory of existing users.\n'
|
||||
printf >&2 '\n'
|
||||
|
||||
@@ -28,7 +28,7 @@ showSyntax() {
|
||||
echo " [--no-update-lock-file] [--no-write-lock-file]" >&2
|
||||
echo " [--override-input input flake] [--update-input input]" >&2
|
||||
echo " [--no-registries] [--offline] [--refresh]]" >&2
|
||||
echo " [--substituters substituters-list] ..." >&2
|
||||
echo " [--substituters substituters-list] [--log-format log-format] ..." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ while [ $# -gt 0 ]; do
|
||||
fi
|
||||
shift 1
|
||||
;;
|
||||
--substituters)
|
||||
--substituters|--log-format)
|
||||
if [ -z "$1" ]; then
|
||||
echo "$0: '$i' requires an argument"
|
||||
exit 1
|
||||
|
||||
@@ -21,6 +21,17 @@ _arguments \
|
||||
'(--keep-going -k)'{--keep-going,-k}"[keep going until all builds are finished]"\
|
||||
'(--keep-failed -K)'{--keep-failed,-K}'[keep failed builds (usually in /tmp)]'\
|
||||
'--fallback[If binary download fails, fall back on building from source]'\
|
||||
'--flake[Build from the given flake URI]:flake uri:'\
|
||||
'--no-flake[Disable implicit flake detection]'\
|
||||
'(-L --print-build-logs)'{-L,--print-build-logs}'[Print build logs during the build]'\
|
||||
'--refresh[Refresh flake inputs]'\
|
||||
'--impure[Allow impure evaluation for flakes]'\
|
||||
'--recreate-lock-file[Recreate flake.lock from scratch]'\
|
||||
'*--update-input[Update a specific flake input]:input name:'\
|
||||
'*--override-input[Override a flake input]:input name: :flake url: '\
|
||||
'--offline[Do not access the network]'\
|
||||
'--dry-run[Show what would be done without making changes]'\
|
||||
'-Q[Only print the resulting store path]'\
|
||||
'--show-trace[Print stack trace of evaluation errors]'\
|
||||
'*--option[set Nix configuration option]:options:_nix_options:value:_nix_options_value'\
|
||||
'*--arg[argument to pass to the Nix function]:Name:_nix_complete_function_arg:Value: '\
|
||||
|
||||
@@ -83,13 +83,21 @@ in {
|
||||
tests.environment-path = makeTest ./tests/environment-path.nix;
|
||||
tests.environment-terminfo = makeTest ./tests/environment-terminfo.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.launchd-daemons = makeTest ./tests/launchd-daemons.nix;
|
||||
tests.launchd-setenv = makeTest ./tests/launchd-setenv.nix;
|
||||
tests.networking-firewall = makeTest ./tests/networking-firewall.nix;
|
||||
tests.networking-hostname = makeTest ./tests/networking-hostname.nix;
|
||||
tests.networking-networkservices = makeTest ./tests/networking-networkservices.nix;
|
||||
tests.networking-networkservices-no-dhcp-client-id = makeTest ./tests/networking-networkservices-no-dhcp-client-id.nix;
|
||||
tests.nix-enable = makeTest ./tests/nix-enable.nix;
|
||||
tests.nixpkgs-overlays = makeTest ./tests/nixpkgs-overlays.nix;
|
||||
tests.nixpkgs-config-allow-unfree = makeTest ./tests/nixpkgs-config-allow-unfree.nix;
|
||||
tests.programs-devenv = makeTest ./tests/programs-devenv.nix;
|
||||
tests.programs-gnupg = makeTest ./tests/programs-gnupg.nix;
|
||||
tests.programs-mas = makeTest ./tests/programs-mas.nix;
|
||||
tests.programs-mas-no-cleanup = makeTest ./tests/programs-mas-no-cleanup.nix;
|
||||
tests.programs-ssh = makeTest ./tests/programs-ssh.nix;
|
||||
tests.programs-tmux = makeTest ./tests/programs-tmux.nix;
|
||||
tests.programs-zsh = makeTest ./tests/programs-zsh.nix;
|
||||
|
||||
Executable
+75
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
git checkout master
|
||||
git pull
|
||||
|
||||
version=$(jq -r .release version.json)
|
||||
|
||||
# branch off ${version}
|
||||
echo "Cutting nix-darwin-${version} release branch"
|
||||
|
||||
git checkout -b "nix-darwin-${version}"
|
||||
|
||||
sed -i -e "s!- master!- nix-darwin-${version}!" .github/workflows/test.yml
|
||||
sed -i -e "s!NIXPKGS_BRANCH: nixpkgs-unstable!NIXPKGS_BRANCH: nixpkgs-${version}-darwin!" .github/workflows/test.yml
|
||||
|
||||
sed -i -e "s!nixpkgs-unstable!nixpkgs-${version}-darwin!" modules/examples/flake/flake.nix
|
||||
sed -i -e "s!github:nix-darwin/nix-darwin/master!github:nix-darwin/nix-darwin/nix-darwin-${version}!" modules/examples/flake/flake.nix
|
||||
|
||||
sed -i -e "s!nixpkgs/unstable!nixpkgs/stable!g" modules/nix/nixpkgs.nix
|
||||
|
||||
sed -i -e "s!nixpkgs-unstable!nixpkgs-${version}-darwin!" flake.nix
|
||||
nix flake lock
|
||||
|
||||
cat <<EOF > README.md
|
||||
# nix-darwin
|
||||
|
||||
This is the ${version} release branch of nix-darwin. See [the main readme](https://github.com/nix-darwin/nix-darwin#readme) for documentation
|
||||
EOF
|
||||
|
||||
cat <<EOF > version.json
|
||||
{
|
||||
"release": "${version}",
|
||||
"isReleaseBranch": true
|
||||
}
|
||||
EOF
|
||||
|
||||
git add .
|
||||
git commit -m "version: branch off ${version}"
|
||||
|
||||
# update master
|
||||
echo "Updating master to point to next version"
|
||||
|
||||
git checkout master
|
||||
|
||||
## update version.json to point to the next version
|
||||
|
||||
IFS='.' read -r major minor <<< "$version"
|
||||
|
||||
if [[ "$minor" = "11" ]]; then
|
||||
major=$(( major + 1 ))
|
||||
minor="05"
|
||||
else
|
||||
minor="11"
|
||||
fi
|
||||
|
||||
cat <<EOF > version.json
|
||||
{
|
||||
"release": "${major}.${minor}",
|
||||
"isReleaseBranch": false
|
||||
}
|
||||
EOF
|
||||
|
||||
## update readme so that instructions refer to the version we're cutting (our supported stable version)
|
||||
|
||||
sed -i -e "s![0-9][0-9]\.[0-9][0-9]!${version}!g" README.md
|
||||
|
||||
git add .
|
||||
git commit -m "version: bump to ${major}.${minor}"
|
||||
|
||||
nix flake update
|
||||
|
||||
git add .
|
||||
git commit -m "flake.lock: update"
|
||||
@@ -550,6 +550,11 @@ launchctl asuser "$(id -u -- test-defaults-user)" sudo --user=test-defaults-user
|
||||
<plist version="1.0">
|
||||
<string>/tmp</string>
|
||||
</plist>'
|
||||
launchctl asuser "$(id -u -- test-defaults-user)" sudo --user=test-defaults-user -- defaults write com.apple.screencapture save-selections '<?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">
|
||||
<true/>
|
||||
</plist>'
|
||||
launchctl asuser "$(id -u -- test-defaults-user)" sudo --user=test-defaults-user -- defaults write com.apple.screencapture target '<?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">
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{ config, ... }:
|
||||
|
||||
let
|
||||
brewBundleInstallCmd = config.homebrew.onActivation.brewBundleCmd { onlyCheck = false; };
|
||||
in
|
||||
|
||||
{
|
||||
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 --file='.*-Brewfile' cleanup" ${config.out}/activate
|
||||
|
||||
echo "checking that brew bundle [install] command does not have --cleanup flag" >&2
|
||||
if echo "${brewBundleInstallCmd}" | grep -F -- '--cleanup' > /dev/null; then
|
||||
echo "Expected no --cleanup flag in brewBundleInstallCmd"
|
||||
echo "Actual: ${brewBundleInstallCmd}"
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{ config, ... }:
|
||||
|
||||
{
|
||||
homebrew.enable = true;
|
||||
programs.bash.enable = true;
|
||||
programs.zsh.enable = true;
|
||||
programs.fish.enable = true;
|
||||
|
||||
homebrew.user = "test-homebrew-user";
|
||||
|
||||
homebrew.enableBashIntegration = true;
|
||||
homebrew.enableFishIntegration = true;
|
||||
homebrew.enableZshIntegration = true;
|
||||
|
||||
test = ''
|
||||
echo >&2 "checking bash shell integration in /etc/bashrc"
|
||||
grep 'brew shellenv bash' ${config.out}/etc/bashrc
|
||||
echo >&2 "checking bash completions in /etc/bashrc"
|
||||
grep 'bash_completion' ${config.out}/etc/bashrc
|
||||
|
||||
echo >&2 "checking zsh shell integration in /etc/zshrc"
|
||||
grep 'brew shellenv zsh' ${config.out}/etc/zshrc
|
||||
|
||||
echo >&2 "checking fish shell integration in /etc/fish/config.fish"
|
||||
grep 'brew shellenv fish' ${config.out}/etc/fish/config.fish
|
||||
echo >&2 "checking fish completions in /etc/fish/config.fish"
|
||||
grep 'fish_complete_path' ${config.out}/etc/fish/config.fish
|
||||
'';
|
||||
}
|
||||
+39
-7
@@ -17,7 +17,7 @@ in
|
||||
|
||||
homebrew.user = "test-homebrew-user";
|
||||
|
||||
# Examples taken from https://github.com/Homebrew/homebrew-bundle
|
||||
# Examples adapted from https://docs.brew.sh/Brew-Bundle-and-Brewfile
|
||||
homebrew.taps = [
|
||||
"homebrew/cask"
|
||||
{
|
||||
@@ -41,7 +41,8 @@ in
|
||||
{
|
||||
name = "denji/nginx/nginx-full";
|
||||
args = [ "with-rmtp" ];
|
||||
restart_service = "changed";
|
||||
link = "overwrite";
|
||||
restart_service = "always";
|
||||
}
|
||||
{
|
||||
name = "mysql@5.6";
|
||||
@@ -49,6 +50,10 @@ in
|
||||
link = true;
|
||||
conflicts_with = [ "mysql" ];
|
||||
}
|
||||
{
|
||||
name = "postgresql@16";
|
||||
postinstall = "\${HOMEBREW_PREFIX}/opt/postgresql@16/bin/postgres -D \${HOMEBREW_PREFIX}/var/postgresql@16";
|
||||
}
|
||||
];
|
||||
|
||||
homebrew.casks = [
|
||||
@@ -61,6 +66,10 @@ in
|
||||
name = "opera";
|
||||
greedy = true;
|
||||
}
|
||||
{
|
||||
name = "google-cloud-sdk";
|
||||
postinstall = "\${HOMEBREW_PREFIX}/bin/gcloud components update";
|
||||
}
|
||||
];
|
||||
|
||||
homebrew.masApps = {
|
||||
@@ -68,10 +77,19 @@ in
|
||||
Xcode = 497799835;
|
||||
};
|
||||
|
||||
homebrew.whalebrews = [
|
||||
"whalebrew/wget"
|
||||
homebrew.vscode = [
|
||||
"golang.go"
|
||||
];
|
||||
|
||||
homebrew.goPackages = [
|
||||
"github.com/charmbracelet/crush"
|
||||
];
|
||||
|
||||
homebrew.cargoPackages = [
|
||||
"ripgrep"
|
||||
];
|
||||
|
||||
|
||||
test = ''
|
||||
bf=${lib.escapeShellArg config.homebrew.brewfile}
|
||||
|
||||
@@ -85,19 +103,33 @@ in
|
||||
|
||||
echo "checking brew entries in Brewfile" >&2
|
||||
${mkTest "imagemagick" ''brew "imagemagick"''}
|
||||
${mkTest "denji/nginx/nginx-full" ''brew "denji/nginx/nginx-full", args: ["with-rmtp"], restart_service: :changed''}
|
||||
${mkTest "denji/nginx/nginx-full" ''brew "denji/nginx/nginx-full", args: ["with-rmtp"], link: :overwrite, restart_service: :always''}
|
||||
${mkTest "mysql@5.6" ''brew "mysql@5.6", conflicts_with: ["mysql"], link: true, restart_service: true''}
|
||||
${mkTest "postgresql@16" ''brew "postgresql@16", postinstall: "''${HOMEBREW_PREFIX}/opt/postgresql@16/bin/postgres -D ''${HOMEBREW_PREFIX}/var/postgresql@16"''}
|
||||
|
||||
echo "checking cask entries in Brewfile" >&2
|
||||
${mkTest "google-chrome" ''cask "google-chrome"''}
|
||||
${mkTest "firefox" ''cask "firefox", args: { appdir: "~/my-apps/Applications" }''}
|
||||
${mkTest "opera" ''cask "opera", greedy: true''}
|
||||
${mkTest "google-cloud-sdk" ''cask "google-cloud-sdk", postinstall: "''${HOMEBREW_PREFIX}/bin/gcloud components update"''}
|
||||
|
||||
echo "checking mas entries in Brewfile" >&2
|
||||
${mkTest "1Password for Safari" ''mas "1Password for Safari", id: 1569813296''}
|
||||
${mkTest "Xcode" ''mas "Xcode", id: 497799835''}
|
||||
|
||||
echo "checking whalebrew entries in Brewfile" >&2
|
||||
${mkTest "whalebrew/wget" ''whalebrew "whalebrew/wget"''}
|
||||
echo "checking vscode entries in Brewfile" >&2
|
||||
${mkTest "golang.go" ''vscode "golang.go"''}
|
||||
|
||||
echo "checking go entries in Brewfile" >&2
|
||||
${mkTest "github.com/charmbracelet/crush" ''go "github.com/charmbracelet/crush"''}
|
||||
|
||||
echo "checking cargo entries in Brewfile" >&2
|
||||
${mkTest "ripgrep" ''cargo "ripgrep"''}
|
||||
|
||||
echo "checking that shell integration is absent by default" >&2
|
||||
(! 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)
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
{
|
||||
networking.knownNetworkServices = [ "Wi-Fi" "Thunderbolt Ethernet" ];
|
||||
networking.dns = [ "8.8.8.8" "8.8.4.4" ];
|
||||
|
||||
test = ''
|
||||
echo checking dhcp client ID is not configured in /activate >&2
|
||||
if grep -q "networksetup -setdhcp" ${config.out}/activate; then
|
||||
echo "unexpected dhcp client ID configuration in /activate" >&2
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
}
|
||||
@@ -3,11 +3,14 @@
|
||||
{
|
||||
networking.knownNetworkServices = [ "Wi-Fi" "Thunderbolt Ethernet" ];
|
||||
networking.dns = [ "8.8.8.8" "8.8.4.4" ];
|
||||
networking.dhcpClientId = "test-client-id";
|
||||
|
||||
test = ''
|
||||
echo checking dns settings in /activate >&2
|
||||
grep "networksetup -setdnsservers ${lib.escapeShellArgs [ "Wi-Fi" "8.8.8.8" "8.8.4.4" ]}" ${config.out}/activate
|
||||
grep "networksetup -setdnsservers ${lib.escapeShellArgs [ "Thunderbolt Ethernet" "8.8.8.8" "8.8.4.4" ]}" ${config.out}/activate
|
||||
grep "networksetup -setdhcp ${lib.escapeShellArgs [ "Wi-Fi" "test-client-id" ]}" ${config.out}/activate
|
||||
grep "networksetup -setdhcp ${lib.escapeShellArgs [ "Thunderbolt Ethernet" "test-client-id" ]}" ${config.out}/activate
|
||||
echo checking empty searchdomain settings in /activate >&2
|
||||
grep "networksetup -setsearchdomains ${lib.escapeShellArgs [ "Wi-Fi" "empty" ]}" ${config.out}/activate
|
||||
grep "networksetup -setsearchdomains ${lib.escapeShellArgs [ "Thunderbolt Ethernet" "empty" ]}" ${config.out}/activate
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# Check that nixpkgs.config.allowUnfreePackages is merged correctly
|
||||
# run with: nix-build release.nix -A tests.nixpkgs-config-allow-unfree
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
# Module 1: Define some unfree packages
|
||||
nixpkgs.config.allowUnfreePackages = [
|
||||
"vscode"
|
||||
"slack"
|
||||
];
|
||||
|
||||
# Module 2: Define more unfree packages (simulating multiple modules)
|
||||
# In a real scenario, this would be in a separate file
|
||||
imports = [
|
||||
(
|
||||
{ config, ... }:
|
||||
{
|
||||
nixpkgs.config.allowUnfreePackages = [
|
||||
"zoom"
|
||||
"discord"
|
||||
];
|
||||
}
|
||||
)
|
||||
];
|
||||
|
||||
test = ''
|
||||
echo checking allowUnfreePackages merging >&2
|
||||
|
||||
# Verify that all packages from both modules are present
|
||||
expected_packages=("discord" "slack" "vscode" "zoom")
|
||||
actual_packages=(${builtins.toString (builtins.sort builtins.lessThan config.nixpkgs.config.allowUnfreePackages)})
|
||||
|
||||
for pkg in "''${expected_packages[@]}"; do
|
||||
if [[ ! " ''${actual_packages[@]} " =~ " $pkg " ]]; then
|
||||
echo "ERROR: Expected package '$pkg' not found in allowUnfreePackages" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
devenv =
|
||||
pkgs.runCommand "devenv-0.0.0" { } ''
|
||||
mkdir -p $out/bin
|
||||
cat > $out/bin/devenv <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x $out/bin/devenv
|
||||
''
|
||||
// {
|
||||
meta.mainProgram = "devenv";
|
||||
};
|
||||
in
|
||||
{
|
||||
programs.bash.enable = true;
|
||||
programs.zsh.enable = true;
|
||||
programs.fish.enable = true;
|
||||
|
||||
programs.devenv = {
|
||||
enable = true;
|
||||
package = devenv;
|
||||
};
|
||||
|
||||
test = ''
|
||||
echo >&2 "checking devenv bash integration in /etc/bashrc"
|
||||
grep 'devenv hook bash' ${config.out}/etc/bashrc
|
||||
|
||||
echo >&2 "checking devenv zsh integration in /etc/zshrc"
|
||||
grep 'devenv hook zsh' ${config.out}/etc/zshrc
|
||||
|
||||
echo >&2 "checking devenv fish integration in /etc/fish/config.fish"
|
||||
grep 'devenv hook fish' ${config.out}/etc/fish/config.fish
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
gnupg = pkgs.runCommand "gnupg-0.0.0" { } "mkdir -p $out/bin";
|
||||
in
|
||||
|
||||
{
|
||||
system.primaryUser = "test-gnupg-user";
|
||||
|
||||
programs.gnupg.package = gnupg;
|
||||
programs.gnupg.agent.enable = true;
|
||||
programs.gnupg.agent.enableSSHSupport = true;
|
||||
|
||||
test = ''
|
||||
echo >&2 "checking gnupg-agent service in ~/Library/LaunchAgents"
|
||||
grep "org.nixos.gnupg-agent" ${config.out}/user/Library/LaunchAgents/org.nixos.gnupg-agent.plist
|
||||
grep "${gnupg}/bin/gpg-connect-agent" ${config.out}/user/Library/LaunchAgents/org.nixos.gnupg-agent.plist
|
||||
|
||||
echo >&2 "checking GPG_TTY in set-environment"
|
||||
grep 'export GPG_TTY=\$(tty)' ${config.system.build.setEnvironment}
|
||||
|
||||
echo >&2 "checking SSH support in set-environment"
|
||||
grep "${gnupg}/bin/gpg-connect-agent --quiet updatestartuptty /bye" ${config.system.build.setEnvironment}
|
||||
grep "${gnupg}/bin/gpgconf --list-dirs agent-ssh-socket" ${config.system.build.setEnvironment}
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
mas =
|
||||
pkgs.runCommand "mas-0.0.0" { } ''
|
||||
mkdir -p $out/bin
|
||||
cat > $out/bin/mas <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x $out/bin/mas
|
||||
''
|
||||
// {
|
||||
meta.mainProgram = "mas";
|
||||
};
|
||||
in
|
||||
{
|
||||
system.primaryUser = "primary-mas-user";
|
||||
|
||||
programs.mas = {
|
||||
enable = true;
|
||||
user = "test-mas-user";
|
||||
package = mas;
|
||||
update = true;
|
||||
cleanup = false;
|
||||
packages = {
|
||||
Xcode = 497799835;
|
||||
};
|
||||
};
|
||||
|
||||
homebrew.masApps = {
|
||||
"KeepFromHomebrew" = 424242;
|
||||
};
|
||||
|
||||
test = ''
|
||||
echo "checking mas present in systemPackages" >&2
|
||||
test -x ${config.out}/sw/bin/mas
|
||||
|
||||
echo "checking mas activation script still installs and updates apps" >&2
|
||||
grep 'desiredIds=(' ${config.out}/activate
|
||||
grep '497799835' ${config.out}/activate
|
||||
grep 'mas install \"$appId\"' ${config.out}/activate
|
||||
grep 'mas update' ${config.out}/activate
|
||||
|
||||
echo "checking cleanup-only variables are omitted" >&2
|
||||
if grep 'declare -A installedApps' ${config.out}/activate; then
|
||||
echo "unexpected installedApps declaration when cleanup is disabled" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep 'keepIds=(' ${config.out}/activate; then
|
||||
echo "unexpected keepIds declaration when cleanup is disabled" >&2
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
mas =
|
||||
pkgs.runCommand "mas-0.0.0" { } ''
|
||||
mkdir -p $out/bin
|
||||
cat > $out/bin/mas <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x $out/bin/mas
|
||||
''
|
||||
// {
|
||||
meta.mainProgram = "mas";
|
||||
};
|
||||
in
|
||||
{
|
||||
system.primaryUser = "primary-mas-user";
|
||||
|
||||
programs.mas = {
|
||||
enable = true;
|
||||
user = "test-mas-user";
|
||||
package = mas;
|
||||
update = true;
|
||||
cleanup = true;
|
||||
packages = {
|
||||
"1Password for Safari" = 1569813296;
|
||||
Xcode = 497799835;
|
||||
};
|
||||
};
|
||||
|
||||
homebrew.masApps = {
|
||||
"KeepFromHomebrew" = 424242;
|
||||
};
|
||||
|
||||
test = ''
|
||||
echo "checking mas present in systemPackages" >&2
|
||||
test -x ${config.out}/sw/bin/mas
|
||||
|
||||
echo "checking mas activation script uses requested user" >&2
|
||||
grep -- '--user=test-mas-user' ${config.out}/activate
|
||||
|
||||
echo "checking mas desired ids are present" >&2
|
||||
grep 'desiredIds=(' ${config.out}/activate
|
||||
grep '1569813296' ${config.out}/activate
|
||||
grep '497799835' ${config.out}/activate
|
||||
|
||||
echo "checking mas install loop exists" >&2
|
||||
grep 'mas install \"$appId\"' ${config.out}/activate
|
||||
|
||||
echo "checking mas update is triggered" >&2
|
||||
grep 'mas update' ${config.out}/activate
|
||||
|
||||
echo "checking mas parses installedApps from mas list" >&2
|
||||
grep 'declare -A installedApps' ${config.out}/activate
|
||||
grep 'installedApps\[' ${config.out}/activate
|
||||
|
||||
echo "checking mas cleanup log and uninstall" >&2
|
||||
grep 'removing .* from App Store' ${config.out}/activate
|
||||
grep 'runAsUser .*/mas uninstall' ${config.out}/activate
|
||||
|
||||
echo "checking homebrew.masApps ids are kept during cleanup" >&2
|
||||
grep 'homebrewIds=(' ${config.out}/activate
|
||||
grep '424242' ${config.out}/activate
|
||||
'';
|
||||
}
|
||||
@@ -1,12 +1,37 @@
|
||||
{ config, pkgs, ... }:
|
||||
{ config, ... }:
|
||||
|
||||
{
|
||||
services.openssh.enable = true;
|
||||
services.openssh.extraConfig = ''
|
||||
StreamLocalBindUnlink yes
|
||||
'';
|
||||
services.openssh.hostKeys = [
|
||||
{ type = "ed25519"; path = "/etc/ssh/custom_host_ed25519_key"; comment = "my-host"; }
|
||||
{ type = "rsa"; path = "/etc/ssh/custom_host_rsa_key"; bits = 4096; }
|
||||
];
|
||||
|
||||
test = ''
|
||||
echo >&2 "checking for StreamLocalBindUnlink in /etc/ssh/ssh_known_hosts"
|
||||
echo >&2 "checking for StreamLocalBindUnlink in /etc/ssh/sshd_config.d/100-nix-darwin.conf"
|
||||
grep 'StreamLocalBindUnlink yes' ${config.out}/etc/ssh/sshd_config.d/100-nix-darwin.conf
|
||||
|
||||
echo >&2 "checking for HostKey directives in /etc/ssh/sshd_config.d/099-host-keys.conf"
|
||||
grep 'HostKey /etc/ssh/custom_host_ed25519_key' ${config.out}/etc/ssh/sshd_config.d/099-host-keys.conf
|
||||
grep 'HostKey /etc/ssh/custom_host_rsa_key' ${config.out}/etc/ssh/sshd_config.d/099-host-keys.conf
|
||||
|
||||
echo >&2 "checking that default keys are absent from config"
|
||||
(! grep 'HostKey /etc/ssh/ssh_host_rsa_key' ${config.out}/etc/ssh/sshd_config.d/099-host-keys.conf)
|
||||
(! grep 'HostKey /etc/ssh/ssh_host_ecdsa_key' ${config.out}/etc/ssh/sshd_config.d/099-host-keys.conf)
|
||||
(! grep 'HostKey /etc/ssh/ssh_host_ed25519_key' ${config.out}/etc/ssh/sshd_config.d/099-host-keys.conf)
|
||||
|
||||
echo >&2 "checking for ssh-keygen commands in activation script"
|
||||
grep 'ssh-keygen.*keygenArgs' ${config.out}/activate
|
||||
|
||||
echo >&2 "checking for keygenArgs in activation script"
|
||||
grep '\-t ed25519' ${config.out}/activate
|
||||
grep '\-C my-host' ${config.out}/activate
|
||||
grep '\-f /etc/ssh/custom_host_ed25519_key' ${config.out}/activate
|
||||
grep '\-t rsa' ${config.out}/activate
|
||||
grep '\-b 4096' ${config.out}/activate
|
||||
grep '\-f /etc/ssh/custom_host_rsa_key' ${config.out}/activate
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
system.defaults.screencapture.location = "/tmp";
|
||||
system.defaults.screencapture.target = "file";
|
||||
system.defaults.screencapture.include-date = true;
|
||||
system.defaults.screencapture.save-selections = true;
|
||||
system.defaults.screensaver.askForPassword = true;
|
||||
system.defaults.screensaver.askForPasswordDelay = 5;
|
||||
system.defaults.smb.NetBIOSName = "IMAC-000000";
|
||||
|
||||
@@ -5,20 +5,28 @@
|
||||
system.keyboard.remapCapsLockToControl = true;
|
||||
system.keyboard.remapCapsLockToEscape = true;
|
||||
system.keyboard.nonUS.remapTilde = true;
|
||||
system.keyboard.swapCapsLockAndEscape = true;
|
||||
system.keyboard.swapLeftCommandAndLeftAlt = true;
|
||||
system.keyboard.swapRightCommandAndRightOption = true;
|
||||
system.keyboard.swapLeftCtrlAndFn = true;
|
||||
|
||||
test = ''
|
||||
echo checking keyboard mappings in /activate >&2
|
||||
grep "hidutil property --set '{\"UserKeyMapping\":.*}'" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingSrc\":30064771129" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingSrc\":30064771113" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingSrc\":30064771172" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingDst\":30064771113" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingDst\":30064771125" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingDst\":30064771129" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingDst\":30064771296" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingDst\":30064771298" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingDst\":30064771299" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingDst\":30064771296" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingSrc\":30064771303" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingSrc\":30064771302" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingDst\":30064771302" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingDst\":30064771303" ${config.out}/activate
|
||||
grep "\"HIDKeyboardModifierMappingDst\":1095216660483" ${config.out}/activate
|
||||
'';
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"release": "25.11",
|
||||
"release": "26.11",
|
||||
"isReleaseBranch": false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user