Dotfiles managed with Nix
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: isolate daily upgrades from the working checkout

+114 -19
+52
.github/workflows/update-flake-lock.yml
··· 1 + name: Update flake lock 2 + 3 + on: 4 + schedule: 5 + - cron: "15 23 * * *" 6 + workflow_dispatch: 7 + 8 + permissions: 9 + contents: write 10 + pull-requests: write 11 + 12 + jobs: 13 + update-flake-lock: 14 + runs-on: ubuntu-latest 15 + 16 + steps: 17 + - name: Check out main 18 + uses: actions/checkout@v4 19 + with: 20 + ref: main 21 + 22 + - name: Install Nix 23 + uses: cachix/install-nix-action@v31 24 + with: 25 + extra_nix_config: | 26 + experimental-features = nix-command flakes 27 + 28 + - name: Update package inputs 29 + run: nix flake update nixpkgs neovim-nightly-overlay 30 + 31 + - name: Validate flake evaluation 32 + run: nix flake show 33 + 34 + - name: Create update pull request 35 + id: cpr 36 + uses: peter-evans/create-pull-request@v6 37 + with: 38 + branch: ci/update-flake-lock 39 + delete-branch: true 40 + commit-message: "chore: update flake lock" 41 + title: "chore: update flake lock" 42 + body: | 43 + ## Summary 44 + - update `nixpkgs` and `neovim-nightly-overlay` 45 + - regenerate `flake.lock` after a successful `nix flake show` 46 + 47 + - name: Report created pull request 48 + if: ${{ steps.cpr.outputs.pull-request-number != '' }} 49 + run: | 50 + printf 'Created PR #%s: %s\n' \ 51 + "${{ steps.cpr.outputs.pull-request-number }}" \ 52 + "${{ steps.cpr.outputs.pull-request-url }}"
+11 -2
README.md
··· 11 11 2. Clone this repo to `~/.dot`. 12 12 3. Apply the configuration for the current host. 13 13 14 + Automatic upgrades use a separate deploy clone at `~/.dot-deploy` by default. 15 + That clone is bootstrapped from the `origin` remote of `~/.dot` the first time 16 + the scheduled macOS upgrade job runs, then updated independently from its own 17 + `origin/main` afterward. 18 + 14 19 macOS: 15 20 16 21 ```sh ··· 44 49 2. Add an entry to `hosts.nix` using that hostname as the attribute name. 45 50 3. Set `system` to the target platform string, for example `aarch64-darwin`, `x86_64-linux`, or `aarch64-linux`. 46 51 4. Set `username` to the local account that Home Manager should manage. 47 - 5. Override `homeDirectory` or `flakeDirectory` only when the machine uses a non-standard path. 52 + 5. Override `homeDirectory`, `flakeDirectory`, or `deployDirectory` only when the machine uses a non-standard path. 48 53 49 54 You can get the `system` value on the target machine with: 50 55 ··· 55 60 ## Repository Layout 56 61 57 62 ```text 63 + .github/workflows/ # remote lock-file maintenance on GitHub 58 64 darwin/ # nix-darwin system-level modules for macOS 59 65 default.nix # main macOS settings, users, Homebrew 60 - auto-upgrade.nix # scheduled darwin-rebuild and Nix garbage collection 66 + auto-upgrade.nix # sync deploy clone, run darwin-rebuild, and garbage collect 61 67 home/ # Home Manager user-level modules shared across platforms 62 68 default.nix # shared user configuration entry point 63 69 packages/ ··· 72 78 73 79 - `flake.nix` exports Darwin hosts as `darwinConfigurations` and non-Darwin hosts as `homeConfigurations`. 74 80 - On macOS, Home Manager is embedded inside `nix-darwin`, so user configuration still lives under `home/`. 81 + - Daily macOS upgrades rebuild from `~/.dot-deploy`, keeping `~/.dot` free for branch work and local edits. 82 + - The deploy clone is updated with `git pull --ff-only origin main` before each scheduled rebuild. 83 + - A scheduled GitHub Actions workflow opens a PR that refreshes `flake.lock` for `nixpkgs` and `neovim-nightly-overlay`. 75 84 - Automatic upgrade logs live at `/var/log/darwin-auto-upgrade.log`. 76 85 - The automatic `darwin-rebuild` job runs daily at 02:00. 77 86 - Nix garbage collection runs weekly on Sunday at 03:15 and deletes generations older than 30 days.
+43 -14
darwin/auto-upgrade.nix
··· 1 - { config, lib, pkgs, flakeDirectory, hostName, username, ... }: 1 + { config, lib, pkgs, deployDirectory, flakeDirectory, homeDirectory, hostName, username, ... }: 2 2 3 3 let 4 - flakeDir = flakeDirectory; 5 - flakeRef = "path:${flakeDir}#${hostName}"; 4 + deployDir = deployDirectory; 5 + deployRef = "path:${deployDir}#${hostName}"; 6 6 upgradeLogFile = "/var/log/darwin-auto-upgrade.log"; 7 7 upgradeScript = pkgs.writeShellScript "darwin-auto-upgrade" '' 8 8 set -euo pipefail 9 9 10 - flake_dir=${lib.escapeShellArg flakeDir} 11 - flake_ref=${lib.escapeShellArg flakeRef} 10 + authoring_dir=${lib.escapeShellArg flakeDirectory} 11 + deploy_dir=${lib.escapeShellArg deployDir} 12 + user_home=${lib.escapeShellArg homeDirectory} 13 + 14 + run_as_user() { 15 + /usr/bin/sudo -u ${lib.escapeShellArg username} \ 16 + /usr/bin/env HOME="$user_home" "$@" 17 + } 18 + 19 + user_git() { 20 + run_as_user ${pkgs.git}/bin/git "$@" 21 + } 22 + 23 + if [ ! -e "$deploy_dir" ]; then 24 + remote_url="$(user_git -C "$authoring_dir" remote get-url origin)" || { 25 + printf 'Cannot bootstrap %s from %s\n' "$deploy_dir" "$authoring_dir" >&2 26 + exit 1 27 + } 28 + 29 + run_as_user ${pkgs.coreutils}/bin/mkdir -p "$(${pkgs.coreutils}/bin/dirname "$deploy_dir")" 30 + user_git clone --branch main --single-branch "$remote_url" "$deploy_dir" 31 + fi 32 + 33 + user_git -C "$deploy_dir" rev-parse --is-inside-work-tree >/dev/null 2>&1 || { 34 + printf 'Deploy directory %s is not a git repository\n' "$deploy_dir" >&2 35 + exit 1 36 + } 12 37 13 - # Update flake inputs as the regular user to preserve flake.lock ownership. 14 - # GIT_CONFIG_COUNT/KEY/VALUE mark the flake dir as a safe git directory so 15 - # that nix can read it; GIT_CONFIG_NOSYSTEM + the custom safe.directory 16 - # entry prevent git from refusing to write the lock file due to ownership. 17 - sudo -u ${lib.escapeShellArg username} \ 18 - HOME=${lib.escapeShellArg "/Users/${username}"} \ 19 - ${pkgs.nix}/bin/nix flake update --flake "$flake_dir" 38 + [ -z "$(user_git -C "$deploy_dir" status --porcelain)" ] || { 39 + printf 'Deploy directory %s must stay clean for unattended upgrades\n' "$deploy_dir" >&2 40 + exit 1 41 + } 42 + 43 + [ "$(user_git -C "$deploy_dir" branch --show-current)" = "main" ] || { 44 + printf 'Deploy directory %s must stay on main\n' "$deploy_dir" >&2 45 + exit 1 46 + } 47 + 48 + user_git -C "$deploy_dir" pull --ff-only origin main 20 49 21 50 export HOME="/var/root" 22 51 export GIT_CONFIG_COUNT=1 23 52 export GIT_CONFIG_KEY_0="safe.directory" 24 - export GIT_CONFIG_VALUE_0="$flake_dir" 53 + export GIT_CONFIG_VALUE_0="$deploy_dir" 25 54 26 55 ${config.system.build.darwin-rebuild}/bin/darwin-rebuild switch \ 27 - --flake "$flake_ref" \ 56 + --flake ${lib.escapeShellArg deployRef} \ 28 57 --print-build-logs 29 58 ''; 30 59 in
+7 -3
flake.nix
··· 27 27 isDarwin = host: lib.hasSuffix "darwin" host.system; 28 28 29 29 # Fill in default paths so every host entry has the same shape, even when 30 - # `homeDirectory` or `flakeDirectory` are omitted in `hosts.nix`. 30 + # `homeDirectory`, `flakeDirectory`, or `deployDirectory` are omitted in 31 + # `hosts.nix`. 31 32 # { 32 33 # system 33 34 # username 34 35 # homeDirectory 35 36 # flakeDirectory 37 + # deployDirectory 36 38 # } 37 39 mkHost = host: 38 40 let ··· 46 48 host // { 47 49 inherit homeDirectory; 48 50 flakeDirectory = host.flakeDirectory or "${homeDirectory}/.dot"; 51 + deployDirectory = host.deployDirectory or "${homeDirectory}/.dot-deploy"; 49 52 }; 50 53 51 54 # Load the host inventory and normalize each entry once up front. ··· 95 98 # Values passed here: 96 99 # self - the flake's own output set 97 100 # hostName - the attribute name from `darwinConfigurations` 98 - # flakeDirectory - absolute path where the flake lives on disk 101 + # flakeDirectory - interactive working checkout on disk 102 + # deployDirectory - dedicated checkout that tracks `origin/main` 99 103 # username - primary user account name 100 104 # homeDirectory - absolute path to the user's home directory 101 105 specialArgs = { 102 106 inherit self hostName; 103 - inherit (host) flakeDirectory username homeDirectory; 107 + inherit (host) flakeDirectory deployDirectory username homeDirectory; 104 108 }; 105 109 106 110 modules = [
+1
hosts.nix
··· 12 12 # Optional overrides: 13 13 # - `homeDirectory`: defaults to `/Users/<username>` on macOS and `/home/<username>` on Linux 14 14 # - `flakeDirectory`: defaults to `<homeDirectory>/.dot` 15 + # - `deployDirectory`: defaults to `<homeDirectory>/.dot-deploy` 15 16 MacBook-Air-de-Daniel = { 16 17 system = "aarch64-darwin"; 17 18 username = "vieitesprefapp";