1
0
Fork 0
mirror of https://github.com/LnL7/nix-darwin.git synced 2025-03-16 05:18:17 +00:00

Merge branch 'LnL7:master' into keyboard-shortcuts-update

This commit is contained in:
Jun Matsushita 2024-11-24 11:53:53 +01:00 committed by GitHub
commit 07543d1519
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
71 changed files with 1869 additions and 1119 deletions

View file

@ -1,18 +0,0 @@
name: "Build"
on:
# curl -fsSL -XPOST \
# -H "Accept: application/vnd.github.everest-preview+json" \
# -H "Authorization: token $GITHUB_TOKEN" \
# --data '{"event_type": "build", "client_payload": {"args": "-f channel:nixpkgs-unstable hello"}}' \
# https://api.github.com/repos/LnL7/nix-darwin/dispatches
repository_dispatch:
types:
- build
jobs:
build:
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v22
- run: |
nix build ${{ github.event.client_payload.args }} -vL

View file

@ -1,23 +0,0 @@
name: "Debug"
on:
# curl -fsSL -XPOST \
# -H "Accept: application/vnd.github.everest-preview+json" \
# -H "Authorization: token $GITHUB_TOKEN" \
# --data '{"event_type": "debug"}' \
# https://api.github.com/repos/LnL7/nix-darwin/dispatches
repository_dispatch:
types:
- debug
jobs:
debug:
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v22
- run: |
nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs
nix-channel --update
- run: |
nix-shell -A installer
nix-shell -A installer.check
- uses: mxschmitt/action-tmate@v3

View file

@ -2,144 +2,144 @@ name: "Test"
on: on:
pull_request: pull_request:
push: push:
branches:
- master
env: env:
CURRENT_STABLE_CHANNEL: nixpkgs-24.05-darwin CURRENT_STABLE_CHANNEL: nixpkgs-24.05-darwin
jobs: jobs:
test-stable: test-stable:
runs-on: macos-12 runs-on: macos-13
timeout-minutes: 30
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
# We use the Determinate Systems installer for 2.18 because the
# Sequoia UID/GID changes have not yet been backported to the
# official installer for that version.
- name: Install nix corresponding to latest stable channel - name: Install nix corresponding to latest stable channel
uses: DeterminateSystems/nix-installer-action@main uses: cachix/install-nix-action@v30
with: with:
nix-package-url: https://releases.nixos.org/nix/nix-2.18.5/nix-2.18.5-x86_64-darwin.tar.xz install_url: https://releases.nixos.org/nix/nix-2.18.8/install
- run: nix-build ./release.nix -I nixpkgs=channel:${{ env.CURRENT_STABLE_CHANNEL }} -I darwin=. -A tests - run: nix flake check --override-input nixpkgs nixpkgs/${{ env.CURRENT_STABLE_CHANNEL }}
- run: nix-build ./release.nix -I nixpkgs=channel:${{ env.CURRENT_STABLE_CHANNEL }} -I darwin=. -A manpages
- run: nix-build ./release.nix -I nixpkgs=channel:${{ env.CURRENT_STABLE_CHANNEL }} -I darwin=. -A examples.simple
test-unstable: test-unstable:
runs-on: macos-12 runs-on: macos-13
timeout-minutes: 30
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Install nix from current unstable channel - name: Install nix from current unstable channel
uses: cachix/install-nix-action@v27 uses: cachix/install-nix-action@v30
with: with:
install_url: https://releases.nixos.org/nix/nix-2.24.6/install install_url: https://releases.nixos.org/nix/nix-2.24.9/install
- run: nix-build ./release.nix -I nixpkgs=channel:nixpkgs-unstable -I darwin=. -A tests - run: nix flake check --override-input nixpkgs nixpkgs/nixpkgs-unstable
- run: nix-build ./release.nix -I nixpkgs=channel:nixpkgs-unstable -I darwin=. -A manpages
- run: nix-build ./release.nix -I nixpkgs=channel:nixpkgs-unstable -I darwin=. -A examples.simple
install-against-stable: install-against-stable:
runs-on: macos-12 runs-on: macos-13
timeout-minutes: 30
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
# We use the Determinate Systems installer for 2.18 because the
# Sequoia UID/GID changes have not yet been backported to the
# official installer for that version.
- name: Install nix corresponding to latest stable channel - name: Install nix corresponding to latest stable channel
uses: DeterminateSystems/nix-installer-action@main uses: cachix/install-nix-action@v30
with: with:
nix-package-url: https://releases.nixos.org/nix/nix-2.18.5/nix-2.18.5-x86_64-darwin.tar.xz install_url: https://releases.nixos.org/nix/nix-2.18.8/install
- name: Install ${{ env.CURRENT_STABLE_CHANNEL }} channel nix_path: nixpkgs=channel:${{ env.CURRENT_STABLE_CHANNEL }}
- name: Install channels
run: | run: |
nix-channel --add https://github.com/LnL7/nix-darwin/archive/master.tar.gz darwin
nix-channel --add https://nixos.org/channels/${{ env.CURRENT_STABLE_CHANNEL }} nixpkgs nix-channel --add https://nixos.org/channels/${{ env.CURRENT_STABLE_CHANNEL }} nixpkgs
nix-channel --update nix-channel --update
- name: Install nix-darwin and test - name: Install nix-darwin
run: | run: |
export NIX_PATH=nixpkgs=channel:${{ env.CURRENT_STABLE_CHANNEL }} export NIX_PATH=$HOME/.nix-defexpr/channels
# We run nix-darwin twice to test that it can create darwin-configuration correctly for us mkdir -p ~/.config/nix-darwin
# but we expect it to fail setting up /etc/nix/nix.conf cp modules/examples/simple.nix ~/.config/nix-darwin/configuration.nix
nix-shell -A installer || true
nixConfHash=$(shasum -a 256 /etc/nix/nix.conf | cut -d ' ' -f 1) nixConfHash=$(shasum -a 256 /etc/nix/nix.conf | cut -d ' ' -f 1)
/usr/bin/sed -i.bak \ /usr/bin/sed -i.bak \
"s/# nix.package = pkgs.nix;/nix.settings.access-tokens = [ \"github.com=\${{ secrets.GITHUB_TOKEN }}\" ]; environment.etc.\"nix\/nix.conf\".knownSha256Hashes = [ \"$nixConfHash\" ];/" \ "s/# programs.fish.enable = true;/nix.settings.access-tokens = [ \"github.com=\${{ secrets.GITHUB_TOKEN }}\" ]; environment.etc.\"nix\/nix.conf\".knownSha256Hashes = [ \"$nixConfHash\" ];/" \
~/.nixpkgs/darwin-configuration.nix ~/.config/nix-darwin/configuration.nix
nix-shell -A installer nix run .#darwin-rebuild \
nix-shell -A installer.check -- switch \
- name: Build and activate default derivation -I darwin-config=$HOME/.config/nix-darwin/configuration.nix
- name: Switch to new configuration
run: | run: |
. /etc/static/bashrc . /etc/bashrc
/usr/bin/sed -i.bak \
"s/pkgs.vim/pkgs.hello/" \
~/.config/nix-darwin/configuration.nix
darwin-rebuild switch -I darwin=. darwin-rebuild switch -I darwin=.
hello
- name: Test uninstallation of nix-darwin - name: Test uninstallation of nix-darwin
run: | run: |
export NIX_PATH=$HOME/.nix-defexpr/channels # We need to specify `--extra-experimental-features` because `experimental-features` is set by
nix-shell -A uninstaller # `cachix/install-nix-action` but not by our default config above
nix-shell -A uninstaller.check nix run .#darwin-uninstaller \
- name: Debugging tmate session --extra-experimental-features "nix-command flakes" \
if: ${{ failure() }} --override-input nixpkgs nixpkgs/${{ env.CURRENT_STABLE_CHANNEL }}
uses: mxschmitt/action-tmate@v3 nix run .#darwin-uninstaller.tests.uninstaller \
timeout-minutes: 15 --extra-experimental-features "nix-command flakes" \
with: --override-input nixpkgs nixpkgs/${{ env.CURRENT_STABLE_CHANNEL }}
limit-access-to-actor: true
install-against-unstable: install-against-unstable:
runs-on: macos-12 runs-on: macos-13
timeout-minutes: 30 timeout-minutes: 30
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Install nix from current unstable channel - name: Install nix from current unstable channel
uses: cachix/install-nix-action@v27 uses: cachix/install-nix-action@v30
with: with:
install_url: https://releases.nixos.org/nix/nix-2.24.6/install install_url: https://releases.nixos.org/nix/nix-2.24.9/install
nix_path: nixpkgs=channel:nixpkgs-unstable nix_path: nixpkgs=channel:nixpkgs-unstable
- name: Install nixpkgs-unstable channel - name: Install channels
run: | run: |
nix-channel --add https://github.com/LnL7/nix-darwin/archive/master.tar.gz darwin
nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs
nix-channel --update nix-channel --update
- name: Install nix-darwin and test - name: Install nix-darwin
run: | run: |
export NIX_PATH=$HOME/.nix-defexpr/channels export NIX_PATH=$HOME/.nix-defexpr/channels
# We run nix-darwin twice to test that it can create darwin-configuration correctly for us mkdir -p ~/.config/nix-darwin
# but we expect it to fail setting up /etc/nix/nix.conf cp modules/examples/simple.nix ~/.config/nix-darwin/configuration.nix
nix-shell -A installer || true
nixConfHash=$(shasum -a 256 /etc/nix/nix.conf | cut -d ' ' -f 1) nixConfHash=$(shasum -a 256 /etc/nix/nix.conf | cut -d ' ' -f 1)
/usr/bin/sed -i.bak \ /usr/bin/sed -i.bak \
"s/# nix.package = pkgs.nix;/nix.settings.access-tokens = [ \"github.com=\${{ secrets.GITHUB_TOKEN }}\" ]; environment.etc.\"nix\/nix.conf\".knownSha256Hashes = [ \"$nixConfHash\" ];/" \ "s/# programs.fish.enable = true;/nix.settings.access-tokens = [ \"github.com=\${{ secrets.GITHUB_TOKEN }}\" ]; environment.etc.\"nix\/nix.conf\".knownSha256Hashes = [ \"$nixConfHash\" ];/" \
~/.nixpkgs/darwin-configuration.nix ~/.config/nix-darwin/configuration.nix
nix-shell -A installer nix run .#darwin-rebuild \
nix-shell -A installer.check -- switch \
- name: Build and activate default derivation -I darwin-config=$HOME/.config/nix-darwin/configuration.nix
- name: Switch to new configuration
run: | run: |
. /etc/static/bashrc . /etc/bashrc
/usr/bin/sed -i.bak \
"s/pkgs.vim/pkgs.hello/" \
~/.config/nix-darwin/configuration.nix
darwin-rebuild switch -I darwin=. darwin-rebuild switch -I darwin=.
hello
- name: Test uninstallation of nix-darwin - name: Test uninstallation of nix-darwin
run: | run: |
export NIX_PATH=$HOME/.nix-defexpr/channels # We need to specify `--extra-experimental-features` because `experimental-features` is set by
nix-shell -A uninstaller # `cachix/install-nix-action` but not by our default config above
nix-shell -A uninstaller.check nix run .#darwin-uninstaller \
- name: Debugging tmate session --extra-experimental-features "nix-command flakes" \
if: ${{ failure() }} --override-input nixpkgs nixpkgs/nixpkgs-unstable
uses: mxschmitt/action-tmate@v3 nix run .#darwin-uninstaller.tests.uninstaller \
timeout-minutes: 15 --extra-experimental-features "nix-command flakes" \
with: --override-input nixpkgs nixpkgs/nixpkgs-unstable
limit-access-to-actor: true
install-flake-against-stable: install-flake-against-stable:
runs-on: macos-12 runs-on: macos-13
timeout-minutes: 30
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
# We use the Determinate Systems installer for 2.18 because the - name: Install nix version corresponding to latest stable channel
# Sequoia UID/GID changes have not yet been backported to the uses: cachix/install-nix-action@v30
# official installer for that version.
- name: Install nix corresponding to latest stable channel
uses: DeterminateSystems/nix-installer-action@main
with: with:
nix-package-url: https://releases.nixos.org/nix/nix-2.18.5/nix-2.18.5-x86_64-darwin.tar.xz install_url: https://releases.nixos.org/nix/nix-2.18.8/install
- name: Install nix-darwin - name: Install nix-darwin
run: | run: |
mkdir -p ~/.config/nix-darwin mkdir -p ~/.config/nix-darwin
@ -148,81 +148,43 @@ jobs:
nix flake init -t $darwin nix flake init -t $darwin
nixConfHash=$(shasum -a 256 /etc/nix/nix.conf | cut -d ' ' -f 1) nixConfHash=$(shasum -a 256 /etc/nix/nix.conf | cut -d ' ' -f 1)
/usr/bin/sed -i.bak \ /usr/bin/sed -i.bak \
"s/# nix.package = pkgs.nix;/nix.settings.access-tokens = [ \"github.com=\${{ secrets.GITHUB_TOKEN }}\" ]; environment.etc.\"nix\/nix.conf\".knownSha256Hashes = [ \"$nixConfHash\" ];/" \ "s/# programs.fish.enable = true;/nix.settings.access-tokens = [ \"github.com=\${{ secrets.GITHUB_TOKEN }}\" ]; environment.etc.\"nix\/nix.conf\".knownSha256Hashes = [ \"$nixConfHash\" ];/" \
flake.nix
/usr/bin/sed -i.bak \
's/nixpkgs.hostPlatform = "aarch64-darwin";/nixpkgs.hostPlatform = "'$(nix eval --expr builtins.currentSystem --impure --raw)'";/' \
flake.nix flake.nix
popd popd
nix run .#darwin-rebuild -- \ nix run .#darwin-rebuild -- \
switch --flake ~/.config/nix-darwin#simple \ switch --flake ~/.config/nix-darwin#simple \
--override-input nix-darwin . \ --override-input nix-darwin . \
--override-input nixpkgs nixpkgs/${{ env.CURRENT_STABLE_CHANNEL }} --override-input nixpkgs nixpkgs/${{ env.CURRENT_STABLE_CHANNEL }}
- name: Rebuild and activate simple flake, but this time using nix-darwin's flake interface - name: Switch to new configuration
run: | run: |
. /etc/static/bashrc . /etc/bashrc
darwin-rebuild build --flake ./modules/examples/flake#simple --override-input nix-darwin . --override-input nixpkgs nixpkgs/${{ env.CURRENT_STABLE_CHANNEL }}
- name: Test git submodules /usr/bin/sed -i.bak \
"s/pkgs.vim/pkgs.hello/" \
~/.config/nix-darwin/flake.nix
darwin-rebuild switch --flake ~/.config/nix-darwin#simple \
--override-input nix-darwin . \
--override-input nixpkgs nixpkgs/${{ env.CURRENT_STABLE_CHANNEL }}
hello
- name: Test uninstallation of nix-darwin
run: | run: |
. /etc/static/bashrc nix run .#darwin-uninstaller --override-input nixpkgs nixpkgs/${{ env.CURRENT_STABLE_CHANNEL }}
nix run .#darwin-uninstaller.tests.uninstaller --override-input nixpkgs nixpkgs/${{ env.CURRENT_STABLE_CHANNEL }}
mkdir -p /tmp/{test-nix-darwin-submodules,example-submodule}
pushd /tmp/example-submodule
echo '"hello"' > hello.nix
git init
git add .
git commit -m "add a submodule we will import"
popd
cp -a ./modules/examples/. /tmp/test-nix-darwin-submodules
cp -a ./modules/examples/flake/flake.nix /tmp/test-nix-darwin-submodules
pushd /tmp/test-nix-darwin-submodules
/usr/bin/sed -i.bak \
'\#modules = \[#s#configuration#configuration ./simple.nix#' \
./flake.nix
/usr/bin/sed -i.bak \
's#pkgs.vim#pkgs."${import ./submodule-test/hello.nix}"#' \
./simple.nix
git init
git add flake.nix simple.nix
git \
-c protocol.file.allow=always \
submodule add /tmp/example-submodule submodule-test
popd
# Should fail
darwin-rebuild build \
--flake /tmp/test-nix-darwin-submodules#simple \
--override-input nix-darwin . \
--override-input nixpkgs nixpkgs/${{ env.CURRENT_STABLE_CHANNEL }} \
&& {
printf 'succeeded while expecting failure due to submodule\n' >/dev/stderr
exit 1
}
# Should also fail
darwin-rebuild build \
--flake /tmp/test-nix-darwin-submodules?submodules=0#simple \
--override-input nix-darwin . \
--override-input nixpkgs nixpkgs/${{ env.CURRENT_STABLE_CHANNEL }} \
&& {
printf 'succeeded while expecting failure due to submodule\n' >/dev/stderr
exit 1
}
# Should succeed
darwin-rebuild build \
--flake /tmp/test-nix-darwin-submodules?submodules=1#simple \
--override-input nix-darwin . \
--override-input nixpkgs nixpkgs/${{ env.CURRENT_STABLE_CHANNEL }} \
install-flake-against-unstable: install-flake-against-unstable:
runs-on: macos-12 runs-on: macos-13
timeout-minutes: 30 timeout-minutes: 30
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Install nix from current unstable channel - name: Install nix from current unstable channel
uses: cachix/install-nix-action@v27 uses: cachix/install-nix-action@v30
with: with:
install_url: https://releases.nixos.org/nix/nix-2.24.6/install install_url: https://releases.nixos.org/nix/nix-2.24.9/install
- name: Install nix-darwin - name: Install nix-darwin
run: | run: |
mkdir -p ~/.config/nix-darwin mkdir -p ~/.config/nix-darwin
@ -231,75 +193,30 @@ jobs:
nix flake init -t $darwin nix flake init -t $darwin
nixConfHash=$(shasum -a 256 /etc/nix/nix.conf | cut -d ' ' -f 1) nixConfHash=$(shasum -a 256 /etc/nix/nix.conf | cut -d ' ' -f 1)
/usr/bin/sed -i.bak \ /usr/bin/sed -i.bak \
"s/# nix.package = pkgs.nix;/nix.settings.access-tokens = [ \"github.com=\${{ secrets.GITHUB_TOKEN }}\" ]; environment.etc.\"nix\/nix.conf\".knownSha256Hashes = [ \"$nixConfHash\" ];/" \ "s/# programs.fish.enable = true;/nix.settings.access-tokens = [ \"github.com=\${{ secrets.GITHUB_TOKEN }}\" ]; environment.etc.\"nix\/nix.conf\".knownSha256Hashes = [ \"$nixConfHash\" ];/" \
flake.nix
/usr/bin/sed -i.bak \
's/nixpkgs.hostPlatform = "aarch64-darwin";/nixpkgs.hostPlatform = "'$(nix eval --expr builtins.currentSystem --impure --raw)'";/' \
flake.nix flake.nix
popd popd
nix run .#darwin-rebuild -- \ nix run .#darwin-rebuild -- \
switch --flake ~/.config/nix-darwin#simple \ switch --flake ~/.config/nix-darwin#simple \
--override-input nix-darwin . \ --override-input nix-darwin . \
--override-input nixpkgs nixpkgs/nixpkgs-unstable --override-input nixpkgs nixpkgs/nixpkgs-unstable
- name: Rebuild and activate simple flake, but this time using nix-darwin's flake interface - name: Switch to new configuration
run: | run: |
. /etc/static/bashrc . /etc/bashrc
darwin-rebuild build --flake ./modules/examples/flake#simple --override-input nix-darwin . --override-input nixpkgs nixpkgs/nixpkgs-unstable
- name: Test git submodules
run: |
. /etc/static/bashrc
mkdir -p /tmp/{test-nix-darwin-submodules,example-submodule} /usr/bin/sed -i.bak \
"s/pkgs.vim/pkgs.hello/" \
~/.config/nix-darwin/flake.nix
pushd /tmp/example-submodule darwin-rebuild switch --flake ~/.config/nix-darwin#simple \
echo '"hello"' > hello.nix
git init
git add .
git commit -m "add a submodule we will import"
popd
cp -a ./modules/examples/. /tmp/test-nix-darwin-submodules
cp -a ./modules/examples/flake/flake.nix /tmp/test-nix-darwin-submodules
pushd /tmp/test-nix-darwin-submodules
/usr/bin/sed -i.bak \
'\#modules = \[#s#configuration#configuration ./simple.nix#' \
./flake.nix
/usr/bin/sed -i.bak \
's#pkgs.vim#pkgs."${import ./submodule-test/hello.nix}"#' \
./simple.nix
git init
git add flake.nix simple.nix
git \
-c protocol.file.allow=always \
submodule add /tmp/example-submodule submodule-test
popd
# Should fail
darwin-rebuild build \
--flake /tmp/test-nix-darwin-submodules#simple \
--override-input nix-darwin . \
--override-input nixpkgs nixpkgs/nixpkgs-unstable \
&& {
printf 'succeeded while expecting failure due to submodule\n' >/dev/stderr
exit 1
}
# Should also fail
darwin-rebuild build \
--flake /tmp/test-nix-darwin-submodules?submodules=0#simple \
--override-input nix-darwin . \
--override-input nixpkgs nixpkgs/nixpkgs-unstable \
&& {
printf 'succeeded while expecting failure due to submodule\n' >/dev/stderr
exit 1
}
# Should succeed
darwin-rebuild build \
--flake /tmp/test-nix-darwin-submodules?submodules=1#simple \
--override-input nix-darwin . \ --override-input nix-darwin . \
--override-input nixpkgs nixpkgs/nixpkgs-unstable --override-input nixpkgs nixpkgs/nixpkgs-unstable
# Should also succeed hello
darwin-rebuild build \ - name: Test uninstallation of nix-darwin
--flake git+file:///tmp/test-nix-darwin-submodules?submodules=1#simple \ run: |
--override-input nix-darwin . \ nix run .#darwin-uninstaller --override-input nixpkgs nixpkgs/nixpkgs-unstable
--override-input nixpkgs nixpkgs/nixpkgs-unstable nix run .#darwin-uninstaller.tests.uninstaller --override-input nixpkgs nixpkgs/nixpkgs-unstable

View file

@ -3,25 +3,23 @@ on:
push: push:
branches: branches:
- master - master
paths:
- '**.nix'
jobs: jobs:
update-manual: update-manual:
runs-on: macos-12 runs-on: macos-13
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
# So that we fetch all branches, since we need to checkout the `gh-pages` branch later. # So that we fetch all branches, since we need to checkout the `gh-pages` branch later.
fetch-depth: 0 fetch-depth: 0
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v27 uses: cachix/install-nix-action@v30
- name: Build manual - name: Build manual
run: | run: |
nix-build ./release.nix -I nixpkgs=channel:nixpkgs-24.05-darwin -I darwin=. -A manualHTML nix build .#manualHTML
- name: Push update to manual - name: Push update to manual
run: | run: |

143
README.md
View file

@ -2,80 +2,30 @@
# nix-darwin # nix-darwin
![Test](https://github.com/LnL7/nix-darwin/workflows/Test/badge.svg) [![Test](https://github.com/LnL7/nix-darwin/actions/workflows/test.yml/badge.svg)](https://github.com/LnL7/nix-darwin/actions/workflows/test.yml)
Nix modules for darwin, `/etc/nixos/configuration.nix` for macOS. Nix modules for darwin, `/etc/nixos/configuration.nix` for macOS.
This project aims to bring the convenience of a declarative system approach to macOS. This project aims to bring the convenience of a declarative system approach to macOS.
nix-darwin is built up around [Nixpkgs](https://github.com/NixOS/nixpkgs), quite similar to [NixOS](https://nixos.org/). nix-darwin is built up around [Nixpkgs](https://github.com/NixOS/nixpkgs), quite similar to [NixOS](https://nixos.org/).
## Installing ## Prerequisites
To install nix-darwin, a working installation of [Nix](https://github.com/NixOS/nix#installation) is required. The only prerequisite is a Nix implementation, both Nix and Lix are supported.
If you wish to use nix-darwin with flakes, please refer to the [flakes](#flakes) section. 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:
```bash - 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. **Make sure you use it without the `--determinate` flag**. The `--determinate` flag installs the Determinate Nix distribution which does not work out of the box with nix-darwin.
nix-build https://github.com/LnL7/nix-darwin/archive/master.tar.gz -A installer * The [Lix installer](https://lix.systems/install/#on-any-other-linuxmacos-system) supports both flake-based and channel-based setups.
./result/bin/darwin-installer
```
> NOTE: the system activation scripts don't overwrite existing etc files, so files like `/etc/bashrc` and `/etc/zshrc` won't be
> updated by default. If you didn't use the installer or skipped some of the options you'll have to take care of this yourself.
> Either modify the existing file to source/import the one from `/etc/static` or remove it. Some examples:
- `mv /etc/bashrc /etc/bashrc.before-nix-darwin`
- `echo 'if test -e /etc/static/bashrc; then . /etc/static/bashrc; fi' | sudo tee -a /etc/bashrc`
## Updating ## Getting started
The installer will configure a channel for this repository. Despite being an experimental feature in Nix currently, nix-darwin recommends that beginners use flakes to manage their nix-darwin configurations.
```bash <details>
nix-channel --update darwin <summary>Flakes (Recommended for beginners)</summary>
darwin-rebuild changelog
```
> NOTE: If you are using Nix as a daemon service the channel for that will be owned by root.
> Use `sudo -i nix-channel --update darwin` instead.
## Uninstalling
To run the latest version of the uninstaller, you can run the following command:
```
nix --extra-experimental-features "nix-command flakes" run nix-darwin#darwin-uninstaller
```
If that command doesn't work for you, you can try the locally installed uninstaller:
```
darwin-uninstaller
```
## Example configuration
Configuration lives in `~/.nixpkgs/darwin-configuration.nix`. Check out
[modules/examples](https://github.com/LnL7/nix-darwin/tree/master/modules/examples) for some example configurations.
```nix
{ pkgs, ... }:
{
# List packages installed in system profile. To search by name, run:
# $ nix-env -qaP | grep wget
environment.systemPackages =
[ pkgs.vim
];
# Auto upgrade nix package and the daemon service.
services.nix-daemon.enable = true;
nix.package = pkgs.nix;
}
```
## Flakes
nix-darwin aims for both non-flake and flake configurations to be well supported despite flakes being an experimental feature in Nix.
### Step 1. Creating `flake.nix` ### Step 1. Creating `flake.nix`
@ -128,7 +78,7 @@ Make sure to set `nixpkgs.hostPlatform` in your `configuration.nix` to either `x
### Step 2. Installing `nix-darwin` ### Step 2. Installing `nix-darwin`
Instead of using `darwin-installer`, you can just run `darwin-rebuild switch` to install nix-darwin. As `darwin-rebuild` won't be installed in your `PATH` yet, you can use the following command: Unlike NixOS, `nix-darwin` does not have an installer, you can just run `darwin-rebuild switch` to install nix-darwin. As `darwin-rebuild` won't be installed in your `PATH` yet, you can use the following command:
```bash ```bash
nix run nix-darwin -- switch --flake ~/.config/nix-darwin nix run nix-darwin -- switch --flake ~/.config/nix-darwin
@ -160,34 +110,67 @@ nix-darwin.lib.darwinSystem {
{ pkgs, lib, inputs }: { pkgs, lib, inputs }:
# inputs.self, inputs.nix-darwin, and inputs.nixpkgs can be accessed here # inputs.self, inputs.nix-darwin, and inputs.nixpkgs can be accessed here
``` ```
</details>
<details>
<summary>Channels</summary>
### Step 1. Creating `configuration.nix`
Copy the [simple](./modules/examples/simple.nix) example to `~/.config/nix-darwin/configuration.nix`.
### Step 2. Adding `nix-darwin` channel
```bash
nix-channel --add https://github.com/LnL7/nix-darwin/archive/master.tar.gz darwin
nix-channel --update
```
### Step 3. Installing `nix-darwin`
To install `nix-darwin`, you can just run `darwin-rebuild switch` to install nix-darwin. As `darwin-rebuild` won't be installed in your `PATH` yet, you can use the following command:
```bash
nix-build https://github.com/LnL7/nix-darwin/archive/master.tar.gz -A darwin-rebuild
./result/bin/darwin-rebuild switch -I darwin-config=$HOME/.config/nix-darwin/configuration.nix
```
### Step 4. Using `nix-darwin`
After installing, you can run `darwin-rebuild` to apply changes to your system:
```bash
darwin-rebuild switch
```
### Step 5. Updating `nix-darwin`
You can update `nix-darwin` using the following command:
```bash
nix-channel --update darwin
```
</details>
## Documentation ## Documentation
Reference documentation of all the options is available [here](https://daiderd.com/nix-darwin/manual/index.html). `darwin-help` will open up a local copy of the reference documentation, it can also be found online [here](https://daiderd.com/nix-darwin/manual/index.html).
This can also be accessed locally using `man 5 configuration.nix`.
`darwin-help` will open a HTML version of the manpage in the default browser. The documentation is also available as manpages by running `man 5 configuration.nix`.
Furthermore there's `darwin-option` to introspect the settings of a system and its available options. ## Uninstalling
> NOTE: `darwin-option` is only available to non-flake installations.
To run the latest version of the uninstaller, you can run the following command:
``` ```
$ darwin-option services.activate-system.enable nix --extra-experimental-features "nix-command flakes" run nix-darwin#darwin-uninstaller
Value:
true
Default:
false
Example:
no example
Description:
Whether to activate system at boot time.
``` ```
There's also a small wiki https://github.com/LnL7/nix-darwin/wiki about If that command doesn't work for you, you can try the locally installed uninstaller:
specific topics, like macOS upgrades.
```
darwin-uninstaller
```
## Tests ## Tests

View file

@ -1,8 +1,8 @@
{ nixpkgs ? <nixpkgs> { nixpkgs ? <nixpkgs>
, configuration ? <darwin-config> , configuration ? <darwin-config>
, lib ? pkgs.lib
, pkgs ? import nixpkgs { inherit system; }
, system ? builtins.currentSystem , system ? builtins.currentSystem
, pkgs ? import nixpkgs { inherit system; }
, lib ? pkgs.lib
}: }:
let let
@ -15,20 +15,9 @@ let
nixpkgs.system = lib.mkDefault system; nixpkgs.system = lib.mkDefault system;
}; };
}; };
# The source code of this repo needed by the installer.
nix-darwin = lib.cleanSource (
lib.cleanSourceWith {
# We explicitly specify a name here otherwise `cleanSource` will use the
# basename of ./. which might be different for different clones of this
# repo leading to non-reproducible outputs.
name = "nix-darwin";
src = ./.;
}
);
in in
eval // { eval // {
installer = pkgs.callPackage ./pkgs/darwin-installer { inherit nix-darwin; }; darwin-uninstaller = pkgs.callPackage ./pkgs/darwin-uninstaller { };
uninstaller = pkgs.callPackage ./pkgs/darwin-uninstaller { };
inherit (pkgs.callPackage ./pkgs/nix-tools { }) darwin-option darwin-rebuild darwin-version;
} }

View file

@ -79,11 +79,17 @@ in rec {
'@DARWIN_OPTIONS_JSON@' \ '@DARWIN_OPTIONS_JSON@' \
${optionsJSON}/share/doc/darwin/options.json ${optionsJSON}/share/doc/darwin/options.json
# Pass --redirects option if nixos-render-docs supports it
if nixos-render-docs manual html --help | grep --silent -E '^\s+--redirects\s'; then
redirects_opt="--redirects ${./redirects.json}"
fi
# TODO: --manpage-urls? # TODO: --manpage-urls?
nixos-render-docs -j $NIX_BUILD_CORES manual html \ nixos-render-docs -j $NIX_BUILD_CORES manual html \
--manpage-urls ${pkgs.writeText "manpage-urls.json" "{}"} \ --manpage-urls ${pkgs.writeText "manpage-urls.json" "{}"} \
--revision ${lib.escapeShellArg revision} \ --revision ${lib.escapeShellArg revision} \
--generator "nixos-render-docs ${lib.version}" \ --generator "nixos-render-docs ${lib.version}" \
$redirects_opt \
--stylesheet style.css \ --stylesheet style.css \
--stylesheet highlightjs/mono-blue.css \ --stylesheet highlightjs/mono-blue.css \
--script ./highlightjs/highlight.pack.js \ --script ./highlightjs/highlight.pack.js \
@ -118,18 +124,18 @@ in rec {
# TODO: get these parameterized in upstream nixos-render-docs # TODO: get these parameterized in upstream nixos-render-docs
sed -i -e ' sed -i -e '
/^\.TH / s|NixOS|Darwin|g /^\.TH / s|NixOS|nix-darwin|g
/^\.SH "NAME"$/ { /^\.SH "NAME"$/ {
N N
s|NixOS|Darwin|g s|NixOS|nix-darwin|g
} }
/^\.SH "DESCRIPTION"$/ { /^\.SH "DESCRIPTION"$/ {
N; N N; N
s|/etc/nixos/configuration|configuration|g s|/etc/nixos/configuration|configuration|g
s|NixOS|Darwin|g s|NixOS|nix-darwin|g
s|nixos|darwin|g s|nixos|nix-darwin|g
} }
/\.SH "AUTHORS"$/ { /\.SH "AUTHORS"$/ {

View file

@ -1,4 +1,4 @@
# Darwin Configuration Options {#book-darwin-manual} # nix-darwin Configuration Options {#book-darwin-manual}
## Version @DARWIN_VERSION@ ## Version @DARWIN_VERSION@
```{=include=} options ```{=include=} options

View file

@ -0,0 +1,5 @@
{
"book-darwin-manual": [
"index.html#book-darwin-manual"
]
}

View file

@ -1,9 +1,15 @@
{ {
# WARNING this is very much still experimental.
description = "A collection of darwin modules"; description = "A collection of darwin modules";
outputs = { self, nixpkgs }: let outputs = { self, nixpkgs }: let
forAllSystems = nixpkgs.lib.genAttrs [ "aarch64-darwin" "x86_64-darwin" ]; forAllSystems = nixpkgs.lib.genAttrs [ "aarch64-darwin" "x86_64-darwin" "aarch64-linux" "x86_64-linux" ];
forDarwinSystems = nixpkgs.lib.genAttrs [ "aarch64-darwin" "x86_64-darwin" ];
jobs = forAllSystems (system: import ./release.nix {
inherit nixpkgs system;
nix-darwin = self;
});
in { in {
lib = { lib = {
evalConfig = import ./eval-config.nix; evalConfig = import ./eval-config.nix;
@ -48,7 +54,6 @@
darwinModules.hydra = ./modules/examples/hydra.nix; darwinModules.hydra = ./modules/examples/hydra.nix;
darwinModules.lnl = ./modules/examples/lnl.nix; darwinModules.lnl = ./modules/examples/lnl.nix;
darwinModules.ofborg = ./modules/examples/ofborg.nix;
darwinModules.simple = ./modules/examples/simple.nix; darwinModules.simple = ./modules/examples/simple.nix;
templates.default = { templates.default = {
@ -56,23 +61,11 @@
description = "nix flake init -t nix-darwin"; description = "nix flake init -t nix-darwin";
}; };
checks = forAllSystems (system: let checks = forDarwinSystems (system: jobs.${system}.tests // jobs.${system}.examples);
simple = self.lib.darwinSystem {
modules = [
self.darwinModules.simple
{ nixpkgs.hostPlatform = system; }
];
};
in {
simple = simple.system;
inherit (simple.config.system.build.manual) packages = forAllSystems (system: {
optionsJSON inherit (jobs.${system}.docs) manualHTML manpages optionsJSON;
manualHTML } // (nixpkgs.lib.optionalAttrs (nixpkgs.lib.hasSuffix "darwin" system) (let
manpages;
});
packages = forAllSystems (system: let
pkgs = import nixpkgs { pkgs = import nixpkgs {
inherit system; inherit system;
overlays = [ self.overlays.default ]; overlays = [ self.overlays.default ];
@ -81,6 +74,6 @@
default = self.packages.${system}.darwin-rebuild; default = self.packages.${system}.darwin-rebuild;
inherit (pkgs) darwin-option darwin-rebuild darwin-version darwin-uninstaller; inherit (pkgs) darwin-option darwin-rebuild darwin-version darwin-uninstaller;
}); })));
}; };
} }

View file

@ -18,6 +18,11 @@ in
{ {
imports = [ imports = [
(mkRenamedOptionModule ["environment" "postBuild"] ["environment" "extraSetup"]) (mkRenamedOptionModule ["environment" "postBuild"] ["environment" "extraSetup"])
(mkRemovedOptionModule [ "environment" "loginShell" ] ''
This option was only used to change the default command in tmux.
This has been removed in favour of changing the default command or default shell in tmux directly.
'')
]; ];
options = { options = {
@ -74,12 +79,6 @@ in
''; '';
}; };
environment.loginShell = mkOption {
type = types.str;
default = "$SHELL -l";
description = "Configure default login shell.";
};
environment.variables = mkOption { environment.variables = mkOption {
type = types.attrsOf (types.either types.str (types.listOf types.str)); type = types.attrsOf (types.either types.str (types.listOf types.str));
default = {}; default = {};
@ -198,6 +197,7 @@ in
name = "system-path"; name = "system-path";
paths = cfg.systemPackages; paths = cfg.systemPackages;
postBuild = cfg.extraSetup; postBuild = cfg.extraSetup;
ignoreCollisions = true;
inherit (cfg) pathsToLink extraOutputsToInstall; inherit (cfg) pathsToLink extraOutputsToInstall;
}; };

View file

@ -1,5 +1,5 @@
{ {
description = "Example Darwin system flake"; description = "Example nix-darwin system flake";
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
@ -16,15 +16,10 @@
[ pkgs.vim [ pkgs.vim
]; ];
# Auto upgrade nix package and the daemon service.
services.nix-daemon.enable = true;
# nix.package = pkgs.nix;
# Necessary for using flakes on this system. # Necessary for using flakes on this system.
nix.settings.experimental-features = "nix-command flakes"; nix.settings.experimental-features = "nix-command flakes";
# Create /etc/zshrc that loads the nix-darwin environment. # Enable alternative shell support in nix-darwin.
programs.zsh.enable = true; # default shell on catalina
# programs.fish.enable = true; # programs.fish.enable = true;
# Set Git commit hash for darwin-version. # Set Git commit hash for darwin-version.
@ -35,7 +30,7 @@
system.stateVersion = 5; system.stateVersion = 5;
# The platform the configuration will be used on. # The platform the configuration will be used on.
nixpkgs.hostPlatform = "x86_64-darwin"; nixpkgs.hostPlatform = "aarch64-darwin";
}; };
in in
{ {
@ -44,8 +39,5 @@
darwinConfigurations."simple" = nix-darwin.lib.darwinSystem { darwinConfigurations."simple" = nix-darwin.lib.darwinSystem {
modules = [ configuration ]; modules = [ configuration ];
}; };
# Expose the package set, including overlays, for convenience.
darwinPackages = self.darwinConfigurations."simple".pkgs;
}; };
} }

View file

@ -1,25 +1,14 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
with lib;
let let
environment = concatStringsSep " " environment = lib.concatStringsSep " "
[ "NIX_REMOTE=daemon" [ "NIX_REMOTE=daemon"
"NIX_SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" "NIX_SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
]; ];
in in
{ {
# Create /etc/bashrc that loads the nix-darwin environment. nix.settings.substituters = [ "http://cache1" ];
programs.bash.enable = true;
programs.bash.enableCompletion = false;
# Recreate /run/current-system symlink after boot.
services.activate-system.enable = true;
services.nix-daemon.enable = true;
nix.settings.substituters = [ http://cache1 ];
nix.settings.trusted-public-keys = [ "cache.daiderd.com-1:R8KOWZ8lDaLojqD+v9dzXAqGn29gEzPTTbr/GIpCTrI=" ]; nix.settings.trusted-public-keys = [ "cache.daiderd.com-1:R8KOWZ8lDaLojqD+v9dzXAqGn29gEzPTTbr/GIpCTrI=" ];
nix.settings.trusted-users = [ "@admin" "@hydra" ]; nix.settings.trusted-users = [ "@admin" "@hydra" ];
@ -31,7 +20,7 @@ in
nix.gc.automatic = true; nix.gc.automatic = true;
nix.gc.options = "--max-freed $((25 * 1024**3 - 1024 * $(df -P -k /nix/store | tail -n 1 | awk '{ print $4 }')))"; nix.gc.options = "--max-freed $((25 * 1024**3 - 1024 * $(df -P -k /nix/store | tail -n 1 | awk '{ print $4 }')))";
environment.etc."per-user/hydra/ssh/authorized_keys".text = concatStringsSep "\n" environment.etc."per-user/hydra/ssh/authorized_keys".text = lib.concatStringsSep "\n"
[ "command=\"${environment} ${config.nix.package}/bin/nix-store --serve --write\" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCVsc0pHGsskoayziMhA2e59bHPWe0bbKgusmqhuJFBGQ1BAk9UmPzKCWE3nCiV6CLD1+SygVkBjb06DYtc+94BnzviCa9qZtL0G4+2vhp6x8OvXh8xlf/eWw3k5MWlvu+kjJFpbW8wHWTiUqzH+uEeHklAosT0lFNjiIYd/Vs3JAezhUR62a6c7ZjWOd5F7ALGEKzOiwC4i37kSgGsIWNCbe0Ku7gyr718zhMGeyxax6saHhnkSpIB+7d6oHhKeiJSFMWctNmz1/qxXUPbxNaJvqgdKlVHhN+B7x/TIbkVr5pTC59Okx9LTcpflFIv79VT+Gf1K7VypZpSvJjG0xFRt8iDs1+ssWFBfvpo94vUbZ+ZwMDcBGR5iJeO41Gj5fYn5aaDl32RXfJ9Fkwael1L6pcXtkIc66jk+KQQpgoeNj8Y3Emntpqva/2AM41wDDvr5tKp5KhEKFLM95CoiWq+g88pZLcpqLK7wooDVqNkVUEbMaj9lBN0AzU9mcsIRGvTa6CmWAdBvwqS2fRZD97Oarqct9AWgb0X6mOUq9BJNi4i4xvjgnVkylLwtLUnibR/PeXMtkb9bv6BEZXNf5ACqxSjKXJyaIHI65I5TILCr5eEgaujgvmkREn6U3T1NZAUIeVe9aVYLqehYh79OHUBzggoHqidRrXBB/6zdg9UgQ==" [ "command=\"${environment} ${config.nix.package}/bin/nix-store --serve --write\" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCVsc0pHGsskoayziMhA2e59bHPWe0bbKgusmqhuJFBGQ1BAk9UmPzKCWE3nCiV6CLD1+SygVkBjb06DYtc+94BnzviCa9qZtL0G4+2vhp6x8OvXh8xlf/eWw3k5MWlvu+kjJFpbW8wHWTiUqzH+uEeHklAosT0lFNjiIYd/Vs3JAezhUR62a6c7ZjWOd5F7ALGEKzOiwC4i37kSgGsIWNCbe0Ku7gyr718zhMGeyxax6saHhnkSpIB+7d6oHhKeiJSFMWctNmz1/qxXUPbxNaJvqgdKlVHhN+B7x/TIbkVr5pTC59Okx9LTcpflFIv79VT+Gf1K7VypZpSvJjG0xFRt8iDs1+ssWFBfvpo94vUbZ+ZwMDcBGR5iJeO41Gj5fYn5aaDl32RXfJ9Fkwael1L6pcXtkIc66jk+KQQpgoeNj8Y3Emntpqva/2AM41wDDvr5tKp5KhEKFLM95CoiWq+g88pZLcpqLK7wooDVqNkVUEbMaj9lBN0AzU9mcsIRGvTa6CmWAdBvwqS2fRZD97Oarqct9AWgb0X6mOUq9BJNi4i4xvjgnVkylLwtLUnibR/PeXMtkb9bv6BEZXNf5ACqxSjKXJyaIHI65I5TILCr5eEgaujgvmkREn6U3T1NZAUIeVe9aVYLqehYh79OHUBzggoHqidRrXBB/6zdg9UgQ=="
"command=\"${environment} ${config.nix.package}/bin/nix-store --serve --write\" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCnubA1pRqlpoAXkZ1q5nwhqi1RY2z840wFLFDj7vAMSups9E2U8PNIVtuVYApZpkBWIpzD4GGbQTF5Itnu5uBpJswc2Yat9yGWO/guuVyXIaRoBIM0Pg1WBWcWsz+k4rNludu9UQ74FHqEiqZIuIuOcgV+RIZn8xQlGt2kUqN9TWboHhZz8Zhx7EtGSJH6MJRLn3mA/pPjOF6k1jiiFG1pVDuqBTZPANkelWYCWAJ46jCyhxXltWE/jkBYGc/XbB8yT7DFE1XC6TVsSEp68R9PhVG3yqxqY06sniEyduSoGt/TDr6ycERd93bvLElXFATes85YiFszeaUgayYSKwQPe0q7YeHMhIXL0UYJYaKVVgT9saFDiHDzde7kKe+NA+J4+TbIk7Y/Ywn0jepsYV13M7TyEqgqbu9fvVGF3JI9+4g0m1gAzHTa7n6iiAedtz+Pi79uCEpRD2hWSSoLWroyPlep8j1p2tygtFsrieePEukesoToCTwqg1Ejnjh+yKdtUbc6xpyRvl3hKeO8QbCpfaaVd27e4vE4lP2JMW6nOo8b0wlVXQIFe5K2zh52q1MSwhLAq6Kg8oPmgj0lru4IivmPc+/NVwd3Qj3E9ZB8LRfTesfbcxHrC8lF5dL/QpLMeLwebrwCxL19gI0kxmDIaUQuHSyP3B2z+EmBKcN/Xw==" "command=\"${environment} ${config.nix.package}/bin/nix-store --serve --write\" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCnubA1pRqlpoAXkZ1q5nwhqi1RY2z840wFLFDj7vAMSups9E2U8PNIVtuVYApZpkBWIpzD4GGbQTF5Itnu5uBpJswc2Yat9yGWO/guuVyXIaRoBIM0Pg1WBWcWsz+k4rNludu9UQ74FHqEiqZIuIuOcgV+RIZn8xQlGt2kUqN9TWboHhZz8Zhx7EtGSJH6MJRLn3mA/pPjOF6k1jiiFG1pVDuqBTZPANkelWYCWAJ46jCyhxXltWE/jkBYGc/XbB8yT7DFE1XC6TVsSEp68R9PhVG3yqxqY06sniEyduSoGt/TDr6ycERd93bvLElXFATes85YiFszeaUgayYSKwQPe0q7YeHMhIXL0UYJYaKVVgT9saFDiHDzde7kKe+NA+J4+TbIk7Y/Ywn0jepsYV13M7TyEqgqbu9fvVGF3JI9+4g0m1gAzHTa7n6iiAedtz+Pi79uCEpRD2hWSSoLWroyPlep8j1p2tygtFsrieePEukesoToCTwqg1Ejnjh+yKdtUbc6xpyRvl3hKeO8QbCpfaaVd27e4vE4lP2JMW6nOo8b0wlVXQIFe5K2zh52q1MSwhLAq6Kg8oPmgj0lru4IivmPc+/NVwd3Qj3E9ZB8LRfTesfbcxHrC8lF5dL/QpLMeLwebrwCxL19gI0kxmDIaUQuHSyP3B2z+EmBKcN/Xw=="
]; ];
@ -53,4 +42,6 @@ in
chown hydra:hydra ~hydra ~hydra/.ssh ~hydra/.ssh/authorized_keys chown hydra:hydra ~hydra ~hydra/.ssh ~hydra/.ssh/authorized_keys
echo "ok" echo "ok"
''; '';
system.stateVersion = 5;
} }

View file

@ -1,10 +1,6 @@
{ config, lib, inputs, pkgs, ... }: { config, lib, inputs, pkgs, ... }:
{ {
# imports = [ ~/.config/nixpkgs/darwin/local-configuration.nix ];
# system.patches = [ ./pam.patch ];
system.defaults.NSGlobalDomain.AppleKeyboardUIMode = 3; system.defaults.NSGlobalDomain.AppleKeyboardUIMode = 3;
system.defaults.NSGlobalDomain.ApplePressAndHoldEnabled = false; system.defaults.NSGlobalDomain.ApplePressAndHoldEnabled = false;
system.defaults.NSGlobalDomain.InitialKeyRepeat = 10; system.defaults.NSGlobalDomain.InitialKeyRepeat = 10;
@ -50,13 +46,10 @@
pkgs.gnupg pkgs.gnupg
pkgs.htop pkgs.htop
pkgs.jq pkgs.jq
pkgs.mosh
pkgs.ripgrep pkgs.ripgrep
pkgs.shellcheck pkgs.shellcheck
pkgs.vault
pkgs.qes pkgs.qes
pkgs.darwin-zsh-completions
]; ];
services.yabai.enable = true; services.yabai.enable = true;
@ -84,7 +77,6 @@
# serviceConfig.ProcessType = "Background"; # serviceConfig.ProcessType = "Background";
# }; # };
services.nix-daemon.enable = true;
# services.nix-daemon.enableSocketListener = true; # services.nix-daemon.enableSocketListener = true;
nix.extraOptions = '' nix.extraOptions = ''
@ -96,7 +88,7 @@
''; '';
nix.settings.trusted-public-keys = [ "cache.daiderd.com-1:R8KOWZ8lDaLojqD+v9dzXAqGn29gEzPTTbr/GIpCTrI=" ]; nix.settings.trusted-public-keys = [ "cache.daiderd.com-1:R8KOWZ8lDaLojqD+v9dzXAqGn29gEzPTTbr/GIpCTrI=" ];
nix.settings.trusted-substituters = [ https://d3i7ezr9vxxsfy.cloudfront.net ]; nix.settings.trusted-substituters = [ "https://d3i7ezr9vxxsfy.cloudfront.net" ];
nix.settings.sandbox = true; nix.settings.sandbox = true;
nix.settings.extra-sandbox-paths = [ "/private/tmp" "/private/var/tmp" "/usr/bin/env" ]; nix.settings.extra-sandbox-paths = [ "/private/tmp" "/private/var/tmp" "/usr/bin/env" ];
@ -199,7 +191,7 @@
# Dotfiles. # Dotfiles.
# programs.vim.package = mkForce pkgs.lnl.vim; # programs.vim.package = mkForce pkgs.lnl.vim;
programs.bash.enableCompletion = true; programs.bash.completion.enable = true;
programs.zsh.enable = true; programs.zsh.enable = true;
programs.zsh.enableBashCompletion = true; programs.zsh.enableBashCompletion = true;
@ -277,7 +269,6 @@
zle -N up-line-or-beginning-search zle -N up-line-or-beginning-search
''; '';
environment.loginShell = "${pkgs.zsh}/bin/zsh -l";
environment.variables.SHELL = "${pkgs.zsh}/bin/zsh"; environment.variables.SHELL = "${pkgs.zsh}/bin/zsh";
environment.variables.LANG = "en_US.UTF-8"; environment.variables.LANG = "en_US.UTF-8";
@ -303,8 +294,6 @@
fi fi
''; '';
# environment.darwinConfig = "$HOME/.config/nixpkgs/darwin/configuration.nix";
nixpkgs.config.allowUnfree = true; nixpkgs.config.allowUnfree = true;
nixpkgs.overlays = [ nixpkgs.overlays = [
@ -332,4 +321,6 @@
nix.configureBuildUsers = true; nix.configureBuildUsers = true;
nix.nrBuildUsers = 32; nix.nrBuildUsers = 32;
system.stateVersion = 5;
} }

View file

@ -1,29 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
{
# Logs are enabled by default.
# $ tail -f /var/log/ofborg.log
services.ofborg.enable = true;
# services.ofborg.configFile = "/var/lib/ofborg/config.json";
# $ nix-channel --add https://github.com/NixOS/ofborg/archive/released.tar.gz ofborg
# $ nix-channel --update
services.ofborg.package = (import <ofborg> {}).ofborg.rs;
# Keep nix-daemon updated.
services.nix-daemon.enable = true;
nix.gc.automatic = true;
nix.gc.options = "--max-freed $((25 * 1024**3 - 1024 * $(df -P -k /nix/store | tail -n 1 | awk '{ print $4 }')))";
# Manage user for ofborg, this enables creating/deleting users
# depending on what modules are enabled.
users.knownGroups = [ "ofborg" ];
users.knownUsers = [ "ofborg" ];
# Used for backwards compatibility, please read the changelog before changing.
# $ darwin-rebuild changelog
system.stateVersion = 5;
}

View file

@ -7,16 +7,10 @@
[ pkgs.vim [ pkgs.vim
]; ];
# Use a custom configuration.nix location. # Use custom location for configuration.nix.
# $ darwin-rebuild switch -I darwin-config=$HOME/.config/nixpkgs/darwin/configuration.nix environment.darwinConfig = "$HOME/.config/nix-darwin/configuration.nix";
# environment.darwinConfig = "$HOME/.config/nixpkgs/darwin/configuration.nix";
# Auto upgrade nix package and the daemon service. # Enable alternative shell support in nix-darwin.
# services.nix-daemon.enable = true;
# nix.package = pkgs.nix;
# Create /etc/zshrc that loads the nix-darwin environment.
programs.zsh.enable = true; # default shell on catalina
# programs.fish.enable = true; # programs.fish.enable = true;
# Used for backwards compatibility, please read the changelog before changing. # Used for backwards compatibility, please read the changelog before changing.

View file

@ -38,10 +38,12 @@ in
ids.uids = { ids.uids = {
nixbld = lib.mkDefault 350; nixbld = lib.mkDefault 350;
_prometheus-node-exporter = 534;
}; };
ids.gids = { ids.gids = {
nixbld = lib.mkDefault (if config.system.stateVersion < 5 then 30000 else 350); nixbld = lib.mkDefault (if config.system.stateVersion < 5 then 30000 else 350);
_prometheus-node-exporter = 534;
}; };
}; };

View file

@ -14,6 +14,7 @@
./system/activation-scripts.nix ./system/activation-scripts.nix
./system/applications.nix ./system/applications.nix
./system/defaults-write.nix ./system/defaults-write.nix
./system/defaults/controlcenter.nix
./system/defaults/LaunchServices.nix ./system/defaults/LaunchServices.nix
./system/defaults/NSGlobalDomain.nix ./system/defaults/NSGlobalDomain.nix
./system/defaults/GlobalPreferences.nix ./system/defaults/GlobalPreferences.nix
@ -21,6 +22,7 @@
./system/defaults/clock.nix ./system/defaults/clock.nix
./system/defaults/dock.nix ./system/defaults/dock.nix
./system/defaults/finder.nix ./system/defaults/finder.nix
./system/defaults/hitoolbox.nix
./system/defaults/screencapture.nix ./system/defaults/screencapture.nix
./system/defaults/screensaver.nix ./system/defaults/screensaver.nix
./system/defaults/alf.nix ./system/defaults/alf.nix
@ -52,7 +54,10 @@
./environment ./environment
./fonts ./fonts
./launchd ./launchd
./power
./power/sleep.nix
./services/activate-system ./services/activate-system
./services/aerospace
./services/autossh.nix ./services/autossh.nix
./services/buildkite-agents.nix ./services/buildkite-agents.nix
./services/chunkwm.nix ./services/chunkwm.nix
@ -72,6 +77,7 @@
./services/mopidy.nix ./services/mopidy.nix
./services/monitoring/telegraf.nix ./services/monitoring/telegraf.nix
./services/monitoring/netdata.nix ./services/monitoring/netdata.nix
./services/monitoring/prometheus-node-exporter.nix
./services/netbird.nix ./services/netbird.nix
./services/nix-daemon.nix ./services/nix-daemon.nix
./services/nix-gc ./services/nix-gc

View file

@ -1,4 +1,4 @@
{ config, lib, pkgs, ... }: { config, lib, ... }:
with lib; with lib;
@ -8,15 +8,16 @@ let
hostnameRegEx = ''^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$''; hostnameRegEx = ''^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$'';
emptyList = lst: if lst != [] then lst else ["empty"]; emptyList = lst: if lst != [] then lst else ["empty"];
quoteStrings = concatMapStringsSep " " (str: "'${str}'");
onOff = cond: if cond then "on" else "off";
setNetworkServices = optionalString (cfg.knownNetworkServices != []) '' setNetworkServices = optionalString (cfg.knownNetworkServices != []) ''
networkservices=$(networksetup -listallnetworkservices) networkservices=$(networksetup -listallnetworkservices)
${concatMapStringsSep "\n" (srv: '' ${concatMapStringsSep "\n" (srv: ''
case "$networkservices" in case "$networkservices" in
*'${srv}'*) *${lib.escapeShellArg srv}*)
networksetup -setdnsservers '${srv}' ${quoteStrings (emptyList cfg.dns)} networksetup -setdnsservers ${lib.escapeShellArgs ([ srv ] ++ (emptyList cfg.dns))}
networksetup -setsearchdomains '${srv}' ${quoteStrings (emptyList cfg.search)} networksetup -setsearchdomains ${lib.escapeShellArgs ([ srv ] ++ (emptyList cfg.search))}
;; ;;
esac esac
'') cfg.knownNetworkServices} '') cfg.knownNetworkServices}
@ -94,6 +95,16 @@ in
default = []; default = [];
description = "The list of search paths used when resolving domain names."; description = "The list of search paths used when resolving domain names.";
}; };
networking.wakeOnLan.enable = mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Enable Wake-on-LAN for the device.
Battery powered devices may require being connected to power.
'';
};
}; };
config = { config = {
@ -107,6 +118,7 @@ in
echo "configuring networking..." >&2 echo "configuring networking..." >&2
${optionalString (cfg.computerName != null) '' ${optionalString (cfg.computerName != null) ''
# shellcheck disable=SC1112
scutil --set ComputerName ${escapeShellArg cfg.computerName} scutil --set ComputerName ${escapeShellArg cfg.computerName}
''} ''}
${optionalString (cfg.hostName != null) '' ${optionalString (cfg.hostName != null) ''
@ -117,6 +129,10 @@ in
''} ''}
${setNetworkServices} ${setNetworkServices}
${optionalString (cfg.wakeOnLan.enable != null) ''
systemsetup -setWakeOnNetworkAccess '${onOff cfg.wakeOnLan.enable}' &> /dev/null
''}
''; '';
}; };

View file

@ -191,9 +191,6 @@ in
description = '' description = ''
Whether to distribute builds to the machines listed in Whether to distribute builds to the machines listed in
{option}`nix.buildMachines`. {option}`nix.buildMachines`.
NOTE: This requires services.nix-daemon.enable for a
multi-user install.
''; '';
}; };
@ -404,7 +401,7 @@ in
{ darwin-config = "${config.environment.darwinConfig}"; } { darwin-config = "${config.environment.darwinConfig}"; }
"/nix/var/nix/profiles/per-user/root/channels" "/nix/var/nix/profiles/per-user/root/channels"
]; ];
defaultText = lib.literalExpression '' defaultText = lib.literalExpression ''
lib.optionals cfg.channel.enable [ lib.optionals cfg.channel.enable [
# Include default path <darwin-config>. # Include default path <darwin-config>.
@ -527,8 +524,10 @@ in
description = '' description = ''
If set to true, Nix automatically detects files in the store that have If set to true, Nix automatically detects files in the store that have
identical contents, and replaces them with hard links to a single copy. identical contents, and replaces them with hard links to a single copy.
This saves disk space. If set to false (the default), you can still run This saves disk space. If set to false (the default), you can enable
nix-store --optimise to get rid of duplicate files. {option}`nix.optimise.automatic` to run {command}`nix-store --optimise`
periodically to get rid of duplicate files. You can also run
{command}`nix-store --optimise` manually.
''; '';
}; };
@ -686,7 +685,7 @@ in
nixPackage nixPackage
pkgs.nix-info pkgs.nix-info
] ]
++ optional (config.programs.bash.enableCompletion) pkgs.nix-bash-completions; ++ optional (config.programs.bash.completion.enable) pkgs.nix-bash-completions;
environment.etc."nix/nix.conf".source = nixConf; environment.etc."nix/nix.conf".source = nixConf;
@ -761,11 +760,17 @@ in
{ assertion = elem "nixbld" config.users.knownGroups -> elem "nixbld" createdGroups; message = "refusing to delete group nixbld in users.knownGroups, this would break nix"; } { assertion = elem "nixbld" config.users.knownGroups -> elem "nixbld" createdGroups; message = "refusing to delete group nixbld in users.knownGroups, this would break nix"; }
{ assertion = elem "_nixbld1" config.users.knownGroups -> elem "_nixbld1" createdUsers; message = "refusing to delete user _nixbld1 in users.knownUsers, this would break nix"; } { assertion = elem "_nixbld1" config.users.knownGroups -> elem "_nixbld1" createdUsers; message = "refusing to delete user _nixbld1 in users.knownUsers, this would break nix"; }
{ assertion = config.users.groups ? "nixbld" -> config.users.groups.nixbld.members != []; message = "refusing to remove all members from nixbld group, this would break nix"; } { 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
# As `isNixAtLeast "2.92.0" "2.92.0-devpre20241107" == false`, we need to explicitly check if the user is running Lix 2.92.0
assertion = cfg.settings.auto-optimise-store -> (cfg.package.pname == "lix" && (isNixAtLeast "2.92.0-devpre20241107" || cfg.package.version == "2.92.0"));
message = "`nix.settings.auto-optimise-store` is known to corrupt the Nix Store, please use `nix.optimise.automatic` instead.";
}
]; ];
# Not in NixOS module # Not in NixOS module
warnings = [ warnings = [
(mkIf (!config.services.activate-system.enable && cfg.distributedBuilds) "services.activate-system is not enabled, a reboot could cause distributed builds to stop working.")
(mkIf (!cfg.distributedBuilds && cfg.buildMachines != []) "nix.distributedBuilds is not enabled, build machines won't be configured.") (mkIf (!cfg.distributedBuilds && cfg.buildMachines != []) "nix.distributedBuilds is not enabled, build machines won't be configured.")
]; ];

47
modules/power/default.nix Normal file
View file

@ -0,0 +1,47 @@
{ config, lib, ... }:
let
cfg = config.power;
types = lib.types;
onOff = cond: if cond then "on" else "off";
in
{
options = {
power.restartAfterPowerFailure = lib.mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Whether to restart the computer after a power failure.
'';
};
power.restartAfterFreeze = lib.mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Whether to restart the computer after a system freeze.
'';
};
};
config = {
system.activationScripts.power.text = ''
echo "configuring power..." >&2
${lib.optionalString (cfg.restartAfterPowerFailure != null) ''
systemsetup -setRestartPowerFailure \
'${onOff cfg.restartAfterPowerFailure}' &> /dev/null
''}
${lib.optionalString (cfg.restartAfterFreeze != null) ''
systemsetup -setRestartFreeze \
'${onOff cfg.restartAfterFreeze}' &> /dev/null
''}
'';
};
}

80
modules/power/sleep.nix Normal file
View file

@ -0,0 +1,80 @@
{ config, lib, ... }:
let
cfg = config.power.sleep;
types = lib.types;
onOff = cond: if cond then "on" else "off";
in
{
options = {
power.sleep.computer = lib.mkOption {
type = types.nullOr (types.either types.ints.positive (types.enum ["never"]));
default = null;
example = "never";
description = ''
Amount of idle time (in minutes) until the computer sleeps.
`"never"` disables computer sleeping.
The system might not be considered idle before connected displays sleep, as
per the `power.sleep.display` option.
'';
};
power.sleep.display = lib.mkOption {
type = types.nullOr (types.either types.ints.positive (types.enum ["never"]));
default = null;
example = "never";
description = ''
Amount of idle time (in minutes) until displays sleep.
`"never"` disables display sleeping.
'';
};
power.sleep.harddisk = lib.mkOption {
type = types.nullOr (types.either types.ints.positive (types.enum ["never"]));
default = null;
example = "never";
description = ''
Amount of idle time (in minutes) until hard disks sleep.
`"never"` disables hard disk sleeping.
'';
};
power.sleep.allowSleepByPowerButton = lib.mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Whether the power button can sleep the computer.
'';
};
};
config = {
system.activationScripts.power.text = lib.mkAfter ''
${lib.optionalString (cfg.computer != null) ''
systemsetup -setComputerSleep '${toString cfg.computer}' &> /dev/null
''}
${lib.optionalString (cfg.display != null) ''
systemsetup -setDisplaySleep '${toString cfg.display}' &> /dev/null
''}
${lib.optionalString (cfg.harddisk != null) ''
systemsetup -setHardDiskSleep '${toString cfg.harddisk}' &> /dev/null
''}
${lib.optionalString (cfg.allowSleepByPowerButton != null) ''
systemsetup -setAllowPowerButtonToSleepComputer \
'${onOff cfg.allowSleepByPowerButton}' &> /dev/null
''}
'';
};
}

View file

@ -7,6 +7,10 @@ let
in in
{ {
imports = [
(mkRenamedOptionModule [ "programs" "bash" "enableCompletion" ] [ "programs" "bash" "completion" "enable" ])
];
options = { options = {
programs.bash.enable = mkOption { programs.bash.enable = mkOption {
@ -21,14 +25,18 @@ in
type = types.lines; type = types.lines;
}; };
programs.bash.enableCompletion = mkOption { programs.bash.completion = {
type = types.bool; enable = mkOption {
default = false; type = types.bool;
description = '' default = false;
Enable bash completion for all interactive bash shells. description = ''
Enable bash completion for all interactive bash shells.
NOTE. This doesn't work with bash 3.2, which is the default on macOS. NOTE: This doesn't work with bash 3.2, which is installed by default on macOS by Apple.
''; '';
};
package = mkPackageOption pkgs "bash-completion" { };
}; };
}; };
@ -38,9 +46,9 @@ in
environment.systemPackages = environment.systemPackages =
[ # Include bash package [ # Include bash package
pkgs.bashInteractive pkgs.bashInteractive
] ++ optional cfg.enableCompletion pkgs.bash-completion; ] ++ optional cfg.completion.enable cfg.completion.package;
environment.pathsToLink = environment.pathsToLink = optionals cfg.completion.enable
[ "/etc/bash_completion.d" [ "/etc/bash_completion.d"
"/share/bash-completion/completions" "/share/bash-completion/completions"
]; ];
@ -70,9 +78,9 @@ in
${config.environment.interactiveShellInit} ${config.environment.interactiveShellInit}
${cfg.interactiveShellInit} ${cfg.interactiveShellInit}
${optionalString cfg.enableCompletion '' ${optionalString cfg.completion.enable ''
if [ "$TERM" != "dumb" ]; then if [ "$TERM" != "dumb" ]; then
source "${pkgs.bash-completion}/etc/profile.d/bash_completion.sh" source "${cfg.completion.package}/etc/profile.d/bash_completion.sh"
nullglobStatus=$(shopt -p nullglob) nullglobStatus=$(shopt -p nullglob)
shopt -s nullglob shopt -s nullglob

View file

@ -41,6 +41,7 @@ in
{ {
imports = [ imports = [
(mkRenamedOptionModule [ "programs" "tmux" "tmuxConfig" ] [ "programs" "tmux" "extraConfig" ]) (mkRenamedOptionModule [ "programs" "tmux" "tmuxConfig" ] [ "programs" "tmux" "extraConfig" ])
(mkRemovedOptionModule [ "programs" "tmux" "defaultCommand" ] "Use `programs.tmux.extraConfig` to configure the default command instead. If unset, tmux will default to using your system configured login shell.")
]; ];
options = { options = {
programs.tmux.enable = mkOption { programs.tmux.enable = mkOption {
@ -84,11 +85,6 @@ in
description = "Cater to iTerm2 and its tmux integration, as appropriate."; description = "Cater to iTerm2 and its tmux integration, as appropriate.";
}; };
programs.tmux.defaultCommand = mkOption {
type = types.either types.str types.package;
description = "The default command to use for tmux panes.";
};
programs.tmux.tmuxOptions = mkOption { programs.tmux.tmuxOptions = mkOption {
internal = true; internal = true;
type = types.attrsOf (types.submodule text); type = types.attrsOf (types.submodule text);
@ -120,12 +116,6 @@ in
source-file -q /etc/tmux.conf.local source-file -q /etc/tmux.conf.local
''; '';
programs.tmux.defaultCommand = mkDefault config.environment.loginShell;
programs.tmux.tmuxOptions.login-shell.text = ''
set -g default-command "${cfg.defaultCommand}"
'';
programs.tmux.tmuxOptions.sensible.text = mkIf cfg.enableSensible '' programs.tmux.tmuxOptions.sensible.text = mkIf cfg.enableSensible ''
set -g default-terminal "screen-256color" set -g default-terminal "screen-256color"
setw -g aggressive-resize on setw -g aggressive-resize on

View file

@ -18,7 +18,7 @@ in
options = { options = {
programs.zsh.enable = mkOption { programs.zsh.enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = true;
description = "Whether to configure zsh as an interactive shell."; description = "Whether to configure zsh as an interactive shell.";
}; };
@ -107,15 +107,24 @@ in
default = false; default = false;
description = "Enable zsh-syntax-highlighting."; description = "Enable zsh-syntax-highlighting.";
}; };
programs.zsh.enableFastSyntaxHighlighting = mkEnableOption "zsh-fast-syntax-highlighting";
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
assertions = [
{
assertion = !(cfg.enableSyntaxHighlighting && cfg.enableFastSyntaxHighlighting);
message = "zsh-syntax-highlighting and zsh-fast-syntax-highlighting are mutually exclusive, please disable one of them.";
}
];
environment.systemPackages = environment.systemPackages =
[ # Include zsh package [ # Include zsh package
pkgs.zsh pkgs.zsh
] ++ optional cfg.enableCompletion pkgs.nix-zsh-completions ] ++ optional cfg.enableCompletion pkgs.nix-zsh-completions
++ optional cfg.enableSyntaxHighlighting pkgs.zsh-syntax-highlighting; ++ optional cfg.enableSyntaxHighlighting pkgs.zsh-syntax-highlighting
++ optional cfg.enableFastSyntaxHighlighting pkgs.zsh-fast-syntax-highlighting;
environment.pathsToLink = [ "/share/zsh" ]; environment.pathsToLink = [ "/share/zsh" ];
@ -127,17 +136,19 @@ in
if [ -n "''${__ETC_ZSHENV_SOURCED-}" ]; then return; fi if [ -n "''${__ETC_ZSHENV_SOURCED-}" ]; then return; fi
__ETC_ZSHENV_SOURCED=1 __ETC_ZSHENV_SOURCED=1
if [ -z "''${__NIX_DARWIN_SET_ENVIRONMENT_DONE-}" ]; then if [[ -o rcs ]]; then
. ${config.system.build.setEnvironment} if [ -z "''${__NIX_DARWIN_SET_ENVIRONMENT_DONE-}" ]; then
. ${config.system.build.setEnvironment}
fi
# Tell zsh how to find installed completions
for p in ''${(z)NIX_PROFILES}; do
fpath=($p/share/zsh/site-functions $p/share/zsh/$ZSH_VERSION/functions $p/share/zsh/vendor-completions $fpath)
done
${cfg.shellInit}
fi fi
# Tell zsh how to find installed completions
for p in ''${(z)NIX_PROFILES}; do
fpath=($p/share/zsh/site-functions $p/share/zsh/$ZSH_VERSION/functions $p/share/zsh/vendor-completions $fpath)
done
${cfg.shellInit}
# Read system-wide modifications. # Read system-wide modifications.
if test -f /etc/zshenv.local; then if test -f /etc/zshenv.local; then
source /etc/zshenv.local source /etc/zshenv.local
@ -192,6 +203,10 @@ in
"source ${pkgs.zsh-syntax-highlighting}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" "source ${pkgs.zsh-syntax-highlighting}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh"
} }
${optionalString cfg.enableFastSyntaxHighlighting
"source ${pkgs.zsh-fast-syntax-highlighting}/share/zsh-fast-syntax-highlighting/zsh-fast-syntax-highlighting.zsh"
}
${optionalString cfg.enableFzfCompletion "source ${fzfCompletion}"} ${optionalString cfg.enableFzfCompletion "source ${fzfCompletion}"}
${optionalString cfg.enableFzfGit "source ${fzfGit}"} ${optionalString cfg.enableFzfGit "source ${fzfGit}"}
${optionalString cfg.enableFzfHistory "source ${fzfHistory}"} ${optionalString cfg.enableFzfHistory "source ${fzfHistory}"}

View file

@ -1,22 +1,11 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.activate-system;
in
{ {
options = { imports = [
services.activate-system.enable = mkOption { (lib.mkRemovedOptionModule [ "services" "activate-system" "enable" ] "The `activate-system` service is now always enabled as it is necessary for a working `nix-darwin` setup.")
type = types.bool; ];
default = true;
description = "Whether to activate system at boot time.";
};
};
config = mkIf cfg.enable {
config = {
launchd.daemons.activate-system = { launchd.daemons.activate-system = {
script = '' script = ''
set -e set -e
@ -41,6 +30,5 @@ in
serviceConfig.RunAtLoad = true; serviceConfig.RunAtLoad = true;
serviceConfig.KeepAlive.SuccessfulExit = false; serviceConfig.KeepAlive.SuccessfulExit = false;
}; };
}; };
} }

View file

@ -0,0 +1,163 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.aerospace;
format = pkgs.formats.toml { };
configFile = format.generate "aerospace.toml" cfg.settings;
in
{
options = {
services.aerospace = with lib.types; {
enable = lib.mkEnableOption "AeroSpace window manager";
package = lib.mkPackageOption pkgs "aerospace" { };
settings = lib.mkOption {
type = submodule {
freeformType = format.type;
options = {
start-at-login = lib.mkOption {
type = bool;
default = false;
description = "Do not start AeroSpace at login. (Managed by launchd instead)";
};
after-login-command = lib.mkOption {
type = listOf str;
default = [ ];
description = "Do not use AeroSpace to run commands after login. (Managed by launchd instead)";
};
after-startup-command = lib.mkOption {
type = listOf str;
default = [ ];
description = "Do not use AeroSpace to run commands after startup. (Managed by launchd instead)";
};
enable-normalization-flatten-containers = lib.mkOption {
type = bool;
default = true;
description = "Containers that have only one child are \"flattened\".";
};
enable-normalization-opposite-orientation-for-nested-containers = lib.mkOption {
type = bool;
default = true;
description = "Containers that nest into each other must have opposite orientations.";
};
accordion-padding = lib.mkOption {
type = int;
default = 30;
description = "Padding between windows in an accordion container.";
};
default-root-container-layout = lib.mkOption {
type = enum [
"tiles"
"accordion"
];
default = "tiles";
description = "Default layout for the root container.";
};
default-root-container-orientation = lib.mkOption {
type = enum [
"horizontal"
"vertical"
"auto"
];
default = "auto";
description = "Default orientation for the root container.";
};
on-window-detected = lib.mkOption {
type = listOf str;
default = [ ];
description = "Commands to run every time a new window is detected.";
};
on-focus-changed = lib.mkOption {
type = listOf str;
default = [ ];
description = "Commands to run every time focused window or workspace changes.";
};
on-focused-monitor-changed = lib.mkOption {
type = listOf str;
default = [ "move-mouse monitor-lazy-center" ];
description = "Commands to run every time focused monitor changes.";
};
exec-on-workspace-change = lib.mkOption {
type = listOf str;
default = [ ];
example = [
"/bin/bash"
"-c"
"sketchybar --trigger aerospace_workspace_change FOCUSED=$AEROSPACE_FOCUSED_WORKSPACE"
];
description = "Commands to run every time workspace changes.";
};
key-mapping.preset = lib.mkOption {
type = enum [
"qwerty"
"dvorak"
];
default = "qwerty";
description = "Keymapping preset.";
};
};
};
default = { };
example = lib.literalExpression ''
{
gaps = {
outer.left = 8;
outer.bottom = 8;
outer.top = 8;
outer.right = 8;
};
mode.main.binding = {
alt-h = "focus left";
alt-j = "focus down";
alt-k = "focus up";
alt-l = "focus right";
};
}
'';
description = ''
AeroSpace configuration, see
<link xlink:href="https://nikitabobko.github.io/AeroSpace/guide#configuring-aerospace"/>
for supported values.
'';
};
};
};
config = (
lib.mkIf (cfg.enable) {
assertions = [
{
assertion = !cfg.settings.start-at-login;
message = "AeroSpace started at login is managed by home-manager and launchd instead of itself via this option.";
}
{
assertion = cfg.settings.after-login-command == [ ];
message = "AeroSpace will not run these commands as it does not start itself.";
}
{
assertion = cfg.settings.after-startup-command == [ ];
message = "AeroSpace will not run these commands as it does not start itself.";
}
];
environment.systemPackages = [ cfg.package ];
launchd.user.agents.aerospace = {
command =
"${cfg.package}/Applications/AeroSpace.app/Contents/MacOS/AeroSpace"
+ (lib.optionalString (cfg.settings != { }) " --config-path ${configFile}");
serviceConfig = {
KeepAlive = true;
RunAtLoad = true;
};
};
}
);
}

View file

@ -237,7 +237,7 @@ in
tagStr = lib.concatStringsSep "," (lib.mapAttrsToList (name: value: "${name}=${value}") cfg.tags); tagStr = lib.concatStringsSep "," (lib.mapAttrsToList (name: value: "${name}=${value}") cfg.tags);
in in
optionalString (cfg.privateSshKeyPath != null) '' optionalString (cfg.privateSshKeyPath != null) ''
mkdir -m 0700 -p "${sshDir}" mkdir -m 0700 "${sshDir}"
install -m600 "${toString cfg.privateSshKeyPath}" "${sshDir}/id_rsa" install -m600 "${toString cfg.privateSshKeyPath}" "${sshDir}/id_rsa"
'' + '' '' + ''
cat > "${cfg.dataDir}/buildkite-agent.cfg" <<EOF cat > "${cfg.dataDir}/buildkite-agent.cfg" <<EOF

View file

@ -44,9 +44,11 @@ in {
launchd.user.agents.emacs = { launchd.user.agents.emacs = {
path = cfg.additionalPath ++ [ config.environment.systemPath ]; path = cfg.additionalPath ++ [ config.environment.systemPath ];
serviceConfig.ProgramArguments = serviceConfig = {
[ "${cfg.package}/bin/${cfg.exec}" "--fg-daemon" ]; ProgramArguments = [ "${cfg.package}/bin/${cfg.exec}" "--fg-daemon" ];
serviceConfig.RunAtLoad = true; RunAtLoad = true;
KeepAlive = true;
};
}; };
}; };

View file

@ -48,14 +48,20 @@ in
text = mkBefore ('' text = mkBefore (''
echo >&2 "setting up GitHub Runner '${cfg.name}'..." echo >&2 "setting up GitHub Runner '${cfg.name}'..."
${pkgs.coreutils}/bin/mkdir -p -m 0750 ${escapeShellArg (mkStateDir cfg)} (
${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkStateDir cfg)} umask -S u=rwx,g=rx,o= > /dev/null
${pkgs.coreutils}/bin/mkdir -p -m 0750 ${escapeShellArg (mkLogDir cfg)} ${pkgs.coreutils}/bin/mkdir -p ${escapeShellArg (mkStateDir cfg)}
${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkLogDir cfg)} ${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkStateDir cfg)}
'' + optionalString (cfg.workDir == null) ''
${pkgs.coreutils}/bin/mkdir -p -m 0750 ${escapeShellArg (mkWorkDir cfg)} ${pkgs.coreutils}/bin/mkdir -p ${escapeShellArg (mkLogDir cfg)}
${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkWorkDir cfg)} ${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkLogDir cfg)}
${optionalString (cfg.workDir == null) ''
${pkgs.coreutils}/bin/mkdir -p ${escapeShellArg (mkWorkDir cfg)}
${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkWorkDir cfg)}
''}
)
''); '');
}; };
})); }));
@ -88,6 +94,10 @@ in
script = script =
let let
# https://github.com/NixOS/nixpkgs/pull/333744 introduced an inconsistency with different
# versions of nixpkgs. Use the old version of escapeShellArg to make sure that labels
# are always escaped to avoid https://www.shellcheck.net/wiki/SC2054
escapeShellArgAlways = string: "'${replaceStrings ["'"] ["'\\''"] (toString string)}'";
configure = pkgs.writeShellApplication { configure = pkgs.writeShellApplication {
name = "configure-github-runner-${name}"; name = "configure-github-runner-${name}";
text = /*bash*/'' text = /*bash*/''
@ -98,7 +108,7 @@ in
--disableupdate --disableupdate
--work ${escapeShellArg workDir} --work ${escapeShellArg workDir}
--url ${escapeShellArg cfg.url} --url ${escapeShellArg cfg.url}
--labels "${escapeShellArg (concatStringsSep "," cfg.extraLabels)}" --labels ${escapeShellArgAlways (concatStringsSep "," cfg.extraLabels)}
${optionalString (cfg.name != null ) "--name ${escapeShellArg cfg.name}"} ${optionalString (cfg.name != null ) "--name ${escapeShellArg cfg.name}"}
${optionalString cfg.replace "--replace"} ${optionalString cfg.replace "--replace"}
${optionalString (cfg.runnerGroup != null) "--runnergroup ${escapeShellArg cfg.runnerGroup}"} ${optionalString (cfg.runnerGroup != null) "--runnergroup ${escapeShellArg cfg.runnerGroup}"}

View file

@ -9,18 +9,19 @@ let
in in
{ {
options = { options.services.karabiner-elements = {
services.karabiner-elements.enable = mkEnableOption "Karabiner-Elements"; enable = mkEnableOption "Karabiner-Elements";
package = mkPackageOption pkgs "karabiner-elements" { };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
environment.systemPackages = [ pkgs.karabiner-elements ]; environment.systemPackages = [ cfg.package ];
system.activationScripts.preActivation.text = '' system.activationScripts.preActivation.text = ''
rm -rf ${parentAppDir} rm -rf ${parentAppDir}
mkdir -p ${parentAppDir} mkdir -p ${parentAppDir}
# Kernel extensions must reside inside of /Applications, they cannot be symlinks # Kernel extensions must reside inside of /Applications, they cannot be symlinks
cp -r ${pkgs.karabiner-elements.driver}/Applications/.Karabiner-VirtualHIDDevice-Manager.app ${parentAppDir} cp -r ${cfg.package.driver}/Applications/.Karabiner-VirtualHIDDevice-Manager.app ${parentAppDir}
''; '';
system.activationScripts.postActivation.text = '' system.activationScripts.postActivation.text = ''
@ -49,7 +50,7 @@ in
launchd.daemons.karabiner_grabber = { launchd.daemons.karabiner_grabber = {
serviceConfig.ProgramArguments = [ serviceConfig.ProgramArguments = [
"${pkgs.karabiner-elements}/Library/Application Support/org.pqrs/Karabiner-Elements/bin/karabiner_grabber" "${cfg.package}/Library/Application Support/org.pqrs/Karabiner-Elements/bin/karabiner_grabber"
]; ];
serviceConfig.ProcessType = "Interactive"; serviceConfig.ProcessType = "Interactive";
serviceConfig.Label = "org.pqrs.karabiner.karabiner_grabber"; serviceConfig.Label = "org.pqrs.karabiner.karabiner_grabber";
@ -60,7 +61,7 @@ in
launchd.daemons.karabiner_observer = { launchd.daemons.karabiner_observer = {
serviceConfig.ProgramArguments = [ serviceConfig.ProgramArguments = [
"${pkgs.karabiner-elements}/Library/Application Support/org.pqrs/Karabiner-Elements/bin/karabiner_observer" "${cfg.package}/Library/Application Support/org.pqrs/Karabiner-Elements/bin/karabiner_observer"
]; ];
serviceConfig.Label = "org.pqrs.karabiner.karabiner_observer"; serviceConfig.Label = "org.pqrs.karabiner.karabiner_observer";
@ -70,7 +71,7 @@ in
}; };
launchd.daemons.Karabiner-DriverKit-VirtualHIDDeviceClient = { launchd.daemons.Karabiner-DriverKit-VirtualHIDDeviceClient = {
command = "\"${pkgs.karabiner-elements.driver}/Library/Application Support/org.pqrs/Karabiner-DriverKit-VirtualHIDDevice/Applications/Karabiner-DriverKit-VirtualHIDDeviceClient.app/Contents/MacOS/Karabiner-DriverKit-VirtualHIDDeviceClient\""; command = "\"${cfg.package.driver}/Library/Application Support/org.pqrs/Karabiner-DriverKit-VirtualHIDDevice/Applications/Karabiner-DriverKit-VirtualHIDDeviceClient.app/Contents/MacOS/Karabiner-DriverKit-VirtualHIDDeviceClient\"";
serviceConfig.ProcessType = "Interactive"; serviceConfig.ProcessType = "Interactive";
serviceConfig.Label = "org.pqrs.Karabiner-DriverKit-VirtualHIDDeviceClient"; serviceConfig.Label = "org.pqrs.Karabiner-DriverKit-VirtualHIDDeviceClient";
serviceConfig.KeepAlive = true; serviceConfig.KeepAlive = true;
@ -91,7 +92,7 @@ in
script = '' script = ''
rm -rf /run/wrappers rm -rf /run/wrappers
mkdir -p /run/wrappers/bin mkdir -p /run/wrappers/bin
install -m4555 "${pkgs.karabiner-elements}/Library/Application Support/org.pqrs/Karabiner-Elements/bin/karabiner_session_monitor" /run/wrappers/bin install -m4555 "${cfg.package}/Library/Application Support/org.pqrs/Karabiner-Elements/bin/karabiner_session_monitor" /run/wrappers/bin
''; '';
serviceConfig.RunAtLoad = true; serviceConfig.RunAtLoad = true;
serviceConfig.KeepAlive.SuccessfulExit = false; serviceConfig.KeepAlive.SuccessfulExit = false;
@ -106,8 +107,8 @@ in
serviceConfig.KeepAlive = true; serviceConfig.KeepAlive = true;
}; };
environment.userLaunchAgents."org.pqrs.karabiner.agent.karabiner_grabber.plist".source = "${pkgs.karabiner-elements}/Library/LaunchAgents/org.pqrs.karabiner.agent.karabiner_grabber.plist"; environment.userLaunchAgents."org.pqrs.karabiner.agent.karabiner_grabber.plist".source = "${cfg.package}/Library/LaunchAgents/org.pqrs.karabiner.agent.karabiner_grabber.plist";
environment.userLaunchAgents."org.pqrs.karabiner.agent.karabiner_observer.plist".source = "${pkgs.karabiner-elements}/Library/LaunchAgents/org.pqrs.karabiner.agent.karabiner_observer.plist"; environment.userLaunchAgents."org.pqrs.karabiner.agent.karabiner_observer.plist".source = "${cfg.package}/Library/LaunchAgents/org.pqrs.karabiner.agent.karabiner_observer.plist";
environment.userLaunchAgents."org.pqrs.karabiner.karabiner_console_user_server.plist".source = "${pkgs.karabiner-elements}/Library/LaunchAgents/org.pqrs.karabiner.karabiner_console_user_server.plist"; environment.userLaunchAgents."org.pqrs.karabiner.karabiner_console_user_server.plist".source = "${cfg.package}/Library/LaunchAgents/org.pqrs.karabiner.karabiner_console_user_server.plist";
}; };
} }

View file

@ -0,0 +1,121 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
concatStringsSep
escapeShellArgs
getExe
mkEnableOption
mkIf
mkOption
mkPackageOption
mkRemovedOptionModule
types
;
cfg = config.services.prometheus.exporters.node;
in {
imports = [
(mkRemovedOptionModule [ "services" "prometheus" "exporters" "node" "openFirewall" ] "No nix-darwin equivalent to this NixOS option.")
(mkRemovedOptionModule [ "services" "prometheus" "exporters" "node" "firewallFilter" ] "No nix-darwin equivalent to this NixOS option.")
(mkRemovedOptionModule [ "services" "prometheus" "exporters" "node" "firewallRules" ] "No nix-darwin equivalent to this NixOS option.")
];
options = {
services.prometheus.exporters.node = {
enable = mkEnableOption "Prometheus Node exporter";
package = mkPackageOption pkgs "prometheus-node-exporter" { };
listenAddress = mkOption {
type = types.str;
default = "";
example = "0.0.0.0";
description = ''
Address where Node exporter exposes its HTTP interface. Leave empty to bind to all addresses.
'';
};
port = mkOption {
type = types.port;
default = 9100;
description = ''
Port where the Node exporter exposes its HTTP interface.
'';
};
extraFlags = mkOption {
type = types.listOf types.str;
default = [ ];
example = [ "--log.level=debug" ];
description = ''
Extra commandline options to pass to the Node exporter executable.
'';
};
enabledCollectors = mkOption {
type = types.listOf types.str;
default = [ ];
description = ''
Collectors to enable in addition to the ones that are [enabled by default](https://github.com/prometheus/node_exporter#enabled-by-default).
'';
};
disabledCollectors = mkOption {
type = types.listOf types.str;
default = [ ];
example = [ "boottime" ];
description = ''
Collectors to disable from the list of collectors that are [enabled by default](https://github.com/prometheus/node_exporter#enabled-by-default).
'';
};
};
};
config = mkIf cfg.enable {
users.users._prometheus-node-exporter = {
uid = config.ids.uids._prometheus-node-exporter;
gid = config.ids.gids._prometheus-node-exporter;
home = "/var/lib/prometheus-node-exporter";
createHome = true;
shell = "/usr/bin/false";
description = "System user for the Prometheus Node exporter";
};
users.groups._prometheus-node-exporter = {
gid = config.ids.gids._prometheus-node-exporter;
description = "System group for the Prometheus Node exporter";
};
users.knownGroups = [ "_prometheus-node-exporter" ];
users.knownUsers = [ "_prometheus-node-exporter" ];
launchd.daemons.prometheus-node-exporter = {
script = concatStringsSep " "
([
(getExe cfg.package)
"--web.listen-address"
"${cfg.listenAddress}:${toString cfg.port}"
]
++ (map (collector: "--collector.${collector}") cfg.enabledCollectors)
++ (map (collector: "--no-collector.${collector}") cfg.disabledCollectors)
) + escapeShellArgs cfg.extraFlags;
serviceConfig = let
logPath = config.users.users._prometheus-node-exporter.home
+ "/prometheus-node-exporter.log";
in {
KeepAlive = true;
RunAtLoad = true;
StandardErrorPath = logPath;
StandardOutPath = logPath;
GroupName = "_prometheus-node-exporter";
UserName = "_prometheus-node-exporter";
};
};
};
}

View file

@ -1,16 +1,16 @@
{ config, lib, pkgs, ... }: { config, lib, ... }:
with lib;
let let
cfg = config.services.nix-daemon; cfg = config.services.nix-daemon;
inherit (lib) mkDefault mkIf mkMerge mkOption types;
in in
{ {
options = { options = {
services.nix-daemon.enable = mkOption { services.nix-daemon.enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = true;
description = "Whether to enable the nix-daemon service."; description = "Whether to enable the nix-daemon service.";
}; };

View file

@ -46,12 +46,6 @@ in
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
assertions = [
{ assertion = elem "ofborg" config.users.knownGroups; message = "set users.knownGroups to enable ofborg group"; }
{ assertion = elem "ofborg" config.users.knownUsers; message = "set users.knownUsers to enable ofborg user"; }
];
warnings = mkIf (isDerivation cfg.configFile) [ warnings = mkIf (isDerivation cfg.configFile) [
"services.ofborg.configFile is a derivation, credentials will be world readable" "services.ofborg.configFile is a derivation, credentials will be world readable"
]; ];
@ -87,9 +81,13 @@ in
users.users.ofborg.shell = "/bin/bash"; users.users.ofborg.shell = "/bin/bash";
users.users.ofborg.description = "OfBorg service user"; users.users.ofborg.description = "OfBorg service user";
users.knownUsers = [ "ofborg" ];
users.groups.ofborg.gid = mkDefault 531; users.groups.ofborg.gid = mkDefault 531;
users.groups.ofborg.description = "Nix group for OfBorg service"; users.groups.ofborg.description = "Nix group for OfBorg service";
users.knownGroups = [ "ofborg" ];
# FIXME: create logfiles automatically if defined. # FIXME: create logfiles automatically if defined.
system.activationScripts.preActivation.text = '' system.activationScripts.preActivation.text = ''
mkdir -p '${user.home}' mkdir -p '${user.home}'

View file

@ -237,10 +237,10 @@ in
for an overview of `postgresql.conf`. for an overview of `postgresql.conf`.
::: {.note} ::: {.note}
String values will automatically be enclosed in single quotes. Single quotes will be String values will automatically be enclosed in single quotes. Single quotes will be
escaped with two single quotes as described by the upstream documentation linked above. escaped with two single quotes as described by the upstream documentation linked above.
::: :::
''; '';
example = literalExpression '' example = literalExpression ''
@ -355,11 +355,14 @@ in
"${cfg.dataDir}/recovery.conf" "${cfg.dataDir}/recovery.conf"
''} ''}
exec ${postgresql}/bin/postgres -D ${cfg.dataDir} exec ${postgresql}/bin/postgres
''; '';
serviceConfig.KeepAlive = true; serviceConfig.KeepAlive = true;
serviceConfig.RunAtLoad = true; serviceConfig.RunAtLoad = true;
serviceConfig.EnvironmentVariables = {
PGDATA = cfg.dataDir;
};
}; };
}; };

View file

@ -29,6 +29,7 @@ in
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
environment.systemPackages = [ cfg.package ];
environment.etc."skhdrc".text = cfg.skhdConfig; environment.etc."skhdrc".text = cfg.skhdConfig;

View file

@ -67,6 +67,7 @@ in
${cfg.activationScripts.nix-daemon.text} ${cfg.activationScripts.nix-daemon.text}
${cfg.activationScripts.time.text} ${cfg.activationScripts.time.text}
${cfg.activationScripts.networking.text} ${cfg.activationScripts.networking.text}
${cfg.activationScripts.power.text}
${cfg.activationScripts.keyboard.text} ${cfg.activationScripts.keyboard.text}
${cfg.activationScripts.fonts.text} ${cfg.activationScripts.fonts.text}
${cfg.activationScripts.nvram.text} ${cfg.activationScripts.nvram.text}
@ -85,6 +86,7 @@ in
exit $_status exit $_status
''; '';
# FIXME: activationScripts.checks should be system level
system.activationScripts.userScript.text = '' system.activationScripts.userScript.text = ''
#! ${stdenv.shell} #! ${stdenv.shell}
set -e set -e

View file

@ -2,22 +2,49 @@
{ {
system.activationScripts.createRun.text = '' system.activationScripts.createRun.text = ''
if ! test -L /run; then IFS="." read -r -a macOSVersion <<< "$(sw_vers -productVersion)"
if [[ ''${macOSVersion[0]} -gt 10 || ( ''${macOSVersion[0]} -eq 10 && ''${macOSVersion[1]} -ge 15 ) ]]; then
if ! grep -q '^run\b' /etc/synthetic.conf 2>/dev/null; then if ! grep -q '^run\b' /etc/synthetic.conf 2>/dev/null; then
echo "setting up /run via /etc/synthetic.conf..." echo "setting up /run via /etc/synthetic.conf..."
echo -e "run\tprivate/var/run" | sudo tee -a /etc/synthetic.conf >/dev/null printf 'run\tprivate/var/run\n' | sudo tee -a /etc/synthetic.conf >/dev/null
sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -B &>/dev/null || true
sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -t &>/dev/null || true
if ! test -L /run; then
echo "warning: apfs.util failed to symlink /run"
fi
fi fi
if ! test -L /run; then
echo "setting up /run..." if [[ ''${macOSVersion[0]} -gt 10 ]]; then
sudo ln -sfn private/var/run /run sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -t || true
else
sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -B || true
fi fi
if ! test -L /run; then
echo "warning: failed to symlink /run" if [[ ! -L /run ]]; then
printf >&2 'error: apfs.util failed to symlink /run, aborting activation\n'
printf >&2 'To create a symlink from /run to /var/run, please run:\n'
printf >&2 '\n'
printf >&2 "$ printf 'run\tprivate/var/run\n' | sudo tee -a /etc/synthetic.conf"
if [[ ''${macOSVersion[0]} -gt 10 ]]; then
printf >&2 '$ sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -t\n'
else
printf >&2 '$ sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -B\n'
fi
printf >&2 '\n'
printf >&2 'The current contents of /etc/synthetic.conf is:\n'
printf >&2 '\n'
sudo sed 's/^/ /' /etc/synthetic.conf >&2
printf >&2 '\n'
exit 1
fi
else
echo "setting up /run..."
sudo ln -sfn private/var/run /run
if [[ ! -L /run ]]; then
printf >&2 'error: failed to symlink /run, aborting activation\n'
printf >&2 'To create a symlink from /run to /var/run, please run:\n'
printf >&2 '\n'
printf >&2 '$ sudo ln -sfn private/var/link /run\n'
exit 1
fi fi
fi fi
''; '';

View file

@ -3,6 +3,9 @@
with lib; with lib;
let let
# Similar to lib.escapeShellArg but escapes "s instead of 's, to allow for parameter expansion in shells
escapeDoubleQuote = arg: ''"${replaceStrings ["\""] ["\"\\\"\""] (toString arg)}"'';
cfg = config.system.checks; cfg = config.system.checks;
darwinChanges = '' darwinChanges = ''
@ -22,28 +25,13 @@ let
''; '';
runLink = '' runLink = ''
if ! test -e /run; then if [[ ! -e /run ]]; then
echo "error: Directory /run does not exist, aborting activation" >&2 printf >&2 'error: directory /run does not exist, aborting activation\n'
echo "Create a symlink to /var/run with:" >&2 exit 1
if test -e /etc/synthetic.conf; then
echo >&2
echo "$ printf 'run\tprivate/var/run\n' | sudo tee -a /etc/synthetic.conf" >&2
echo "$ sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -B # For Catalina" >&2
echo "$ sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -t # For Big Sur and later" >&2
echo >&2
echo "The current contents of /etc/synthetic.conf is:" >&2
echo >&2
sed 's/^/ /' /etc/synthetic.conf >&2
echo >&2
else
echo >&2
echo "$ sudo ln -s private/var/run /run" >&2
echo >&2
fi
exit 2
fi fi
''; '';
oldBuildUsers = '' oldBuildUsers = ''
if dscl . -list /Users | grep -q '^nixbld'; then if dscl . -list /Users | grep -q '^nixbld'; then
echo "error: Detected old style nixbld users, aborting activation" >&2 echo "error: Detected old style nixbld users, aborting activation" >&2
@ -59,7 +47,7 @@ let
exit 2 exit 2
fi fi
''; '';
preSequoiaBuildUsers = '' preSequoiaBuildUsers = ''
${lib.optionalString config.nix.configureBuildUsers '' ${lib.optionalString config.nix.configureBuildUsers ''
# Dont complain when were about to migrate oldstyle build users… # Dont complain when were about to migrate oldstyle build users…
@ -104,7 +92,7 @@ let
buildUsers = '' buildUsers = ''
buildUser=$(dscl . -read /Groups/nixbld GroupMembership 2>&1 | awk '/^GroupMembership: / {print $2}') || true buildUser=$(dscl . -read /Groups/nixbld GroupMembership 2>&1 | awk '/^GroupMembership: / {print $2}') || true
if [ -z $buildUser ]; then if [[ -z "$buildUser" ]]; then
echo "error: Using the nix-daemon requires build users, aborting activation" >&2 echo "error: Using the nix-daemon requires build users, aborting activation" >&2
echo "Create the build users or disable the daemon:" >&2 echo "Create the build users or disable the daemon:" >&2
echo "$ darwin-install" >&2 echo "$ darwin-install" >&2
@ -120,7 +108,7 @@ let
buildGroupID = '' buildGroupID = ''
buildGroupID=$(dscl . -read /Groups/nixbld PrimaryGroupID | awk '{print $2}') buildGroupID=$(dscl . -read /Groups/nixbld PrimaryGroupID | awk '{print $2}')
expectedBuildGroupID=${toString config.ids.gids.nixbld} expectedBuildGroupID=${toString config.ids.gids.nixbld}
if [[ $buildGroupID != $expectedBuildGroupID ]]; then if [[ $buildGroupID != "$expectedBuildGroupID" ]]; then
printf >&2 '\e[1;31merror: Build user group has mismatching GID, aborting activation\e[0m\n' printf >&2 '\e[1;31merror: Build user group has mismatching GID, aborting activation\e[0m\n'
printf >&2 'The default Nix build user group ID was changed from 30000 to 350.\n' printf >&2 'The default Nix build user group ID was changed from 30000 to 350.\n'
printf >&2 'You are currently managing Nix build users with nix-darwin, but your\n' printf >&2 'You are currently managing Nix build users with nix-darwin, but your\n'
@ -130,6 +118,7 @@ let
printf >&2 'Possible causes include setting up a new Nix installation with an\n' printf >&2 'Possible causes include setting up a new Nix installation with an\n'
printf >&2 'existing nix-darwin configuration, setting up a new nix-darwin\n' printf >&2 'existing nix-darwin configuration, setting up a new nix-darwin\n'
printf >&2 'installation with an existing Nix installation, or manually increasing\n' printf >&2 'installation with an existing Nix installation, or manually increasing\n'
# shellcheck disable=SC2016
printf >&2 'your `system.stateVersion` setting.\n' printf >&2 'your `system.stateVersion` setting.\n'
printf >&2 '\n' printf >&2 '\n'
printf >&2 'You can set the configured group ID to match the actual value:\n' printf >&2 'You can set the configured group ID to match the actual value:\n'
@ -143,18 +132,26 @@ let
fi fi
''; '';
singleUser = '' nixDaemon = if config.nix.useDaemon then ''
if grep -q 'build-users-group =' /etc/nix/nix.conf; then if ! dscl . -read /Groups/nixbld PrimaryGroupID &> /dev/null; then
echo "error: The daemon is not enabled but this is a multi-user install, aborting activation" >&2 printf >&2 'error: The daemon should not be enabled for single-user installs, aborting activation\n'
echo "Enable the nix-daemon service:" >&2 printf >&2 'Disable the nix-daemon service:\n'
echo >&2 printf >&2 '\n'
echo " services.nix-daemon.enable = true;" >&2 printf >&2 ' services.nix-daemon.enable = false;\n'
echo >&2 printf >&2 '\n'
echo "or set" >&2 # shellcheck disable=SC2016
echo >&2 printf >&2 'and remove `nix.useDaemon` from your configuration if it is present.\n'
echo " nix.useDaemon = true;" >&2 printf >&2 '\n'
echo >&2 exit 2
exit 2 fi
'' else ''
if dscl . -read /Groups/nixbld PrimaryGroupID &> /dev/null; then
printf >&2 'error: The daemon should be enabled for multi-user installs, aborting activation\n'
printf >&2 'Enable the nix-daemon service:\n'
printf >&2 '\n'
printf >&2 ' services.nix-daemon.enable = true;\n'
printf >&2 '\n'
exit 2
fi fi
''; '';
@ -194,7 +191,7 @@ let
''; '';
nixPath = '' nixPath = ''
nixPath=${concatStringsSep ":" config.nix.nixPath}:$HOME/.nix-defexpr/channels nixPath=${concatMapStringsSep ":" escapeDoubleQuote config.nix.nixPath}:$HOME/.nix-defexpr/channels
darwinConfig=$(NIX_PATH=$nixPath nix-instantiate --find-file darwin-config) || true darwinConfig=$(NIX_PATH=$nixPath nix-instantiate --find-file darwin-config) || true
if ! test -e "$darwinConfig"; then if ! test -e "$darwinConfig"; then
@ -282,6 +279,7 @@ let
if [[ -d /etc/ssh/authorized_keys.d ]]; then if [[ -d /etc/ssh/authorized_keys.d ]]; then
printf >&2 '\e[1;31merror: /etc/ssh/authorized_keys.d exists, aborting activation\e[0m\n' printf >&2 '\e[1;31merror: /etc/ssh/authorized_keys.d exists, aborting activation\e[0m\n'
printf >&2 'SECURITY NOTICE: The previous implementation of the\n' printf >&2 'SECURITY NOTICE: The previous implementation of the\n'
# shellcheck disable=SC2016
printf >&2 '`users.users.<name>.openssh.authorizedKeys.*` options would not delete\n' printf >&2 '`users.users.<name>.openssh.authorizedKeys.*` options would not delete\n'
printf >&2 'authorized keys files when the setting for a given user was removed.\n' printf >&2 'authorized keys files when the setting for a given user was removed.\n'
printf >&2 '\n' printf >&2 '\n'
@ -297,6 +295,19 @@ let
exit 2 exit 2
fi fi
''; '';
homebrewInstalled = ''
if [[ ! -f ${escapeShellArg config.homebrew.brewPrefix}/brew && -z "''${INSTALLING_HOMEBREW:-}" ]]; then
echo "error: Using the homebrew module requires homebrew installed, aborting activation" >&2
echo "Homebrew doesn't seem to be installed. Please install homebrew separately." >&2
echo "You can install homebrew using the following command:" >&2
echo >&2
# shellcheck disable=SC2016
echo ' /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' >&2
echo >&2
exit 2
fi
'';
in in
{ {
@ -337,7 +348,7 @@ in
(mkIf cfg.verifyBuildUsers buildUsers) (mkIf cfg.verifyBuildUsers buildUsers)
(mkIf cfg.verifyBuildUsers preSequoiaBuildUsers) (mkIf cfg.verifyBuildUsers preSequoiaBuildUsers)
(mkIf config.nix.configureBuildUsers buildGroupID) (mkIf config.nix.configureBuildUsers buildGroupID)
(mkIf (!config.nix.useDaemon) singleUser) nixDaemon
nixStore nixStore
(mkIf (config.nix.gc.automatic && config.nix.gc.user == null) nixGarbageCollector) (mkIf (config.nix.gc.automatic && config.nix.gc.user == null) nixGarbageCollector)
(mkIf (config.nix.optimise.automatic && config.nix.optimise.user == null) nixStoreOptimiser) (mkIf (config.nix.optimise.automatic && config.nix.optimise.user == null) nixStoreOptimiser)
@ -345,12 +356,13 @@ in
nixInstaller nixInstaller
(mkIf cfg.verifyNixPath nixPath) (mkIf cfg.verifyNixPath nixPath)
oldSshAuthorizedKeysDirectory oldSshAuthorizedKeysDirectory
(mkIf config.homebrew.enable homebrewInstalled)
]; ];
system.activationScripts.checks.text = '' system.activationScripts.checks.text = ''
${cfg.text} ${cfg.text}
if test ''${checkActivation:-0} -eq 1; then if [[ "''${checkActivation:-0}" -eq 1 ]]; then
echo "ok" >&2 echo "ok" >&2
exit 0 exit 0
fi fi

View file

@ -92,6 +92,8 @@ in
name = "darwin-system-${cfg.darwinLabel}"; name = "darwin-system-${cfg.darwinLabel}";
preferLocalBuild = true; preferLocalBuild = true;
nativeBuildInputs = [ pkgs.shellcheck ];
activationScript = cfg.activationScripts.script.text; activationScript = cfg.activationScripts.script.text;
activationUserScript = cfg.activationScripts.userScript.text; activationUserScript = cfg.activationScripts.userScript.text;
inherit (cfg) darwinLabel; inherit (cfg) darwinLabel;
@ -133,6 +135,8 @@ in
chmod u+x $out/activate-user chmod u+x $out/activate-user
unset activationUserScript unset activationUserScript
shellcheck $out/activate $out/activate-user
echo -n "$systemConfig" > $out/systemConfig echo -n "$systemConfig" > $out/systemConfig
echo -n "$darwinLabel" > $out/darwin-version echo -n "$darwinLabel" > $out/darwin-version

View file

@ -14,7 +14,7 @@ let
alf = defaultsToList "/Library/Preferences/com.apple.alf" cfg.alf; alf = defaultsToList "/Library/Preferences/com.apple.alf" cfg.alf;
loginwindow = defaultsToList "/Library/Preferences/com.apple.loginwindow" cfg.loginwindow; loginwindow = defaultsToList "/Library/Preferences/com.apple.loginwindow" cfg.loginwindow;
smb = defaultsToList "/Library/Preferences/SystemConfiguration/com.apple.smb.server" cfg.smb; smb = defaultsToList "/Library/Preferences/SystemConfiguration/com.apple.smb.server" cfg.smb;
SoftwareUpdate = defaultsToList "/Library/Preferences/SystemConfiguration/com.apple.SoftwareUpdate" cfg.SoftwareUpdate; SoftwareUpdate = defaultsToList "/Library/Preferences/com.apple.SoftwareUpdate" cfg.SoftwareUpdate;
# userDefaults # userDefaults
GlobalPreferences = defaultsToList ".GlobalPreferences" cfg.".GlobalPreferences"; GlobalPreferences = defaultsToList ".GlobalPreferences" cfg.".GlobalPreferences";
@ -23,6 +23,7 @@ let
menuExtraClock = defaultsToList "com.apple.menuextra.clock" cfg.menuExtraClock; menuExtraClock = defaultsToList "com.apple.menuextra.clock" cfg.menuExtraClock;
dock = defaultsToList "com.apple.dock" cfg.dock; dock = defaultsToList "com.apple.dock" cfg.dock;
finder = defaultsToList "com.apple.finder" cfg.finder; finder = defaultsToList "com.apple.finder" cfg.finder;
hitoolbox = defaultsToList "com.apple.HIToolbox" cfg.hitoolbox;
magicmouse = defaultsToList "com.apple.AppleMultitouchMouse" cfg.magicmouse; magicmouse = defaultsToList "com.apple.AppleMultitouchMouse" cfg.magicmouse;
magicmouseBluetooth = defaultsToList "com.apple.driver.AppleMultitouchMouse.mouse" cfg.magicmouse; magicmouseBluetooth = defaultsToList "com.apple.driver.AppleMultitouchMouse.mouse" cfg.magicmouse;
screencapture = defaultsToList "com.apple.screencapture" cfg.screencapture; screencapture = defaultsToList "com.apple.screencapture" cfg.screencapture;
@ -33,9 +34,11 @@ let
universalaccess = defaultsToList "com.apple.universalaccess" cfg.universalaccess; universalaccess = defaultsToList "com.apple.universalaccess" cfg.universalaccess;
ActivityMonitor = defaultsToList "com.apple.ActivityMonitor" cfg.ActivityMonitor; ActivityMonitor = defaultsToList "com.apple.ActivityMonitor" cfg.ActivityMonitor;
WindowManager = defaultsToList "com.apple.WindowManager" cfg.WindowManager; WindowManager = defaultsToList "com.apple.WindowManager" cfg.WindowManager;
controlcenter = defaultsToList "~/Library/Preferences/ByHost/com.apple.controlcenter" cfg.controlcenter;
CustomUserPreferences = flatten (mapAttrsToList (name: value: defaultsToList name value) cfg.CustomUserPreferences); CustomUserPreferences = flatten (mapAttrsToList (name: value: defaultsToList name value) cfg.CustomUserPreferences);
CustomSystemPreferences = flatten (mapAttrsToList (name: value: defaultsToList name value) cfg.CustomSystemPreferences); CustomSystemPreferences = flatten (mapAttrsToList (name: value: defaultsToList name value) cfg.CustomSystemPreferences);
mkIfAttrs = list: mkIf (any (attrs: attrs != { }) list); mkIfAttrs = list: mkIf (any (attrs: attrs != { }) list);
in in
@ -76,6 +79,7 @@ in
menuExtraClock menuExtraClock
dock dock
finder finder
hitoolbox
magicmouse magicmouse
magicmouseBluetooth magicmouseBluetooth
screencapture screencapture
@ -87,6 +91,7 @@ in
ActivityMonitor ActivityMonitor
CustomUserPreferences CustomUserPreferences
WindowManager WindowManager
controlcenter
] ]
'' ''
# Set defaults # Set defaults
@ -99,6 +104,7 @@ in
${concatStringsSep "\n" menuExtraClock} ${concatStringsSep "\n" menuExtraClock}
${concatStringsSep "\n" dock} ${concatStringsSep "\n" dock}
${concatStringsSep "\n" finder} ${concatStringsSep "\n" finder}
${concatStringsSep "\n" hitoolbox}
${concatStringsSep "\n" magicmouse} ${concatStringsSep "\n" magicmouse}
${concatStringsSep "\n" magicmouseBluetooth} ${concatStringsSep "\n" magicmouseBluetooth}
${concatStringsSep "\n" screencapture} ${concatStringsSep "\n" screencapture}
@ -110,10 +116,11 @@ in
${concatStringsSep "\n" ActivityMonitor} ${concatStringsSep "\n" ActivityMonitor}
${concatStringsSep "\n" CustomUserPreferences} ${concatStringsSep "\n" CustomUserPreferences}
${concatStringsSep "\n" WindowManager} ${concatStringsSep "\n" WindowManager}
${concatStringsSep "\n" controlcenter}
${optionalString (length dock > 0) '' ${optionalString (length dock > 0) ''
# Only restart Dock if current user is logged in # Only restart Dock if current user is logged in
if pgrep -xu $UID Dock; then if pgrep -xu $UID Dock >/dev/null; then
echo >&2 "restarting Dock..." echo >&2 "restarting Dock..."
killall Dock || true killall Dock || true
fi fi

View file

@ -5,6 +5,14 @@ with lib;
{ {
options = { options = {
system.defaults.menuExtraClock.FlashDateSeparators = mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
When enabled, the clock indicator (which by default is the colon) will flash on and off each second. Default is null.
'';
};
system.defaults.menuExtraClock.IsAnalog = mkOption { system.defaults.menuExtraClock.IsAnalog = mkOption {
type = types.nullOr types.bool; type = types.nullOr types.bool;
default = null; default = null;

View file

@ -0,0 +1,100 @@
{ config, lib, ... }:
{
options = {
system.defaults.controlcenter.BatteryShowPercentage = lib.mkOption {
type = lib.types.nullOr lib.types.bool;
default = null;
description = ''
Apple menu > System Preferences > Control Center > Battery
Show a battery percentage in menu bar. Default is null.
'';
};
system.defaults.controlcenter.Sound = lib.mkOption {
type = lib.types.nullOr lib.types.bool;
apply = v: if v == null then null else if v == true then 18 else 24;
default = null;
description = ''
Apple menu > System Preferences > Control Center > Sound
Show a sound control in menu bar . Default is null.
18 = Display icon in menu bar
24 = Hide icon in menu bar
'';
};
system.defaults.controlcenter.Bluetooth = lib.mkOption {
type = lib.types.nullOr lib.types.bool;
apply = v: if v == null then null else if v == true then 18 else 24;
default = null;
description = ''
Apple menu > System Preferences > Control Center > Bluetooth
Show a bluetooth control in menu bar. Default is null.
18 = Display icon in menu bar
24 = Hide icon in menu bar
'';
};
system.defaults.controlcenter.AirDrop = lib.mkOption {
type = lib.types.nullOr lib.types.bool;
apply = v: if v == null then null else if v == true then 18 else 24;
default = null;
description = ''
Apple menu > System Preferences > Control Center > AirDrop
Show a AirDrop control in menu bar. Default is null.
18 = Display icon in menu bar
24 = Hide icon in menu bar
'';
};
system.defaults.controlcenter.Display = lib.mkOption {
type = lib.types.nullOr lib.types.bool;
apply = v: if v == null then null else if v == true then 18 else 24;
default = null;
description = ''
Apple menu > System Preferences > Control Center > Display
Show a Screen Brightness control in menu bar. Default is null.
18 = Display icon in menu bar
24 = Hide icon in menu bar
'';
};
system.defaults.controlcenter.FocusModes = lib.mkOption {
type = lib.types.nullOr lib.types.bool;
apply = v: if v == null then null else if v == true then 18 else 24;
default = null;
description = ''
Apple menu > System Preferences > Control Center > Focus
Show a Focus control in menu bar. Default is null.
18 = Display icon in menu bar
24 = Hide icon in menu bar
'';
};
system.defaults.controlcenter.NowPlaying = lib.mkOption {
type = lib.types.nullOr lib.types.bool;
apply = v: if v == null then null else if v == true then 18 else 24;
default = null;
description = ''
Apple menu > System Preferences > Control Center > Now Playing
Show a Now Playing control in menu bar. Default is null.
18 = Display icon in menu bar
24 = Hide icon in menu bar
'';
};
};
}

View file

@ -149,6 +149,14 @@ in {
else map (folder: { tile-data = { file-data = { _CFURLString = "file://" + folder; _CFURLStringType = 15; }; }; tile-type = if strings.hasInfix "." (last (splitString "/" folder)) then "file-tile" else "directory-tile"; }) value; else map (folder: { tile-data = { file-data = { _CFURLString = "file://" + folder; _CFURLStringType = 15; }; }; tile-type = if strings.hasInfix "." (last (splitString "/" folder)) then "file-tile" else "directory-tile"; }) value;
}; };
system.defaults.dock.scroll-to-open = mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Scroll up on a Dock icon to show all Space's opened windows for an app, or open stack. The default is false.
'';
};
system.defaults.dock.show-process-indicators = mkOption { system.defaults.dock.show-process-indicators = mkOption {
type = types.nullOr types.bool; type = types.nullOr types.bool;
default = null; default = null;

View file

@ -1,7 +1,10 @@
{ config, lib, ... }: { config, lib, ... }:
with lib; let
inherit (lib) mkOption types;
cfg = config.system.defaults.finder;
in
{ {
options = { options = {
@ -38,6 +41,15 @@ with lib;
''; '';
}; };
system.defaults.finder.FXRemoveOldTrashItems = mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Remove items in the trash after 30 days.
The default is false.
'';
};
system.defaults.finder.FXPreferredViewStyle = mkOption { system.defaults.finder.FXPreferredViewStyle = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
@ -52,7 +64,7 @@ with lib;
type = types.nullOr types.bool; type = types.nullOr types.bool;
default = null; default = null;
description = '' description = ''
Whether to always show file extensions. The default is false. Whether to always show file extensions. The default is false.
''; '';
}; };
@ -68,7 +80,39 @@ with lib;
type = types.nullOr types.bool; type = types.nullOr types.bool;
default = null; default = null;
description = '' description = ''
Whether to allow quitting of the Finder. The default is false. Whether to allow quitting of the Finder. The default is false.
'';
};
system.defaults.finder.ShowExternalHardDrivesOnDesktop = mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Whether to show external disks on desktop. The default is true.
'';
};
system.defaults.finder.ShowHardDrivesOnDesktop = mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Whether to show hard disks on desktop. The default is false.
'';
};
system.defaults.finder.ShowMountedServersOnDesktop = mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Whether to show connected servers on desktop. The default is false.
'';
};
system.defaults.finder.ShowRemovableMediaOnDesktop = mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Whether to show removable media (CDs, DVDs and iPods) on desktop. The default is true.
''; '';
}; };
@ -76,7 +120,7 @@ with lib;
type = types.nullOr types.bool; type = types.nullOr types.bool;
default = null; default = null;
description = '' description = ''
Whether to show the full POSIX filepath in the window title. The default is false. Whether to show the full POSIX filepath in the window title. The default is false.
''; '';
}; };
@ -88,13 +132,70 @@ with lib;
''; '';
}; };
system.defaults.finder._FXSortFoldersFirstOnDesktop = mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Keep folders on top when sorting by name on the desktop. The default is false.
'';
};
system.defaults.finder.FXEnableExtensionChangeWarning = mkOption { system.defaults.finder.FXEnableExtensionChangeWarning = mkOption {
type = types.nullOr types.bool; type = types.nullOr types.bool;
default = null; default = null;
description = '' description = ''
Whether to show warnings when change the file extension of files. The default is true. Whether to show warnings when change the file extension of files. The default is true.
''; '';
}; };
system.defaults.finder.NewWindowTarget = mkOption {
type = types.nullOr (types.enum [
"Computer"
"OS volume"
"Home"
"Desktop"
"Documents"
"Recents"
"iCloud Drive"
"Other"
]);
apply = key: if key == null then null else {
"Computer" = "PfCm";
"OS volume" = "PfVo";
"Home" = "PfHm";
"Desktop" = "PfDe";
"Documents" = "PfDo";
"Recents" = "PfAF";
"iCloud Drive" = "PfID";
"Other" = "PfLo";
}.${key};
default = null;
description = ''
Change the default folder shown in Finder windows. "Other" corresponds to the value of
NewWindowTargetPath. The default is unset ("Recents").
'';
};
system.defaults.finder.NewWindowTargetPath = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Sets the URI to open when NewWindowTarget is "Other". Spaces and similar characters must be
escaped. If the value is invalid, Finder will open your home directory.
Example: "file:///Users/foo/long%20cat%20pics".
The default is unset.
'';
};
};
config = {
assertions = [{
assertion = cfg.NewWindowTargetPath != null -> cfg.NewWindowTarget == "PfLo";
message = "`system.defaults.finder.NewWindowTarget` should be set to `Other` when `NewWindowTargetPath` is non-null.";
}
{
assertion = cfg.NewWindowTarget == "PfLo" -> cfg.NewWindowTargetPath != null;
message = "`system.defaults.finder.NewWindowTargetPath` should be non-null when `NewWindowTarget` is set to `Other`.";
}];
}; };
} }

View file

@ -0,0 +1,29 @@
{ lib, ... }:
{
options = {
system.defaults.hitoolbox.AppleFnUsageType = lib.mkOption {
type = lib.types.nullOr (lib.types.enum [
"Do Nothing"
"Change Input Source"
"Show Emoji & Symbols"
"Start Dictation"
]);
apply = key: if key == null then null else {
"Do Nothing" = 0;
"Change Input Source" = 1;
"Show Emoji & Symbols" = 2;
"Start Dictation" = 3;
}.${key};
default = null;
description = ''
Chooses what happens when you press the Fn key on the keyboard. A restart is required for
this setting to take effect.
The default is unset ("Show Emoji & Symbols").
'';
};
};
}

View file

@ -29,6 +29,18 @@ with lib;
''; '';
}; };
system.defaults.screencapture.include-date = mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Include date and time in screenshot filenames. The default is true.
Screenshot 2024-01-09 at 13.27.20.png would be an example for true.
Screenshot.png
Screenshot 1.png would be an example for false.
'';
};
system.defaults.screencapture.show-thumbnail = mkOption { system.defaults.screencapture.show-thumbnail = mkOption {
type = types.nullOr types.bool; type = types.nullOr types.bool;
default = null; default = null;

View file

@ -105,19 +105,29 @@ in
${concatMapStringsSep "\n" (attr: launchdActivation "LaunchAgents" attr.target) launchAgents} ${concatMapStringsSep "\n" (attr: launchdActivation "LaunchAgents" attr.target) launchAgents}
${concatMapStringsSep "\n" (attr: launchdActivation "LaunchDaemons" attr.target) launchDaemons} ${concatMapStringsSep "\n" (attr: launchdActivation "LaunchDaemons" attr.target) launchDaemons}
for f in $(ls /run/current-system/Library/LaunchAgents 2> /dev/null); do for f in /run/current-system/Library/LaunchAgents/*; do
if test ! -e "${cfg.build.launchd}/Library/LaunchAgents/$f"; then [[ -e "$f" ]] || break # handle when directory is empty
echo "removing service $(basename $f .plist)" >&2 f=''${f#/run/current-system/Library/LaunchAgents/}
if [[ ! -e "${cfg.build.launchd}/Library/LaunchAgents/$f" ]]; then
echo "removing service $(basename "$f" .plist)" >&2
launchctl unload "/Library/LaunchAgents/$f" || true launchctl unload "/Library/LaunchAgents/$f" || true
if test -e "/Library/LaunchAgents/$f"; then rm -f "/Library/LaunchAgents/$f"; fi if [[ -e "/Library/LaunchAgents/$f" ]]; then
rm -f "/Library/LaunchAgents/$f"
fi
fi fi
done done
for f in $(ls /run/current-system/Library/LaunchDaemons 2> /dev/null); do for f in /run/current-system/Library/LaunchDaemons/*; do
if test ! -e "${cfg.build.launchd}/Library/LaunchDaemons/$f"; then [[ -e "$f" ]] || break # handle when directory is empty
echo "removing service $(basename $f .plist)" >&2 f=''${f#/run/current-system/Library/LaunchDaemons/}
if [[ ! -e "${cfg.build.launchd}/Library/LaunchDaemons/$f" ]]; then
echo "removing service $(basename "$f" .plist)" >&2
launchctl unload "/Library/LaunchDaemons/$f" || true launchctl unload "/Library/LaunchDaemons/$f" || true
if test -e "/Library/LaunchDaemons/$f"; then rm -f "/Library/LaunchDaemons/$f"; fi if [[ -e "/Library/LaunchDaemons/$f" ]]; then
rm -f "/Library/LaunchDaemons/$f"
fi
fi fi
done done
''; '';
@ -133,11 +143,16 @@ in
''} ''}
${concatMapStringsSep "\n" (attr: userLaunchdActivation attr.target) userLaunchAgents} ${concatMapStringsSep "\n" (attr: userLaunchdActivation attr.target) userLaunchAgents}
for f in $(ls /run/current-system/user/Library/LaunchAgents 2> /dev/null); do for f in /run/current-system/user/Library/LaunchAgents/*; do
if test ! -e "${cfg.build.launchd}/user/Library/LaunchAgents/$f"; then [[ -e "$f" ]] || break # handle when directory is empty
echo "removing user service $(basename $f .plist)" >&2 f=''${f#/run/current-system/user/Library/LaunchAgents/}
launchctl unload ~/Library/LaunchAgents/$f || true
if test -e ~/Library/LaunchAgents/$f; then rm -f ~/Library/LaunchAgents/$f; fi if [[ ! -e "${cfg.build.launchd}/user/Library/LaunchAgents/$f" ]]; then
echo "removing user service $(basename "$f" .plist)" >&2
launchctl unload ~/Library/LaunchAgents/"$f" || true
if [[ -e ~/Library/LaunchAgents/"$f" ]]; then
rm -f ~/Library/LaunchAgents/"$f"
fi
fi fi
done done
''; '';

View file

@ -30,9 +30,9 @@ in
Set of patches to apply to {file}`/`. Set of patches to apply to {file}`/`.
::: {.warning} ::: {.warning}
This can modify everything so use with caution. This can modify everything so use with caution.
::: :::
Useful for safely changing system files. Unlike the etc module this Useful for safely changing system files. Unlike the etc module this
@ -56,10 +56,13 @@ in
# Applying patches to /. # Applying patches to /.
echo "applying patches..." >&2 echo "applying patches..." >&2
for f in $(ls /run/current-system/patches 2> /dev/null); do for f in /run/current-system/patches/*; do
if test ! -e "${config.system.build.patches}/patches/$f"; then [[ -e "$f" ]] || break # handle when directory is empty
patch --force --reverse --backup -d / -p1 < "/run/current-system/patches/$f" || true f=''${f#/run/current-system/patches/}
fi
if [[ ! -e "${config.system.build.patches}/patches/$f" ]]; then
patch --force --reverse --backup -d / -p1 < "/run/current-system/patches/$f" || true
fi
done done
${concatMapStringsSep "\n" (f: '' ${concatMapStringsSep "\n" (f: ''

View file

@ -14,9 +14,15 @@ in
example = literalExpression "[ pkgs.bashInteractive pkgs.zsh ]"; example = literalExpression "[ pkgs.bashInteractive pkgs.zsh ]";
description = '' description = ''
A list of permissible login shells for user accounts. A list of permissible login shells for user accounts.
No need to mention `/bin/sh`
and other shells that are available by default on The default macOS shells will be automatically included:
macOS. - /bin/bash
- /bin/csh
- /bin/dash
- /bin/ksh
- /bin/sh
- /bin/tcsh
- /bin/zsh
''; '';
apply = map (v: if types.shellPackage.check v then "/run/current-system/sw${v.shellPath}" else v); apply = map (v: if types.shellPackage.check v then "/run/current-system/sw${v.shellPath}" else v);
}; };

View file

@ -7,7 +7,7 @@ let
cfg = config.time; cfg = config.time;
timeZone = optionalString (cfg.timeZone != null) '' timeZone = optionalString (cfg.timeZone != null) ''
if [ -z $(systemsetup -listtimezones | grep "^ ${cfg.timeZone}$") ]; then 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 echo "${cfg.timeZone} is not a valid timezone. The command 'listtimezones' will show a list of valid time zones." >&2
false false
fi fi

View file

@ -1,14 +1,16 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
with lib;
let let
inherit (lib) concatStringsSep concatMapStringsSep elem escapeShellArg
escapeShellArgs filter filterAttrs flatten flip mapAttrs' mapAttrsToList
mkAfter mkIf mkMerge mkOption mkOrder mkRemovedOptionModule optionals
optionalString types;
cfg = config.users; cfg = config.users;
group = import ./group.nix; group = import ./group.nix;
user = import ./user.nix; user = import ./user.nix;
toArguments = concatMapStringsSep " " (v: "'${v}'");
toGID = v: { "${toString v.gid}" = v.name; }; toGID = v: { "${toString v.gid}" = v.name; };
toUID = v: { "${toString v.uid}" = v.name; }; toUID = v: { "${toString v.uid}" = v.name; };
@ -32,9 +34,19 @@ let
then "/run/current-system/sw${v.shellPath}" then "/run/current-system/sw${v.shellPath}"
else v; else v;
systemShells =
let
shells = mapAttrsToList (_: u: u.shell) cfg.users;
in
filter types.shellPackage.check shells;
in in
{ {
imports = [
(mkRemovedOptionModule [ "users" "forceRecreate" ] "")
];
options = { options = {
users.knownGroups = mkOption { users.knownGroups = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
@ -79,62 +91,185 @@ in
type = types.attrsOf types.str; type = types.attrsOf types.str;
default = {}; default = {};
}; };
users.forceRecreate = mkOption {
internal = true;
type = types.bool;
default = false;
description = "Remove and recreate existing groups/users.";
};
}; };
config = { config = {
assertions = [
{
# We don't check `root` like the rest of the users as on some systems `root`'s
# home directory is set to `/var/root /private/var/root`
assertion = cfg.users ? root -> (cfg.users.root.home == null || cfg.users.root.home == "/var/root");
message = "`users.users.root.home` must be set to either `null` or `/var/root`.";
}
{
assertion = !builtins.elem "root" deletedUsers;
message = "Remove `root` from `users.knownUsers` if you no longer want nix-darwin to manage it.";
}
] ++ flatten (flip mapAttrsToList cfg.users (name: user:
map (shell: {
assertion = let
s = user.shell.pname or null;
in
!user.ignoreShellProgramCheck -> (s == shell || (shell == "bash" && s == "bash-interactive")) -> (config.programs.${shell}.enable == true);
message = ''
users.users.${user.name}.shell is set to ${shell}, but
programs.${shell}.enable is not true. This will cause the ${shell}
shell to lack the basic Nix directories in its PATH and might make
logging in as that user impossible. You can fix it with:
programs.${shell}.enable = true;
If you know what you're doing and you are fine with the behavior,
set users.users.${user.name}.ignoreShellProgramCheck = true;
instead.
'';
}) [
"bash"
"fish"
"zsh"
]
));
warnings = flatten (flip mapAttrsToList cfg.users (name: user:
mkIf
(user.shell.pname or null == "bash")
"Set `users.users.${name}.shell = pkgs.bashInteractive;` instead of `pkgs.bash` as it does not include `readline`."
));
users.gids = mkMerge gids; users.gids = mkMerge gids;
users.uids = mkMerge uids; users.uids = mkMerge uids;
# NOTE: We put this in `system.checks` as we want this to run first to avoid partial activations
# however currently that runs at user level activation as that runs before system level activation
# TODO: replace `$USER` with `$SUDO_USER` when system.checks runs from system level
system.checks.text = mkIf (builtins.length (createdUsers ++ deletedUsers) > 0) (mkAfter ''
ensurePerms() {
homeDirectory=$(dscl . -read /Users/nobody NFSHomeDirectory)
homeDirectory=''${homeDirectory#NFSHomeDirectory: }
if ! sudo dscl . -change /Users/nobody NFSHomeDirectory "$homeDirectory" "$homeDirectory" &> /dev/null; then
if [[ -n "$SSH_CONNECTION" ]]; then
printf >&2 '\e[1;31merror: users cannot be %s over SSH without Full Disk Access, aborting activation\e[0m\n' "$2"
# shellcheck disable=SC2016
printf >&2 'The user %s could not be %s as `darwin-rebuild` was not executed with Full Disk Access over SSH.\n' "$1" "$2"
printf >&2 'You can either:\n'
printf >&2 '\n'
printf >&2 ' grant Full Disk Access to all programs run over SSH\n'
printf >&2 '\n'
printf >&2 'or\n'
printf >&2 '\n'
# shellcheck disable=SC2016
printf >&2 ' run `darwin-rebuild` in a graphical session.\n'
printf >&2 '\n'
printf >&2 'The option "Allow full disk access for remote users" can be found by\n'
printf >&2 'navigating to System Settings > General > Sharing > Remote Login\n'
printf >&2 'and then pressing on the i icon next to the switch.\n'
exit 1
else
# The TCC service required to change home directories is `kTCCServiceSystemPolicySysAdminFiles`
# and we can reset it to ensure the user gets another prompt
tccutil reset SystemPolicySysAdminFiles > /dev/null
if ! sudo dscl . -change /Users/nobody NFSHomeDirectory "$homeDirectory" "$homeDirectory" &> /dev/null; then
printf >&2 '\e[1;31merror: permission denied when trying to %s user %s, aborting activation\e[0m\n' "$2" "$1"
# shellcheck disable=SC2016
printf >&2 '`darwin-rebuild` requires permissions to administrate your computer,\n'
printf >&2 'please accept the dialog that pops up.\n'
printf >&2 '\n'
# shellcheck disable=SC2016
printf >&2 'If you do not wish to be prompted every time `darwin-rebuild updates your users,\n'
printf >&2 'you can grant Full Disk Access to your terminal emulator in System Settings.\n'
printf >&2 '\n'
printf >&2 'This can be found in System Settings > Privacy & Security > Full Disk Access.\n'
exit 1
fi
fi
fi
}
${concatMapStringsSep "\n" (v: let
name = escapeShellArg v.name;
dsclUser = escapeShellArg "/Users/${v.name}";
in ''
u=$(id -u ${name} 2> /dev/null) || true
if ! [[ -n "$u" && "$u" -ne "${toString v.uid}" ]]; then
if [ -z "$u" ]; then
ensurePerms ${name} create
${optionalString (v.home != null && v.name != "root") ''
else
homeDirectory=$(dscl . -read ${dsclUser} NFSHomeDirectory)
homeDirectory=''${homeDirectory#NFSHomeDirectory: }
if [[ ${escapeShellArg v.home} != "$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'
printf >&2 'Please set:\n'
printf >&2 '\n'
printf >&2 ' users.users.%s.home = "%s";\n' ${name} "$homeDirectory"
printf >&2 '\n'
printf >&2 'or remove it from your configuration.\n'
exit 1
fi
''}
fi
fi
'') createdUsers}
${concatMapStringsSep "\n" (v: let
name = escapeShellArg v;
in ''
u=$(id -u ${name} 2> /dev/null) || true
if [ -n "$u" ]; then
if [ "$u" -gt 501 ]; then
# TODO: add `darwin.primaryUser` as well
if [[ ${name} == "$USER" ]]; then
# shellcheck disable=SC2016
printf >&2 '\e[1;31merror: refusing to delete the user calling `darwin-rebuild` (%s), aborting activation\e[0m\n', ${name}
exit 1
fi
ensurePerms ${name} delete
fi
fi
'') deletedUsers}
'');
system.activationScripts.groups.text = mkIf (cfg.knownGroups != []) '' system.activationScripts.groups.text = mkIf (cfg.knownGroups != []) ''
echo "setting up groups..." >&2 echo "setting up groups..." >&2
${concatMapStringsSep "\n" (v: '' ${concatMapStringsSep "\n" (v: let
${optionalString cfg.forceRecreate '' dsclGroup = escapeShellArg "/Groups/${v.name}";
g=$(dscl . -read '/Groups/${v.name}' PrimaryGroupID 2> /dev/null) || true in ''
g=''${g#PrimaryGroupID: } g=$(dscl . -read ${dsclGroup} PrimaryGroupID 2> /dev/null) || true
if [[ "$g" -eq ${toString v.gid} ]]; then
echo "deleting group ${v.name}..." >&2
dscl . -delete '/Groups/${v.name}' 2> /dev/null
else
echo "warning: existing group '${v.name}' has unexpected gid $g, skipping..." >&2
fi
''}
g=$(dscl . -read '/Groups/${v.name}' PrimaryGroupID 2> /dev/null) || true
g=''${g#PrimaryGroupID: } g=''${g#PrimaryGroupID: }
if [ -z "$g" ]; then if [ -z "$g" ]; then
echo "creating group ${v.name}..." >&2 echo "creating group ${v.name}..." >&2
dscl . -create '/Groups/${v.name}' PrimaryGroupID ${toString v.gid} dscl . -create ${dsclGroup} PrimaryGroupID ${toString v.gid}
dscl . -create '/Groups/${v.name}' RealName '${v.description}' dscl . -create ${dsclGroup} RealName ${escapeShellArg v.description}
g=${toString v.gid} g=${toString v.gid}
fi fi
if [ "$g" -eq ${toString v.gid} ]; then if [ "$g" -eq ${toString v.gid} ]; then
g=$(dscl . -read '/Groups/${v.name}' GroupMembership 2> /dev/null) || true g=$(dscl . -read ${dsclGroup} GroupMembership 2> /dev/null) || true
if [ "$g" != 'GroupMembership: ${concatStringsSep " " v.members}' ]; then if [ "$g" != 'GroupMembership: ${concatStringsSep " " v.members}' ]; then
echo "updating group members ${v.name}..." >&2 echo "updating group members ${v.name}..." >&2
dscl . -create '/Groups/${v.name}' GroupMembership ${toArguments v.members} dscl . -create ${dsclGroup} GroupMembership ${escapeShellArgs v.members}
fi fi
else else
echo "warning: existing group '${v.name}' has unexpected gid $g, skipping..." >&2 echo "warning: existing group '${v.name}' has unexpected gid $g, skipping..." >&2
fi fi
'') createdGroups} '') createdGroups}
${concatMapStringsSep "\n" (name: '' ${concatMapStringsSep "\n" (name: let
g=$(dscl . -read '/Groups/${name}' PrimaryGroupID 2> /dev/null) || true dsclGroup = escapeShellArg "/Groups/${name}";
in ''
g=$(dscl . -read ${dsclGroup} PrimaryGroupID 2> /dev/null) || true
g=''${g#PrimaryGroupID: } g=''${g#PrimaryGroupID: }
if [ -n "$g" ]; then if [ -n "$g" ]; then
if [ "$g" -gt 501 ]; then if [ "$g" -gt 501 ]; then
echo "deleting group ${name}..." >&2 echo "deleting group ${name}..." >&2
dscl . -delete '/Groups/${name}' 2> /dev/null dscl . -delete ${dsclGroup}
else else
echo "warning: existing group '${name}' has unexpected gid $g, skipping..." >&2 echo "warning: existing group '${name}' has unexpected gid $g, skipping..." >&2
fi fi
@ -145,44 +280,51 @@ in
system.activationScripts.users.text = mkIf (cfg.knownUsers != []) '' system.activationScripts.users.text = mkIf (cfg.knownUsers != []) ''
echo "setting up users..." >&2 echo "setting up users..." >&2
${concatMapStringsSep "\n" (v: '' ${concatMapStringsSep "\n" (v: let
${optionalString cfg.forceRecreate '' name = escapeShellArg v.name;
u=$(dscl . -read '/Users/${v.name}' UniqueID 2> /dev/null) || true dsclUser = escapeShellArg "/Users/${v.name}";
u=''${u#UniqueID: } in ''
if [[ "$u" -eq ${toString v.uid} ]]; then u=$(id -u ${name} 2> /dev/null) || true
echo "deleting user ${v.name}..." >&2
dscl . -delete '/Users/${v.name}' 2> /dev/null
else
echo "warning: existing user '${v.name}' has unexpected uid $u, skipping..." >&2
fi
''}
u=$(dscl . -read '/Users/${v.name}' UniqueID 2> /dev/null) || true
u=''${u#UniqueID: }
if [[ -n "$u" && "$u" -ne "${toString v.uid}" ]]; then if [[ -n "$u" && "$u" -ne "${toString v.uid}" ]]; then
echo "warning: existing user '${v.name}' has unexpected uid $u, skipping..." >&2 echo "warning: existing user '${v.name}' has unexpected uid $u, skipping..." >&2
else else
if [ -z "$u" ]; then if [ -z "$u" ]; then
echo "creating user ${v.name}..." >&2 echo "creating user ${v.name}..." >&2
dscl . -create '/Users/${v.name}' UniqueID ${toString v.uid}
dscl . -create '/Users/${v.name}' PrimaryGroupID ${toString v.gid} sysadminctl -addUser ${escapeShellArgs ([
dscl . -create '/Users/${v.name}' IsHidden ${if v.isHidden then "1" else "0"} v.name
dscl . -create '/Users/${v.name}' RealName '${v.description}' "-UID" v.uid
dscl . -create '/Users/${v.name}' NFSHomeDirectory '${v.home}' "-GID" v.gid ]
${optionalString v.createHome "createhomedir -cu '${v.name}'"} ++ (optionals (v.description != null) [ "-fullName" v.description ])
++ [ "-home" (if v.home != null then v.home else "/var/empty") ]
++ [ "-shell" (if v.shell != null then shellPath v.shell else "/usr/bin/false") ])} 2> /dev/null
# We need to check as `sysadminctl -addUser` still exits with exit code 0 when there's an error
if ! id ${name} &> /dev/null; then
printf >&2 '\e[1;31merror: failed to create user %s, aborting activation\e[0m\n' ${name}
exit 1
fi
dscl . -create ${dsclUser} IsHidden ${if v.isHidden then "1" else "0"}
# `sysadminctl -addUser` won't create the home directory if we use the `-home`
# flag so we need to do it ourselves
${optionalString (v.home != null && v.createHome) "createhomedir -cu ${name} > /dev/null"}
fi fi
# Always set the shell path, in case it was updated
dscl . -create '/Users/${v.name}' UserShell ${lib.escapeShellArg (shellPath v.shell)} # Update properties on known users to keep them inline with configuration
dscl . -create ${dsclUser} PrimaryGroupID ${toString v.gid}
${optionalString (v.description != null) "dscl . -create ${dsclUser} RealName ${escapeShellArg v.description}"}
${optionalString (v.shell != null) "dscl . -create ${dsclUser} UserShell ${escapeShellArg (shellPath v.shell)}"}
fi fi
'') createdUsers} '') createdUsers}
${concatMapStringsSep "\n" (name: '' ${concatMapStringsSep "\n" (name: ''
u=$(dscl . -read '/Users/${name}' UniqueID 2> /dev/null) || true u=$(id -u ${escapeShellArg name} 2> /dev/null) || true
u=''${u#UniqueID: }
if [ -n "$u" ]; then if [ -n "$u" ]; then
if [ "$u" -gt 501 ]; then if [ "$u" -gt 501 ]; then
echo "deleting user ${name}..." >&2 echo "deleting user ${name}..." >&2
dscl . -delete '/Users/${name}' 2> /dev/null dscl . -delete ${escapeShellArg "/Users/${name}"}
else else
echo "warning: existing user '${name}' has unexpected uid $u, skipping..." >&2 echo "warning: existing user '${name}' has unexpected uid $u, skipping..." >&2
fi fi
@ -190,6 +332,9 @@ in
'') deletedUsers} '') deletedUsers}
''; '';
# Install all the user shells
environment.systemPackages = systemShells;
environment.etc = mapAttrs' (name: { packages, ... }: { environment.etc = mapAttrs' (name: { packages, ... }: {
name = "profiles/per-user/${name}"; name = "profiles/per-user/${name}";
value.source = pkgs.buildEnv { value.source = pkgs.buildEnv {

View file

@ -1,11 +1,12 @@
{ name, lib, ... }: { name, lib, ... }:
with lib;
{ {
options = { options = let
inherit (lib) mkOption types;
in {
name = mkOption { name = mkOption {
type = types.str; type = types.str;
default = name;
description = '' description = ''
The group's name. If undefined, the name of the attribute set The group's name. If undefined, the name of the attribute set
will be used. will be used.
@ -29,10 +30,4 @@ with lib;
description = "The group's description."; description = "The group's description.";
}; };
}; };
config = {
name = mkDefault name;
};
} }

View file

@ -1,11 +1,12 @@
{ name, lib, ... }: { name, lib, ... }:
with lib;
{ {
options = { options = let
inherit (lib) literalExpression mkOption types;
in {
name = mkOption { name = mkOption {
type = types.str; type = types.nonEmptyStr;
default = name;
description = '' description = ''
The name of the user account. If undefined, the name of the The name of the user account. If undefined, the name of the
attribute set will be used. attribute set will be used.
@ -13,12 +14,18 @@ with lib;
}; };
description = mkOption { description = mkOption {
type = types.str; type = types.nullOr types.nonEmptyStr;
default = ""; default = null;
example = "Alice Q. User"; example = "Alice Q. User";
description = '' description = ''
A short description of the user account, typically the A short description of the user account, typically the
user's full name. user's full name.
This defaults to `null` which means, on creation, `sysadminctl`
will pick the description which is usually always {option}`name`.
Using an empty name is not supported and breaks macOS like
making the user not appear in Directory Utility.
''; '';
}; };
@ -46,9 +53,15 @@ with lib;
# }; # };
home = mkOption { home = mkOption {
type = types.path; type = types.nullOr types.path;
default = "/var/empty"; default = null;
description = "The user's home directory."; description = ''
The user's home directory. This defaults to `null`.
When this is set to `null`, if the user has not been created yet,
they will be created with the home directory `/var/empty` to match
the old default.
'';
}; };
createHome = mkOption { createHome = mkOption {
@ -58,10 +71,28 @@ with lib;
}; };
shell = mkOption { shell = mkOption {
type = types.either types.shellPackage types.path; type = types.nullOr (types.either types.shellPackage types.path);
default = "/sbin/nologin"; default = null;
example = literalExpression "pkgs.bashInteractive"; example = literalExpression "pkgs.bashInteractive";
description = "The user's shell."; description = ''
The user's shell. This defaults to `null`.
When this is set to `null`, if the user has not been created yet,
they will be created with the shell `/usr/bin/false` to prevent
interactive login. If the user already exists, the value is
considered managed by macOS and `nix-darwin` will not change it.
'';
};
ignoreShellProgramCheck = mkOption {
type = types.bool;
default = false;
description = ''
By default, nix-darwin will check that programs.SHELL.enable is set to
true if the user has a custom shell specified. If that behavior isn't
required and there are custom overrides in place to make sure that the
shell is functional, set this to true.
'';
}; };
packages = mkOption { packages = mkOption {
@ -75,10 +106,4 @@ with lib;
''; '';
}; };
}; };
config = {
name = mkDefault name;
};
} }

View file

@ -1,147 +0,0 @@
{ stdenv, nix, pkgs, nix-darwin }:
let
nixPath = pkgs.lib.concatStringsSep ":" [
"darwin=${nix-darwin}"
"nixpkgs=${pkgs.path}"
"$HOME/.nix-defexpr/channels"
"/nix/var/nix/profiles/per-user/root/channels"
"$NIX_PATH"
];
in
stdenv.mkDerivation {
name = "darwin-installer";
preferLocalBuild = true;
unpackPhase = ":";
installPhase = ''
mkdir -p $out/bin
echo "$shellHook" > $out/bin/darwin-installer
chmod +x $out/bin/darwin-installer
'';
shellHook = ''
#!${stdenv.shell}
set -e
_PATH=$PATH
export PATH=/nix/var/nix/profiles/default/bin:${nix}/bin:${pkgs.gnused}/bin:${pkgs.openssh}/bin:/usr/bin:/bin:/usr/sbin:/sbin
action=switch
while [ "$#" -gt 0 ]; do
i="$1"; shift 1
case "$i" in
--help)
echo "darwin-installer: [--help] [--check]"
exit
;;
--check)
action=check
;;
esac
done
echo >&2
echo >&2 "Installing nix-darwin..."
echo >&2
config="$HOME/.nixpkgs/darwin-configuration.nix"
if ! test -f "$config"; then
echo "copying example configuration.nix" >&2
mkdir -p "$HOME/.nixpkgs"
cp "${../../modules/examples/simple.nix}" "$config"
chmod u+w "$config"
# Enable nix-daemon service for multi-user installs.
if [ ! -w /nix/var/nix/db ]; then
sed -i 's/# services.nix-daemon.enable/services.nix-daemon.enable/' "$config"
fi
fi
# Skip when stdin is not a tty, eg.
# $ yes | darwin-installer
if test -t 0; then
read -p "Would you like to edit the default configuration.nix before starting? [y/N] " i
case "$i" in
y|Y)
PATH=$_PATH ''${EDITOR:-nano} "$config"
;;
esac
fi
i=y
darwinPath=$(NIX_PATH=$HOME/.nix-defexpr/channels nix-instantiate --eval -E '<darwin>' 2> /dev/null) || true
if ! test -e "$darwinPath"; then
if test -t 0; then
read -p "Would you like to manage <darwin> with nix-channel? [y/N] " i
fi
case "$i" in
y|Y)
nix-channel --add https://github.com/LnL7/nix-darwin/archive/master.tar.gz darwin
nix-channel --update
;;
esac
fi
export NIX_PATH=${nixPath}
system=$(nix-build '<darwin>' -I "darwin-config=$config" -A system --no-out-link --show-trace)
export PATH=$system/sw/bin:$PATH
darwin-rebuild "$action" -I "darwin-config=$config"
echo >&2
echo >&2 " Open '$config' to get started."
echo >&2 " See the README for more information: https://github.com/LnL7/nix-darwin/blob/master/README.md"
echo >&2
echo >&2 " Don't forget to start a new shell or source /etc/static/bashrc."
echo >&2
exit
'';
passthru.check = stdenv.mkDerivation {
name = "run-darwin-test";
shellHook = ''
set -e
echo >&2 "running installer tests..."
echo >&2
echo >&2 "checking configuration.nix"
test -f ~/.nixpkgs/darwin-configuration.nix
test -w ~/.nixpkgs/darwin-configuration.nix
echo >&2 "checking darwin channel"
readlink ~/.nix-defexpr/channels/darwin
test -e ~/.nix-defexpr/channels/darwin
echo >&2 "checking /etc"
readlink /etc/static
test -e /etc/static
echo >&2 "checking profile"
cat /etc/profile
grep -v nix-daemon.sh /etc/profile
echo >&2 "checking /run/current-system"
readlink /run
test -e /run
readlink /run/current-system
test -e /run/current-system
echo >&2 "checking system profile"
readlink /nix/var/nix/profiles/system
test -e /nix/var/nix/profiles/system
echo >&2 "checking bash environment"
env -i USER=john HOME=/Users/john bash -li -c 'echo $PATH'
env -i USER=john HOME=/Users/john bash -li -c 'echo $PATH' | grep /Users/john/.nix-profile/bin:/run/current-system/sw/bin:/nix/var/nix/profiles/default/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin
env -i USER=john HOME=/Users/john bash -li -c 'echo $NIX_PATH'
env -i USER=john HOME=/Users/john bash -li -c 'echo $NIX_PATH' | grep darwin-config=/Users/john/.nixpkgs/darwin-configuration.nix:/nix/var/nix/profiles/per-user/root/channels
echo >&2 "checking zsh environment"
env -i USER=john HOME=/Users/john zsh -l -c 'echo $PATH'
env -i USER=john HOME=/Users/john zsh -l -c 'echo $PATH' | grep /Users/john/.nix-profile/bin:/run/current-system/sw/bin:/nix/var/nix/profiles/default/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin
env -i USER=john HOME=/Users/john zsh -l -c 'echo $NIX_PATH'
env -i USER=john HOME=/Users/john zsh -l -c 'echo $NIX_PATH' | grep darwin-config=/Users/john/.nixpkgs/darwin-configuration.nix:/nix/var/nix/profiles/per-user/root/channels
echo >&2 ok
exit
'';
};
}

View file

@ -1,4 +1,4 @@
{ lib, ... }: { lib, pkgs, ... }:
with lib; with lib;
@ -7,46 +7,49 @@ with lib;
assertions = mkForce []; assertions = mkForce [];
system.activationScripts.checks.text = mkForce ""; system.activationScripts.checks.text = mkForce "";
# Disable etc, launchd, ...
environment.etc = mkForce {}; environment.etc = mkForce {};
launchd.agents = mkForce {}; launchd.agents = mkForce {};
launchd.daemons = mkForce {}; launchd.daemons = mkForce {};
launchd.user.agents = mkForce {}; launchd.user.agents = mkForce {};
# Don't try to reload `nix-daemon`
nix.useDaemon = mkForce false;
system.activationScripts.postUserActivation.text = mkAfter '' system.activationScripts.postUserActivation.text = mkAfter ''
if test -L ~/.nix-defexpr/channels/darwin; then if [[ -L ~/.nix-defexpr/channels/darwin ]]; then
nix-channel --remove darwin || true nix-channel --remove darwin || true
fi fi
''; '';
system.activationScripts.postActivation.text = mkAfter '' system.activationScripts.postActivation.text = mkAfter ''
if test -L /Applications/Nix\ Apps; then if [[ -L /Applications/Nix\ Apps ]]; then
rm /Applications/Nix\ Apps rm /Applications/Nix\ Apps
fi fi
if test -L /etc/static; then if [[ -L /etc/static ]]; then
rm /etc/static rm /etc/static
fi fi
if test -O /nix/store; then # If the Nix Store is owned by root then we're on a multi-user system
if ! test -e /Library/LaunchDaemons/org.nixos.nix-daemon.plist; then if [[ -O /nix/store ]]; then
sudo rm /Library/LaunchDaemons/org.nixos.nix-daemon.plist || true if [[ -e /nix/var/nix/profiles/default/Library/LaunchDaemons/org.nixos.nix-daemon.plist ]]; then
sudo launchctl remove org.nixos.nix-daemon 2> /dev/null || true
sudo cp /nix/var/nix/profiles/default/Library/LaunchDaemons/org.nixos.nix-daemon.plist /Library/LaunchDaemons/org.nixos.nix-daemon.plist sudo cp /nix/var/nix/profiles/default/Library/LaunchDaemons/org.nixos.nix-daemon.plist /Library/LaunchDaemons/org.nixos.nix-daemon.plist
sudo launchctl load -w /Library/LaunchDaemons/org.nixos.nix-daemon.plist sudo launchctl load -w /Library/LaunchDaemons/org.nixos.nix-daemon.plist
fi fi
if ! grep -q etc/profile.d/nix-daemon.sh /etc/bashrc; then
echo >&2 "Found no nix-daemon.sh reference in /etc/bashrc"
echo >&2 "add this snippet back to /etc/bashrc:"
echo >&2
echo >&2 " # Nix"
echo >&2 " if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then"
echo >&2 " . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'"
echo >&2 " fi"
echo >&2 " # End Nix"
echo >&2
fi
fi fi
# grep will return 1 when no lines matched which makes this line fail with `set -eo pipefail`
dscl . -list /Users UserShell | { grep "\s/run/" || true; } | awk '{print $1}' | while read -r user; do
shell=$(dscl . -read /Users/"$user" UserShell)
if [[ "$shell" != */bin/zsh ]]; then
echo >&2 "warning: changing $user's shell from $shell to /bin/zsh"
fi
dscl . -create /Users/"$user" UserShell /bin/zsh
done
while IFS= read -r -d "" file; do
mv "$file" "''${file%.*}"
done < <(find /etc -name '*.before-nix-darwin' -follow -print0)
''; '';
} }

View file

@ -1,4 +1,4 @@
{ stdenv, lib, pkgs }: { lib, path, stdenv, writeShellApplication }:
let let
uninstallSystem = import ../../eval-config.nix { uninstallSystem = import ../../eval-config.nix {
@ -6,39 +6,23 @@ let
modules = [ modules = [
./configuration.nix ./configuration.nix
{ {
nixpkgs.source = pkgs.path; nixpkgs.source = path;
nixpkgs.hostPlatform = pkgs.stdenv.hostPlatform.system; nixpkgs.hostPlatform = stdenv.hostPlatform.system;
system.includeUninstaller = false; system.includeUninstaller = false;
} }
]; ];
}; };
in in writeShellApplication {
stdenv.mkDerivation {
name = "darwin-uninstaller"; name = "darwin-uninstaller";
preferLocalBuild = true; text = ''
unpackPhase = ":";
installPhase = ''
mkdir -p $out/bin
echo "$shellHook" > $out/bin/darwin-uninstaller
chmod +x $out/bin/darwin-uninstaller
'';
shellHook = ''
#!${stdenv.shell}
set -e
action=switch
while [ "$#" -gt 0 ]; do while [ "$#" -gt 0 ]; do
i="$1"; shift 1 i="$1"; shift 1
case "$i" in case "$i" in
--help) --help)
echo "darwin-uninstaller: [--help]" echo "darwin-uninstaller: [--help]"
exit exit
;; ;;
esac esac
done done
echo >&2 echo >&2
@ -47,54 +31,67 @@ stdenv.mkDerivation {
echo >&2 " - remove /Applications/Nix Apps symlink" echo >&2 " - remove /Applications/Nix Apps symlink"
echo >&2 " - cleanup static /etc files" echo >&2 " - cleanup static /etc files"
echo >&2 " - disable and remove all launchd services managed by nix-darwin" echo >&2 " - disable and remove all launchd services managed by nix-darwin"
echo >&2 " - restore daemon service from nix installer (only when this is a multi-user install)" if [[ $(stat -f '%Su' /nix/store) == "root" ]]; then
echo >&2 " - restore nix-daemon service from nix installer as this is a multi-user install"
fi
echo >&2 echo >&2
if test -t 0; then if [[ -t 0 ]]; then
read -p "Proceed? [y/n] " i read -r -p "Proceed? [y/n] " i
case "$i" in case "$i" in
y|Y) y|Y)
;; ;;
*) *)
exit 3 exit 3
;; ;;
esac esac
fi fi
${uninstallSystem.system}/sw/bin/darwin-rebuild activate ${uninstallSystem.system}/sw/bin/darwin-rebuild activate
if test -L /run/current-system; then if [[ -L /run/current-system ]]; then
sudo rm /run/current-system sudo rm /run/current-system
fi fi
if [[ -L /run ]]; then
if [[ -e /etc/synthetic.conf ]]; then
sudo sed -i -E '/^run[[:space:]]/d' /etc/synthetic.conf
sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -B &>/dev/null || true
sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -t &>/dev/null || true
echo >&2 "NOTE: the /run symlink will be removed on reboot"
else
sudo rm /run
fi
fi
echo >&2 echo >&2
echo >&2 "NOTE: The /nix/var/nix/profiles/system* profiles still exist and won't be garbage collected." echo >&2 "NOTE: The /nix/var/nix/profiles/system* profiles still exist and won't be garbage collected."
echo >&2 echo >&2
echo >&2 "Done!" echo >&2 "Done!"
echo >&2 echo >&2
exit
''; '';
passthru.check = stdenv.mkDerivation { derivationArgs.passthru.tests.uninstaller = writeShellApplication {
name = "run-darwin-test"; name = "post-uninstall-test";
shellHook = '' text = ''
set -e echo >&2 "running uninstaller tests..."
echo >&2 "running uninstaller tests..." echo >&2
echo >&2
echo >&2 "checking darwin channel" echo >&2 "checking darwin channel"
! test -e ~/.nix-defexpr/channels/darwin test -e ~/.nix-defexpr/channels/darwin && exit 1
echo >&2 "checking /etc" echo >&2 "checking /etc"
! test -e /etc/static test -e /etc/static && exit 1
echo >&2 "checking /run/current-system" echo >&2 "checking /run/current-system"
! test -e /run/current-system test -e /run/current-system && exit 1
echo >&2 "checking nix-daemon service (assuming a multi-user install)" if [[ $(stat -f '%Su' /nix/store) == "root" ]]; then
sudo launchctl list | grep org.nixos.nix-daemon || echo "FIXME? sudo launchctl list | grep org.nixos.nix-daemon" echo >&2 "checking nix-daemon service"
pgrep -l nix-daemon || echo "FIXME? pgrep -l nix-daemon" launchctl print system/org.nixos.nix-daemon
readlink /Library/LaunchDaemons/org.nixos.nix-daemon.plist || echo "FIXME? readlink /Library/LaunchDaemons/org.nixos.nix-daemon.plist" pgrep -l nix-daemon
grep /nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt /Library/LaunchDaemons/org.nixos.nix-daemon.plist || echo "FIXME? grep /nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt /Library/LaunchDaemons/org.nixos.nix-daemon.plist" test -e /Library/LaunchDaemons/org.nixos.nix-daemon.plist
echo >&2 ok [[ "$(shasum -a 256 /Library/LaunchDaemons/org.nixos.nix-daemon.plist | awk '{print $1}')" == "$(shasum -a 256 /Library/LaunchDaemons/org.nixos.nix-daemon.plist | awk '{print $1}')" ]]
exit nix-store --store daemon -q --hash ${stdenv.shell}
fi
echo >&2 ok
''; '';
}; };
} }

View file

@ -9,17 +9,25 @@ showSyntax() {
echo " [--list-generations] [{--profile-name | -p} name] [--rollback]" >&2 echo " [--list-generations] [{--profile-name | -p} name] [--rollback]" >&2
echo " [{--switch-generation | -G} generation] [--verbose...] [-v...]" >&2 echo " [{--switch-generation | -G} generation] [--verbose...] [-v...]" >&2
echo " [-Q] [{--max-jobs | -j} number] [--cores number] [--dry-run]" >&2 echo " [-Q] [{--max-jobs | -j} number] [--cores number] [--dry-run]" >&2
echo " [--keep-going] [-k] [--keep-failed] [-K] [--fallback] [--show-trace]" >&2 echo " [--keep-going | -k] [--keep-failed | -K] [--fallback] [--show-trace]" >&2
echo " [-I path] [--option name value] [--arg name value] [--argstr name value]" >&2 echo " [--print-build-logs | -L] [--impure] [-I path]" >&2
echo " [--flake flake] [--no-flake] [--update-input input flake] [--impure]" >&2 echo " [--option name value] [--arg name value] [--argstr name value]" >&2
echo " [--recreate-lock-file] [--no-update-lock-file] [--refresh]" >&2 echo " [--no-flake | [--flake flake]" >&2
echo " [--offline] [--substituters substituters-list] ..." >&2 echo " [--commit-lock-file] [--recreate-lock-file]" >&2
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
exit 1 exit 1
} }
sudo() { sudo() {
# REMOVEME when support for macOS 10.13 is dropped
# macOS 10.13 does not support sudo --preserve-env so we make this conditional
if command sudo --help | grep -- --preserve-env= >/dev/null; then if command sudo --help | grep -- --preserve-env= >/dev/null; then
command sudo -H --preserve-env=PATH env "$@" # We use `env` before our command to ensure the preserved PATH gets checked
# when trying to resolve the command to execute
command sudo -H --preserve-env=PATH --preserve-env=SSH_CONNECTION env "$@"
else else
command sudo -H "$@" command sudo -H "$@"
fi fi
@ -149,43 +157,17 @@ fi
# For convenience, use the hostname as the default configuration to # For convenience, use the hostname as the default configuration to
# build from the flake. # build from the flake.
if [ -n "$flake" ]; then if [[ -n "$flake" ]]; then
# Offical regex from https://www.rfc-editor.org/rfc/rfc3986#appendix-B if [[ $flake =~ ^(.*)\#([^\#\"]*)$ ]]; then
if [[ "${flake}" =~ ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? ]]; then flake="${BASH_REMATCH[1]}"
scheme=${BASH_REMATCH[1]} # eg. http: flakeAttr="${BASH_REMATCH[2]}"
authority=${BASH_REMATCH[3]} # eg. //www.ics.uci.edu
path=${BASH_REMATCH[5]} # eg. /pub/ietf/uri/
queryWithQuestion=${BASH_REMATCH[6]}
fragment=${BASH_REMATCH[9]}
flake=${scheme}${authority}${path}${queryWithQuestion}
flakeAttr=${fragment}
fi fi
if [ -z "$flakeAttr" ]; then if [[ -z "$flakeAttr" ]]; then
flakeAttr=$(scutil --get LocalHostName) flakeAttr=$(scutil --get LocalHostName)
fi fi
flakeAttr=darwinConfigurations.${flakeAttr} flakeAttr=darwinConfigurations.${flakeAttr}
fi fi
if [ -n "$flake" ]; then
if nix "${flakeFlags[@]}" flake metadata --version &>/dev/null; then
cmd=metadata
else
cmd=info
fi
metadata=$(nix "${flakeFlags[@]}" flake "$cmd" --json "${extraMetadataFlags[@]}" "${extraLockFlags[@]}" -- "$flake")
flake=$(jq -r .url <<<"${metadata}")
if [ "$(jq -r .resolved.submodules <<<"${metadata}")" = "true" ]; then
if [[ "$flake" == *'?'* ]]; then
flake="${flake}&submodules=1"
else
flake="${flake}?submodules=1"
fi
fi
fi
if [ "$action" != build ]; then if [ "$action" != build ]; then
if [ -n "$flake" ]; then if [ -n "$flake" ]; then
extraBuildFlags+=("--no-link") extraBuildFlags+=("--no-link")

View file

@ -17,6 +17,7 @@ let
inherit name src; inherit name src;
dir = "bin"; dir = "bin";
isExecutable = true; isExecutable = true;
meta.mainProgram = name;
} // env); } // env);
path = "${extraPath}:${systemPath}"; path = "${extraPath}:${systemPath}";

View file

@ -1,21 +1,16 @@
{ nixpkgs ? <nixpkgs> { nixpkgs ? <nixpkgs>
, supportedSystems ? [ "x86_64-darwin" ] # Adapted from https://github.com/NixOS/nixpkgs/blob/e818264fe227ad8861e0598166cf1417297fdf54/pkgs/top-level/release.nix#L11
, nix-darwin ? { }
, system ? builtins.currentSystem
, supportedSystems ? [ "x86_64-darwin" "aarch64-darwin" ]
, scrubJobs ? true , scrubJobs ? true
}: }:
let let
inherit (release) mapTestOn packagePlatforms pkgs all linux darwin;
system = "x86_64-darwin";
mapPlatforms = systems: pkgs.lib.mapAttrs (n: v: systems);
buildFromConfig = configuration: sel: sel buildFromConfig = configuration: sel: sel
(import ./. { inherit nixpkgs configuration system; }).config; (import ./. { inherit nixpkgs configuration system; }).config;
makeSystem = configuration: pkgs.lib.genAttrs [ system ] (system: makeSystem = configuration: buildFromConfig configuration (config: config.system.build.toplevel);
buildFromConfig configuration (config: config.system.build.toplevel)
);
makeTest = test: makeTest = test:
let let
@ -61,103 +56,76 @@ let
in in
buildFromConfig configuration (config: config.system.build.run-test); buildFromConfig configuration (config: config.system.build.run-test);
release = import <nixpkgs/pkgs/top-level/release-lib.nix> {
inherit supportedSystems scrubJobs;
packageSet = import nixpkgs;
};
packageSet = {
inherit (pkgs)
stdenv bash zsh nix
tmux reattach-to-user-namespace
nano emacs vim;
};
manual = buildFromConfig ({ lib, config, ... }: { manual = buildFromConfig ({ lib, config, ... }: {
system.stateVersion = lib.mkDefault config.system.maxStateVersion; system.stateVersion = lib.mkDefault config.system.maxStateVersion;
system.darwinVersionSuffix = let
shortRev = nix-darwin.shortRev or nix-darwin.dirtyShortRev or null;
in
lib.mkIf (shortRev != null) ".${shortRev}";
system.darwinRevision = let
rev = nix-darwin.rev or nix-darwin.dirtyRev or null;
in
lib.mkIf (rev != null) rev;
}) (config: config.system.build.manual); }) (config: config.system.build.manual);
jobs = { in {
docs = {
inherit (manual) manualHTML manpages optionsJSON;
};
unstable = pkgs.releaseTools.aggregate { examples.hydra = makeSystem ./modules/examples/hydra.nix;
name = "darwin-${pkgs.lib.nixpkgsVersion}"; examples.lnl = makeSystem ./modules/examples/lnl.nix;
constituents = examples.simple = makeSystem ./modules/examples/simple.nix;
[ jobs.stdenv.x86_64-darwin
jobs.bash.x86_64-darwin
jobs.zsh.x86_64-darwin
jobs.nix.x86_64-darwin
jobs.reattach-to-user-namespace.x86_64-darwin
jobs.tmux.x86_64-darwin
jobs.nano.x86_64-darwin
jobs.vim.x86_64-darwin
jobs.emacs.x86_64-darwin
jobs.examples.hydra.x86_64-darwin
jobs.examples.lnl.x86_64-darwin
jobs.examples.simple.x86_64-darwin
];
meta.description = "Release-critical builds for the darwin channel";
};
manualHTML = manual.manualHTML; tests.activation-scripts = makeTest ./tests/activation-scripts.nix;
manpages = manual.manpages; tests.autossh = makeTest ./tests/autossh.nix;
options = manual.optionsJSON; tests.checks-nix-gc = makeTest ./tests/checks-nix-gc.nix;
tests.environment-path = makeTest ./tests/environment-path.nix;
examples.hydra = makeSystem ./modules/examples/hydra.nix; tests.environment-terminfo = makeTest ./tests/environment-terminfo.nix;
examples.lnl = makeSystem ./modules/examples/lnl.nix; tests.homebrew = makeTest ./tests/homebrew.nix;
examples.simple = makeSystem ./modules/examples/simple.nix; tests.launchd-daemons = makeTest ./tests/launchd-daemons.nix;
tests.launchd-setenv = makeTest ./tests/launchd-setenv.nix;
tests.activation-scripts = makeTest ./tests/activation-scripts.nix; tests.networking-hostname = makeTest ./tests/networking-hostname.nix;
tests.autossh = makeTest ./tests/autossh.nix; tests.networking-networkservices = makeTest ./tests/networking-networkservices.nix;
tests.checks-nix-gc = makeTest ./tests/checks-nix-gc.nix; tests.nixpkgs-overlays = makeTest ./tests/nixpkgs-overlays.nix;
tests.environment-path = makeTest ./tests/environment-path.nix; tests.programs-ssh = makeTest ./tests/programs-ssh.nix;
tests.environment-terminfo = makeTest ./tests/environment-terminfo.nix; tests.programs-tmux = makeTest ./tests/programs-tmux.nix;
tests.homebrew = makeTest ./tests/homebrew.nix; tests.programs-zsh = makeTest ./tests/programs-zsh.nix;
tests.launchd-daemons = makeTest ./tests/launchd-daemons.nix; tests.programs-ssh-empty-known-hosts = makeTest ./tests/programs-ssh-empty-known-hosts.nix;
tests.launchd-setenv = makeTest ./tests/launchd-setenv.nix; tests.security-pki = makeTest ./tests/security-pki.nix;
tests.networking-hostname = makeTest ./tests/networking-hostname.nix; tests.services-activate-system = makeTest ./tests/services-activate-system.nix;
tests.networking-networkservices = makeTest ./tests/networking-networkservices.nix; tests.services-activate-system-changed-label-prefix = makeTest ./tests/services-activate-system-changed-label-prefix.nix;
tests.nixpkgs-overlays = makeTest ./tests/nixpkgs-overlays.nix; tests.services-buildkite-agent = makeTest ./tests/services-buildkite-agent.nix;
tests.programs-ssh = makeTest ./tests/programs-ssh.nix; tests.services-github-runners = makeTest ./tests/services-github-runners.nix;
tests.programs-tmux = makeTest ./tests/programs-tmux.nix; tests.services-lorri = makeTest ./tests/services-lorri.nix;
tests.programs-zsh = makeTest ./tests/programs-zsh.nix; tests.services-nix-daemon = makeTest ./tests/services-nix-daemon.nix;
tests.programs-ssh-empty-known-hosts = makeTest ./tests/programs-ssh-empty-known-hosts.nix; tests.sockets-nix-daemon = makeTest ./tests/sockets-nix-daemon.nix;
tests.security-pki = makeTest ./tests/security-pki.nix; tests.services-aerospace = makeTest ./tests/services-aerospace.nix;
tests.services-activate-system = makeTest ./tests/services-activate-system.nix; tests.services-dnsmasq = makeTest ./tests/services-dnsmasq.nix;
tests.services-activate-system-changed-label-prefix = makeTest ./tests/services-activate-system-changed-label-prefix.nix; tests.services-eternal-terminal = makeTest ./tests/services-eternal-terminal.nix;
tests.services-buildkite-agent = makeTest ./tests/services-buildkite-agent.nix; tests.services-nix-gc = makeTest ./tests/services-nix-gc.nix;
tests.services-github-runners = makeTest ./tests/services-github-runners.nix; tests.services-nix-optimise = makeTest ./tests/services-nix-optimise.nix;
tests.services-lorri = makeTest ./tests/services-lorri.nix; tests.services-nextdns = makeTest ./tests/services-nextdns.nix;
tests.services-nix-daemon = makeTest ./tests/services-nix-daemon.nix; tests.services-netdata = makeTest ./tests/services-netdata.nix;
tests.sockets-nix-daemon = makeTest ./tests/sockets-nix-daemon.nix; tests.services-ofborg = makeTest ./tests/services-ofborg.nix;
tests.services-dnsmasq = makeTest ./tests/services-dnsmasq.nix; tests.services-offlineimap = makeTest ./tests/services-offlineimap.nix;
tests.services-eternal-terminal = makeTest ./tests/services-eternal-terminal.nix; tests.services-privoxy = makeTest ./tests/services-privoxy.nix;
tests.services-nix-gc = makeTest ./tests/services-nix-gc.nix; tests.services-redis = makeTest ./tests/services-redis.nix;
tests.services-nix-optimise = makeTest ./tests/services-nix-optimise.nix; tests.services-skhd = makeTest ./tests/services-skhd.nix;
tests.services-nextdns = makeTest ./tests/services-nextdns.nix; tests.services-spacebar = makeTest ./tests/services-spacebar.nix;
tests.services-netdata = makeTest ./tests/services-netdata.nix; tests.services-spotifyd = makeTest ./tests/services-spotifyd.nix;
tests.services-ofborg = makeTest ./tests/services-ofborg.nix; tests.services-synapse-bt = makeTest ./tests/services-synapse-bt.nix;
tests.services-offlineimap = makeTest ./tests/services-offlineimap.nix; tests.services-synergy = makeTest ./tests/services-synergy.nix;
tests.services-privoxy = makeTest ./tests/services-privoxy.nix; tests.services-yabai = makeTest ./tests/services-yabai.nix;
tests.services-redis = makeTest ./tests/services-redis.nix; tests.services-jankyborders = makeTest ./tests/services-jankyborders.nix;
tests.services-skhd = makeTest ./tests/services-skhd.nix; tests.system-defaults-write = makeTest ./tests/system-defaults-write.nix;
tests.services-spacebar = makeTest ./tests/services-spacebar.nix; tests.system-environment = makeTest ./tests/system-environment.nix;
tests.services-spotifyd = makeTest ./tests/services-spotifyd.nix; tests.system-keyboard-mapping = makeTest ./tests/system-keyboard-mapping.nix;
tests.services-synapse-bt = makeTest ./tests/services-synapse-bt.nix; tests.system-packages = makeTest ./tests/system-packages.nix;
tests.services-synergy = makeTest ./tests/services-synergy.nix; tests.system-path = makeTest ./tests/system-path.nix;
tests.services-yabai = makeTest ./tests/services-yabai.nix; tests.system-shells = makeTest ./tests/system-shells.nix;
tests.services-jankyborders = makeTest ./tests/services-jankyborders.nix; tests.users-groups = makeTest ./tests/users-groups.nix;
tests.system-defaults-write = makeTest ./tests/system-defaults-write.nix; tests.users-packages = makeTest ./tests/users-packages.nix;
tests.system-environment = makeTest ./tests/system-environment.nix; tests.fonts = makeTest ./tests/fonts.nix;
tests.system-keyboard-mapping = makeTest ./tests/system-keyboard-mapping.nix; }
tests.system-packages = makeTest ./tests/system-packages.nix;
tests.system-path = makeTest ./tests/system-path.nix;
tests.system-shells = makeTest ./tests/system-shells.nix;
tests.users-groups = makeTest ./tests/users-groups.nix;
tests.users-packages = makeTest ./tests/users-packages.nix;
tests.fonts = makeTest ./tests/fonts.nix;
}
// (mapTestOn (packagePlatforms packageSet));
in
jobs

View file

@ -205,6 +205,11 @@ defaults write .GlobalPreferences 'com.apple.sound.beep.sound' $'<?xml version="
<string>/System/Library/Sounds/Funk.aiff</string> <string>/System/Library/Sounds/Funk.aiff</string>
</plist>' </plist>'
defaults write com.apple.menuextra.clock 'FlashDateSeparators' $'<?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">
<false/>
</plist>'
defaults write com.apple.menuextra.clock 'Show24Hour' $'<?xml version="1.0" encoding="UTF-8"?> defaults write com.apple.menuextra.clock 'Show24Hour' $'<?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"> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
@ -299,6 +304,11 @@ defaults write com.apple.dock 'persistent-others' $'<?xml version="1.0" encoding
</dict> </dict>
</array> </array>
</plist>' </plist>'
defaults write com.apple.dock 'scroll-to-open' $'<?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">
<false/>
</plist>'
defaults write com.apple.finder 'AppleShowAllExtensions' $'<?xml version="1.0" encoding="UTF-8"?> defaults write com.apple.finder 'AppleShowAllExtensions' $'<?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"> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
@ -329,16 +339,51 @@ defaults write com.apple.finder 'FXPreferredViewStyle' $'<?xml version="1.0" enc
<plist version="1.0"> <plist version="1.0">
<string>Flwv</string> <string>Flwv</string>
</plist>' </plist>'
defaults write com.apple.finder 'FXRemoveOldTrashItems' $'<?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">
<false/>
</plist>'
defaults write com.apple.finder 'NewWindowTarget' $'<?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">
<string>PfLo</string>
</plist>'
defaults write com.apple.finder 'NewWindowTargetPath' $'<?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">
<string>file:///Library/Apple</string>
</plist>'
defaults write com.apple.finder 'QuitMenuItem' $'<?xml version="1.0" encoding="UTF-8"?> defaults write com.apple.finder 'QuitMenuItem' $'<?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"> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<true/> <true/>
</plist>' </plist>'
defaults write com.apple.finder 'ShowExternalHardDrivesOnDesktop' $'<?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">
<false/>
</plist>'
defaults write com.apple.finder 'ShowHardDrivesOnDesktop' $'<?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">
<false/>
</plist>'
defaults write com.apple.finder 'ShowMountedServersOnDesktop' $'<?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">
<false/>
</plist>'
defaults write com.apple.finder 'ShowPathbar' $'<?xml version="1.0" encoding="UTF-8"?> defaults write com.apple.finder 'ShowPathbar' $'<?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"> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<true/> <true/>
</plist>' </plist>'
defaults write com.apple.finder 'ShowRemovableMediaOnDesktop' $'<?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">
<false/>
</plist>'
defaults write com.apple.finder 'ShowStatusBar' $'<?xml version="1.0" encoding="UTF-8"?> defaults write com.apple.finder 'ShowStatusBar' $'<?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"> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
@ -354,8 +399,23 @@ defaults write com.apple.finder '_FXSortFoldersFirst' $'<?xml version="1.0" enco
<plist version="1.0"> <plist version="1.0">
<true/> <true/>
</plist>' </plist>'
defaults write com.apple.finder '_FXSortFoldersFirstOnDesktop' $'<?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">
<false/>
</plist>'
defaults write com.apple.HIToolbox 'AppleFnUsageType' $'<?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">
<integer>2</integer>
</plist>'
defaults write com.apple.screencapture 'include-date' $'<?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>'
defaults write com.apple.screencapture 'location' $'<?xml version="1.0" encoding="UTF-8"?> defaults write com.apple.screencapture 'location' $'<?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"> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
@ -474,3 +534,38 @@ defaults write com.apple.WindowManager 'StandardHideWidgets' $'<?xml version="1.
<plist version="1.0"> <plist version="1.0">
<true/> <true/>
</plist>' </plist>'
defaults write ~/Library/Preferences/ByHost/com.apple.controlcenter 'AirDrop' $'<?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">
<integer>18</integer>
</plist>'
defaults write ~/Library/Preferences/ByHost/com.apple.controlcenter 'BatteryShowPercentage' $'<?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>'
defaults write ~/Library/Preferences/ByHost/com.apple.controlcenter 'Bluetooth' $'<?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">
<integer>18</integer>
</plist>'
defaults write ~/Library/Preferences/ByHost/com.apple.controlcenter 'Display' $'<?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">
<integer>24</integer>
</plist>'
defaults write ~/Library/Preferences/ByHost/com.apple.controlcenter 'FocusModes' $'<?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">
<integer>24</integer>
</plist>'
defaults write ~/Library/Preferences/ByHost/com.apple.controlcenter 'NowPlaying' $'<?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">
<integer>18</integer>
</plist>'
defaults write ~/Library/Preferences/ByHost/com.apple.controlcenter 'Sound' $'<?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">
<integer>24</integer>
</plist>'

View file

@ -1,4 +1,4 @@
{ config, pkgs, ... }: { config, lib, ... }:
{ {
networking.knownNetworkServices = [ "Wi-Fi" "Thunderbolt Ethernet" ]; networking.knownNetworkServices = [ "Wi-Fi" "Thunderbolt Ethernet" ];
@ -6,10 +6,10 @@
test = '' test = ''
echo checking dns settings in /activate >&2 echo checking dns settings in /activate >&2
grep "networksetup -setdnsservers 'Wi-Fi' '8.8.8.8' '8.8.4.4'" ${config.out}/activate grep "networksetup -setdnsservers ${lib.escapeShellArgs [ "Wi-Fi" "8.8.8.8" "8.8.4.4" ]}" ${config.out}/activate
grep "networksetup -setdnsservers 'Thunderbolt Ethernet' '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
echo checking empty searchdomain settings in /activate >&2 echo checking empty searchdomain settings in /activate >&2
grep "networksetup -setsearchdomains 'Wi-Fi' 'empty'" ${config.out}/activate grep "networksetup -setsearchdomains ${lib.escapeShellArgs [ "Wi-Fi" "empty" ]}" ${config.out}/activate
grep "networksetup -setsearchdomains 'Thunderbolt Ethernet' 'empty'" ${config.out}/activate grep "networksetup -setsearchdomains ${lib.escapeShellArgs [ "Thunderbolt Ethernet" "empty" ]}" ${config.out}/activate
''; '';
} }

View file

@ -0,0 +1,10 @@
{ config, pkgs, ... }:
{
networking.wakeOnLan.enable = true;
test = ''
echo checking wake on network access settings in /activate >&2
grep "systemsetup -setWakeOnNetworkAccess 'on'" ${config.out}/activate
'';
}

12
tests/power-restart.nix Normal file
View file

@ -0,0 +1,12 @@
{ config, pkgs, ... }:
{
power.restartAfterPowerFailure = true;
power.restartAfterFreeze = true;
test = ''
echo checking restart power settings in /activate >&2
grep "systemsetup -setRestartPowerFailure 'on'" ${config.out}/activate
grep "systemsetup -setRestartFreeze 'on'" ${config.out}/activate
'';
}

16
tests/power-sleep.nix Normal file
View file

@ -0,0 +1,16 @@
{ config, pkgs, ... }:
{
power.sleep.computer = "never";
power.sleep.display = 15;
power.sleep.harddisk = 5;
power.sleep.allowSleepByPowerButton = false;
test = ''
echo checking power sleep settings in /activate >&2
grep "systemsetup -setComputerSleep 'never'" ${config.out}/activate
grep "systemsetup -setDisplaySleep '15'" ${config.out}/activate
grep "systemsetup -setHardDiskSleep '5'" ${config.out}/activate
grep "systemsetup -setAllowPowerButtonToSleepComputer 'off'" ${config.out}/activate
'';
}

View file

@ -34,7 +34,7 @@
echo >&2 "checking compinit in /etc/zshrc" echo >&2 "checking compinit in /etc/zshrc"
grep 'autoload -U compinit && compinit' ${config.out}/etc/zshrc grep 'autoload -U compinit && compinit' ${config.out}/etc/zshrc
echo >&2 "checking bashcompinit in /etc/zshrc" echo >&2 "checking bashcompinit in /etc/zshrc"
grep -vq 'bashcompinit' ${config.out}/etc/zshrc (! grep 'bashcompinit' ${config.out}/etc/zshrc)
echo >&2 "checking zprofile.d in /etc/zprofile" echo >&2 "checking zprofile.d in /etc/zprofile"
grep 'source /etc/zprofile.d/\*.conf' ${config.out}/etc/zprofile grep 'source /etc/zprofile.d/\*.conf' ${config.out}/etc/zprofile

View file

@ -1,7 +1,6 @@
{ config, pkgs, ... }: { config, pkgs, ... }:
{ {
services.activate-system.enable = true;
launchd.labelPrefix = "org.nix-darwin"; launchd.labelPrefix = "org.nix-darwin";
test = '' test = ''

View file

@ -1,8 +1,6 @@
{ config, pkgs, ... }: { config, pkgs, ... }:
{ {
services.activate-system.enable = true;
test = '' test = ''
echo checking activation service in /Library/LaunchDaemons >&2 echo checking activation service in /Library/LaunchDaemons >&2
grep "org.nixos.activate-system" ${config.out}/Library/LaunchDaemons/org.nixos.activate-system.plist grep "org.nixos.activate-system" ${config.out}/Library/LaunchDaemons/org.nixos.activate-system.plist

View file

@ -0,0 +1,36 @@
{ config, pkgs, ... }:
let
aerospace = pkgs.runCommand "aerospace-0.0.0" { } "mkdir $out";
in
{
services.aerospace.enable = true;
services.aerospace.package = aerospace;
services.aerospace.settings = {
gaps = {
outer.left = 8;
outer.bottom = 8;
outer.top = 8;
outer.right = 8;
};
mode.main.binding = {
alt-h = "focus left";
alt-j = "focus down";
alt-k = "focus up";
alt-l = "focus right";
};
};
test = ''
echo >&2 "checking aerospace service in ~/Library/LaunchAgents"
grep "org.nixos.aerospace" ${config.out}/user/Library/LaunchAgents/org.nixos.aerospace.plist
grep "${aerospace}/Applications/AeroSpace.app/Contents/MacOS/AeroSpace" ${config.out}/user/Library/LaunchAgents/org.nixos.aerospace.plist
conf=`sed -En 's/^[[:space:]]*<string>.*--config-path (.*)<\/string>$/\1/p' \
${config.out}/user/Library/LaunchAgents/org.nixos.aerospace.plist`
echo >&2 "checking config in $conf"
if [ `cat $conf | wc -l` -eq "27" ]; then echo "aerospace.toml config correctly contains 27 lines"; else return 1; fi
'';
}

View file

@ -42,6 +42,7 @@
system.defaults.NSGlobalDomain."com.apple.springing.delay" = 0.0; system.defaults.NSGlobalDomain."com.apple.springing.delay" = 0.0;
system.defaults.NSGlobalDomain."com.apple.swipescrolldirection" = true; system.defaults.NSGlobalDomain."com.apple.swipescrolldirection" = true;
system.defaults.".GlobalPreferences"."com.apple.sound.beep.sound" = "/System/Library/Sounds/Funk.aiff"; system.defaults.".GlobalPreferences"."com.apple.sound.beep.sound" = "/System/Library/Sounds/Funk.aiff";
system.defaults.menuExtraClock.FlashDateSeparators = false;
system.defaults.menuExtraClock.Show24Hour = false; system.defaults.menuExtraClock.Show24Hour = false;
system.defaults.menuExtraClock.ShowDayOfWeek = true; system.defaults.menuExtraClock.ShowDayOfWeek = true;
system.defaults.menuExtraClock.ShowDate = 2; system.defaults.menuExtraClock.ShowDate = 2;
@ -50,18 +51,29 @@
system.defaults.dock.orientation = "left"; system.defaults.dock.orientation = "left";
system.defaults.dock.persistent-apps = ["MyApp.app" "Cool.app"]; system.defaults.dock.persistent-apps = ["MyApp.app" "Cool.app"];
system.defaults.dock.persistent-others = ["~/Documents" "~/Downloads/file.txt"]; system.defaults.dock.persistent-others = ["~/Documents" "~/Downloads/file.txt"];
system.defaults.dock.scroll-to-open = false;
system.defaults.finder.AppleShowAllFiles = true; system.defaults.finder.AppleShowAllFiles = true;
system.defaults.finder.ShowStatusBar = true; system.defaults.finder.ShowStatusBar = true;
system.defaults.finder.ShowPathbar = true; system.defaults.finder.ShowPathbar = true;
system.defaults.finder.FXDefaultSearchScope = "SCcf"; system.defaults.finder.FXDefaultSearchScope = "SCcf";
system.defaults.finder.FXPreferredViewStyle = "Flwv"; system.defaults.finder.FXPreferredViewStyle = "Flwv";
system.defaults.finder.FXRemoveOldTrashItems = false;
system.defaults.finder.AppleShowAllExtensions = true; system.defaults.finder.AppleShowAllExtensions = true;
system.defaults.finder.CreateDesktop = false; system.defaults.finder.CreateDesktop = false;
system.defaults.finder.NewWindowTarget = "Other";
system.defaults.finder.NewWindowTargetPath = "file:///Library/Apple";
system.defaults.finder.QuitMenuItem = true; system.defaults.finder.QuitMenuItem = true;
system.defaults.finder._FXShowPosixPathInTitle = true; system.defaults.finder._FXShowPosixPathInTitle = true;
system.defaults.finder._FXSortFoldersFirst = true; system.defaults.finder._FXSortFoldersFirst = true;
system.defaults.finder._FXSortFoldersFirstOnDesktop = false;
system.defaults.finder.FXEnableExtensionChangeWarning = false; system.defaults.finder.FXEnableExtensionChangeWarning = false;
system.defaults.finder.ShowExternalHardDrivesOnDesktop = false;
system.defaults.finder.ShowHardDrivesOnDesktop = false;
system.defaults.finder.ShowMountedServersOnDesktop = false;
system.defaults.finder.ShowRemovableMediaOnDesktop = false;
system.defaults.hitoolbox.AppleFnUsageType = "Show Emoji & Symbols";
system.defaults.screencapture.location = "/tmp"; system.defaults.screencapture.location = "/tmp";
system.defaults.screencapture.include-date = true;
system.defaults.screensaver.askForPassword = true; system.defaults.screensaver.askForPassword = true;
system.defaults.screensaver.askForPasswordDelay = 5; system.defaults.screensaver.askForPasswordDelay = 5;
system.defaults.smb.NetBIOSName = "IMAC-000000"; system.defaults.smb.NetBIOSName = "IMAC-000000";
@ -91,6 +103,13 @@
true; true;
}; };
}; };
system.defaults.controlcenter.BatteryShowPercentage = true;
system.defaults.controlcenter.Sound = false;
system.defaults.controlcenter.Bluetooth = true;
system.defaults.controlcenter.AirDrop = true;
system.defaults.controlcenter.Display = false;
system.defaults.controlcenter.FocusModes = false;
system.defaults.controlcenter.NowPlaying = true;
test = lib.strings.concatMapStringsSep "\n" test = lib.strings.concatMapStringsSep "\n"
(x: '' (x: ''
echo >&2 "checking defaults write in /${x}" echo >&2 "checking defaults write in /${x}"

View file

@ -19,45 +19,62 @@
users.users.foo.shell = pkgs.bashInteractive; users.users.foo.shell = pkgs.bashInteractive;
users.users."created.user".uid = 42001; users.users."created.user".uid = 42001;
users.users."created.user".description = null;
users.users."created.user".home = null;
users.users."created.user".shell = null;
users.users."unknown.user".uid = 42002; users.users."unknown.user".uid = 42002;
test = '' test = ''
echo "checking group creation in /activate" >&2 set -v
grep "dscl . -create '/Groups/foo' PrimaryGroupID 42000" ${config.out}/activate
grep "dscl . -create '/Groups/foo' RealName 'Foo group'" ${config.out}/activate
grep "dscl . -create '/Groups/created.group' PrimaryGroupID 42001" ${config.out}/activate
grep -qv "dscl . -delete '/Groups/created.group'" ${config.out}/activate
echo "checking group deletion in /activate" >&2 # checking group creation in /activate
grep "dscl . -delete '/Groups/deleted.group'" ${config.out}/activate grep "dscl . -create ${lib.escapeShellArg "/Groups/foo"} PrimaryGroupID 42000" ${config.out}/activate
grep -qv "dscl . -create '/Groups/deleted.group'" ${config.out}/activate grep "dscl . -create ${lib.escapeShellArg "/Groups/foo"} RealName ${lib.escapeShellArg "Foo group"}" ${config.out}/activate
grep "dscl . -create ${lib.escapeShellArg "/Groups/created.group"} PrimaryGroupID 42001" ${config.out}/activate
(! grep "dscl . -delete ${lib.escapeShellArg "/Groups/created.group"}" ${config.out}/activate)
# checking group deletion in /activate
grep "dscl . -delete ${lib.escapeShellArg "/Groups/deleted.group"}" ${config.out}/activate
(! grep "dscl . -create ${lib.escapeShellArg "/Groups/deleted.group"}" ${config.out}/activate)
echo "checking group membership in /activate" >&2 echo "checking group membership in /activate" >&2
grep "dscl . -create '/Groups/foo' GroupMembership 'admin' 'foo'" ${config.out}/activate grep "dscl . -create ${lib.escapeShellArg "/Groups/foo"} GroupMembership ${lib.escapeShellArgs [ "admin" "foo" ]}" ${config.out}/activate
grep "dscl . -create '/Groups/created.group' GroupMembership" ${config.out}/activate grep "dscl . -create ${lib.escapeShellArg "/Groups/created.group"} GroupMembership" ${config.out}/activate
echo "checking unknown group in /activate" >&2 # checking unknown group in /activate
grep -qv "dscl . -create '/Groups/unknown.group'" ${config.out}/activate # checking groups not in knownGroups don't appear in /activate
grep -qv "dscl . -delete '/Groups/unknown.group'" ${config.out}/activate (! grep "dscl . -create ${lib.escapeShellArg "/Groups/unknown.group"}" ${config.out}/activate)
(! grep "dscl . -delete ${lib.escapeShellArg "/Groups/unknown.group"}" ${config.out}/activate)
echo "checking user creation in /activate" >&2 # checking user creation in /activate
grep "dscl . -create '/Users/foo' UniqueID 42000" ${config.out}/activate grep "sysadminctl -addUser ${lib.escapeShellArgs [ "foo" "-UID" 42000 "-GID" 42000 "-fullName" "Foo user" "-home" "/Users/foo" "-shell" "/run/current-system/sw/bin/bash" ]}" ${config.out}/activate
grep "dscl . -create '/Users/foo' PrimaryGroupID 42000" ${config.out}/activate grep "createhomedir -cu ${lib.escapeShellArg "foo"}" ${config.out}/activate
grep "dscl . -create '/Users/foo' IsHidden 0" ${config.out}/activate grep "sysadminctl -addUser ${lib.escapeShellArgs [ "created.user" "-UID" 42001 ]} .* ${lib.escapeShellArgs [ "-shell" "/usr/bin/false" ] }" ${config.out}/activate
grep "dscl . -create '/Users/foo' RealName 'Foo user'" ${config.out}/activate grep "sysadminctl -addUser ${lib.escapeShellArg "created.user"} .* ${lib.escapeShellArgs [ "-home" "/var/empty" ]}" ${config.out}/activate
grep "dscl . -create '/Users/foo' NFSHomeDirectory '/Users/foo'" ${config.out}/activate (! grep "dscl . -delete ${lib.escapeShellArg "/Users/created.user"}" ${config.out}/activate)
grep "dscl . -create '/Users/foo' UserShell ${lib.escapeShellArg "/run/current-system/sw/bin/bash"}" ${config.out}/activate (! grep "dscl . -delete ${lib.escapeShellArg "/Groups/created.user"}" ${config.out}/activate)
grep "dscl . -create '/Users/created.user' UniqueID 42001" ${config.out}/activate
grep "dscl . -create '/Users/created.user' UserShell ${lib.escapeShellArg "/sbin/nologin"}" ${config.out}/activate
grep "createhomedir -cu 'foo'" ${config.out}/activate
grep -qv "dscl . -delete '/Groups/created.user'" ${config.out}/activate
echo "checking user deletion in /activate" >&2 # checking user properties always get updated in /activate
grep "dscl . -delete '/Users/deleted.user'" ${config.out}/activate grep "dscl . -create ${lib.escapeShellArg "/Users/foo"} PrimaryGroupID 42000" ${config.out}/activate
grep -qv "dscl . -create '/Users/deleted.user'" ${config.out}/activate grep "dscl . -create ${lib.escapeShellArg "/Users/foo"} RealName ${lib.escapeShellArg "Foo user"}" ${config.out}/activate
grep "createhomedir -cu ${lib.escapeShellArg "foo"}" ${config.out}/activate
grep "dscl . -create ${lib.escapeShellArg "/Users/foo"} UserShell ${lib.escapeShellArg "/run/current-system/sw/bin/bash"}" ${config.out}/activate
grep "dscl . -create ${lib.escapeShellArg "/Users/foo"} IsHidden 0" ${config.out}/activate
echo "checking unknown user in /activate" >&2 # checking user properties that are null don't get updated in /activate
grep -qv "dscl . -create '/Users/unknown.user'" ${config.out}/activate (! grep "dscl . -create ${lib.escapeShellArg "/Users/created.user"} RealName" ${config.out}/activate)
grep -qv "dscl . -delete '/Users/unknown.user'" ${config.out}/activate (! grep "dscl . -create ${lib.escapeShellArg "/Users/created.user"} UserShell" ${config.out}/activate)
# checking user deletion in /activate
grep "dscl . -delete ${lib.escapeShellArg "/Users/deleted.user"}" ${config.out}/activate
(! grep "sysadminctl -addUser ${lib.escapeShellArg "deleted.user"}" ${config.out}/activate)
# checking that users not specified in knownUsers doesn't get changed in /activate
(! grep "sysadminctl -addUser ${lib.escapeShellArg "unknown.user"}" ${config.out}/activate)
(! grep "dscl . -delete ${lib.escapeShellArg "/Users/unknown.user"}" ${config.out}/activate)
(! grep "dscl . -create ${lib.escapeShellArg "/Users/unknown.user"}" ${config.out}/activate)
set +v
''; '';
} }