From b0eadea19eefe182d3eafcb6d6107f92a17f690e Mon Sep 17 00:00:00 2001 From: Abel Luck Date: Tue, 24 Feb 2026 15:47:21 +0100 Subject: [PATCH] add auto updater --- .forgejo/workflows/update.yml | 38 ++++++ .gitignore | 2 + flake.lock | 27 +++++ flake.nix | 41 +++++++ matrix-synapse@1.129.0/flake.lock | 27 +++++ matrix-synapse@1.129.0/flake.nix | 30 +++++ matrix-synapse@1.143.0/flake.lock | 8 +- matrix-synapse@1.143.0/flake.nix | 17 +-- matrix-synapse@1.144.0/flake.lock | 8 +- matrix-synapse@1.144.0/flake.nix | 17 +-- matrix-synapse@1.145.0/flake.lock | 8 +- matrix-synapse@1.145.0/flake.nix | 17 +-- matrix-synapse@1.146.0/flake.lock | 8 +- matrix-synapse@1.146.0/flake.nix | 17 +-- matrix-synapse@1.147.1/flake.lock | 8 +- matrix-synapse@1.147.1/flake.nix | 17 +-- update.sh | 188 ++++++++++++++++++++++++++++++ 17 files changed, 423 insertions(+), 55 deletions(-) create mode 100644 .forgejo/workflows/update.yml create mode 100644 .gitignore create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 matrix-synapse@1.129.0/flake.lock create mode 100644 matrix-synapse@1.129.0/flake.nix create mode 100644 update.sh diff --git a/.forgejo/workflows/update.yml b/.forgejo/workflows/update.yml new file mode 100644 index 0000000..1dd7d78 --- /dev/null +++ b/.forgejo/workflows/update.yml @@ -0,0 +1,38 @@ +name: Update Pins + +on: + push: + branches: + - main + paths: + - rules.nix + schedule: + - cron: "0 6 * * *" + workflow_dispatch: {} + +jobs: + update: + runs-on: docker + container: + image: ghcr.io/catthehacker/ubuntu:runner-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Nix + uses: https://guardianproject.dev/actions/determinate-nix-action@v3 + + - name: Run update + run: nix run .#update + + - name: Commit and push + run: | + git config user.name "forgejo-actions[bot]" + git config user.email "forgejo-actions[bot]@noreply.guardianproject.dev" + git add -A + if ! git diff --cached --quiet; then + git commit -m "update matrix-synapse pins" + git push + else + echo "No changes to commit" + fi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..574e7eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +result +*.swp diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..516965b --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1771482645, + "narHash": "sha256-MpAKyXfJRDTgRU33Hja+G+3h9ywLAJJNRq4Pjbb4dQs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "724cf38d99ba81fbb4a347081db93e2e3a9bc2ae", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..5ca5ab7 --- /dev/null +++ b/flake.nix @@ -0,0 +1,41 @@ +{ + description = "Pinned matrix package versions"; + + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + + outputs = + { self, nixpkgs, ... }: + let + forAllSystems = nixpkgs.lib.genAttrs [ + "x86_64-linux" + "aarch64-linux" + ]; + in + { + packages = forAllSystems ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + update = pkgs.writeShellApplication { + name = "update-pins"; + runtimeInputs = [ + pkgs.git + pkgs.nix + pkgs.jq + pkgs.coreutils + ]; + text = builtins.readFile ./update.sh; + }; + } + ); + + apps = forAllSystems (system: { + update = { + type = "app"; + program = "${self.packages.${system}.update}/bin/update-pins"; + }; + }); + }; +} diff --git a/matrix-synapse@1.129.0/flake.lock b/matrix-synapse@1.129.0/flake.lock new file mode 100644 index 0000000..a07267e --- /dev/null +++ b/matrix-synapse@1.129.0/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1746770286, + "narHash": "sha256-Y9s4o1rQlKuaYj4YxKlP7E2/e+FZaV5IjbSxxnF/Nxo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "907e98d6cc08e3261b63e3f8d2831841817b0041", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "907e98d6cc08e3261b63e3f8d2831841817b0041", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/matrix-synapse@1.129.0/flake.nix b/matrix-synapse@1.129.0/flake.nix new file mode 100644 index 0000000..87f2eba --- /dev/null +++ b/matrix-synapse@1.129.0/flake.nix @@ -0,0 +1,30 @@ +{ + description = "matrix-synapse 1.129.0"; + + inputs.nixpkgs.url = "github:NixOS/nixpkgs/907e98d6cc08e3261b63e3f8d2831841817b0041"; + + outputs = + { nixpkgs, ... }: + let + forAllSystems = nixpkgs.lib.genAttrs [ + "x86_64-linux" + "aarch64-linux" + ]; + in + { + packages = forAllSystems (system: { + default = nixpkgs.legacyPackages.${system}.matrix-synapse; + matrix-synapse = nixpkgs.legacyPackages.${system}.matrix-synapse; + matrix-synapse-unwrapped = nixpkgs.legacyPackages.${system}.matrix-synapse-unwrapped; + }); + + overlays.default = _final: prev: + let + pinned = nixpkgs.legacyPackages.${prev.stdenv.hostPlatform.system}; + in + { + matrix-synapse = pinned.matrix-synapse; + matrix-synapse-unwrapped = pinned.matrix-synapse-unwrapped; + }; + }; +} diff --git a/matrix-synapse@1.143.0/flake.lock b/matrix-synapse@1.143.0/flake.lock index 47bd20f..79c6751 100644 --- a/matrix-synapse@1.143.0/flake.lock +++ b/matrix-synapse@1.143.0/flake.lock @@ -2,17 +2,17 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1765438979, - "narHash": "sha256-JhvoqrTua8UBiDagDi4RCY/FPs5XQM57KLPqGgpPgFA=", + "lastModified": 1764486604, + "narHash": "sha256-+gx4ZLPgJEmeMpeIvWynzspCyO0W7evB7irQfdC9gI8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5b219581ae96a4201ac189ce8f1671db863f3621", + "rev": "ad70f6b3e7fe9b4945071617787feb4251657e66", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", - "rev": "5b219581ae96a4201ac189ce8f1671db863f3621", + "rev": "ad70f6b3e7fe9b4945071617787feb4251657e66", "type": "github" } }, diff --git a/matrix-synapse@1.143.0/flake.nix b/matrix-synapse@1.143.0/flake.nix index c840e25..6e0905b 100644 --- a/matrix-synapse@1.143.0/flake.nix +++ b/matrix-synapse@1.143.0/flake.nix @@ -1,7 +1,7 @@ { - description = "Matrix Synapse 1.143.0"; + description = "matrix-synapse 1.143.0"; - inputs.nixpkgs.url = "github:NixOS/nixpkgs/5b219581ae96a4201ac189ce8f1671db863f3621"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/ad70f6b3e7fe9b4945071617787feb4251657e66"; outputs = { nixpkgs, ... }: @@ -18,10 +18,13 @@ matrix-synapse-unwrapped = nixpkgs.legacyPackages.${system}.matrix-synapse-unwrapped; }); - overlays.default = _final: prev: { - matrix-synapse = (import nixpkgs { inherit (prev.stdenv.hostPlatform) system; }).matrix-synapse; - matrix-synapse-unwrapped = - (import nixpkgs { inherit (prev.stdenv.hostPlatform) system; }).matrix-synapse-unwrapped; - }; + overlays.default = _final: prev: + let + pinned = nixpkgs.legacyPackages.${prev.stdenv.hostPlatform.system}; + in + { + matrix-synapse = pinned.matrix-synapse; + matrix-synapse-unwrapped = pinned.matrix-synapse-unwrapped; + }; }; } diff --git a/matrix-synapse@1.144.0/flake.lock b/matrix-synapse@1.144.0/flake.lock index a3e590b..a64180e 100644 --- a/matrix-synapse@1.144.0/flake.lock +++ b/matrix-synapse@1.144.0/flake.lock @@ -2,17 +2,17 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1768655852, - "narHash": "sha256-UWgsh00FQayVQwjHGC/JZ1ibm7Hp9S77tvqRurnrQMI=", + "lastModified": 1768258539, + "narHash": "sha256-W3K+HbQR/RmoFAVf5dlZUkgJZivWkqJA/v28L7nQmLQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0e2c7355d17358d440adeadfe1a9cb77fccc5891", + "rev": "1f4b80d5979922876dc652142c82e204bba28eb2", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", - "rev": "0e2c7355d17358d440adeadfe1a9cb77fccc5891", + "rev": "1f4b80d5979922876dc652142c82e204bba28eb2", "type": "github" } }, diff --git a/matrix-synapse@1.144.0/flake.nix b/matrix-synapse@1.144.0/flake.nix index fe63139..757e2be 100644 --- a/matrix-synapse@1.144.0/flake.nix +++ b/matrix-synapse@1.144.0/flake.nix @@ -1,7 +1,7 @@ { - description = "Matrix Synapse 1.144.0"; + description = "matrix-synapse 1.144.0"; - inputs.nixpkgs.url = "github:NixOS/nixpkgs/0e2c7355d17358d440adeadfe1a9cb77fccc5891"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/1f4b80d5979922876dc652142c82e204bba28eb2"; outputs = { nixpkgs, ... }: @@ -18,10 +18,13 @@ matrix-synapse-unwrapped = nixpkgs.legacyPackages.${system}.matrix-synapse-unwrapped; }); - overlays.default = _final: prev: { - matrix-synapse = (import nixpkgs { inherit (prev.stdenv.hostPlatform) system; }).matrix-synapse; - matrix-synapse-unwrapped = - (import nixpkgs { inherit (prev.stdenv.hostPlatform) system; }).matrix-synapse-unwrapped; - }; + overlays.default = _final: prev: + let + pinned = nixpkgs.legacyPackages.${prev.stdenv.hostPlatform.system}; + in + { + matrix-synapse = pinned.matrix-synapse; + matrix-synapse-unwrapped = pinned.matrix-synapse-unwrapped; + }; }; } diff --git a/matrix-synapse@1.145.0/flake.lock b/matrix-synapse@1.145.0/flake.lock index 531052a..ca6d656 100644 --- a/matrix-synapse@1.145.0/flake.lock +++ b/matrix-synapse@1.145.0/flake.lock @@ -2,17 +2,17 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1769620183, - "narHash": "sha256-wSLf1rVSGWCHBb/C6ZczLhjSDRnmte2B9HGlklD8qJY=", + "lastModified": 1768858439, + "narHash": "sha256-whxg9Sj5vOoQmClFgNPOK1njoPkNMZMYnm48FhVYmrs=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9774bb59bd3bb978cf86b38afc70f9c6d5505983", + "rev": "1c096d58809938b66df361d6e5b49a1c369d311a", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", - "rev": "9774bb59bd3bb978cf86b38afc70f9c6d5505983", + "rev": "1c096d58809938b66df361d6e5b49a1c369d311a", "type": "github" } }, diff --git a/matrix-synapse@1.145.0/flake.nix b/matrix-synapse@1.145.0/flake.nix index cfded84..5b50c44 100644 --- a/matrix-synapse@1.145.0/flake.nix +++ b/matrix-synapse@1.145.0/flake.nix @@ -1,7 +1,7 @@ { - description = "Matrix Synapse 1.145.0"; + description = "matrix-synapse 1.145.0"; - inputs.nixpkgs.url = "github:NixOS/nixpkgs/9774bb59bd3bb978cf86b38afc70f9c6d5505983"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/1c096d58809938b66df361d6e5b49a1c369d311a"; outputs = { nixpkgs, ... }: @@ -18,10 +18,13 @@ matrix-synapse-unwrapped = nixpkgs.legacyPackages.${system}.matrix-synapse-unwrapped; }); - overlays.default = _final: prev: { - matrix-synapse = (import nixpkgs { inherit (prev.stdenv.hostPlatform) system; }).matrix-synapse; - matrix-synapse-unwrapped = - (import nixpkgs { inherit (prev.stdenv.hostPlatform) system; }).matrix-synapse-unwrapped; - }; + overlays.default = _final: prev: + let + pinned = nixpkgs.legacyPackages.${prev.stdenv.hostPlatform.system}; + in + { + matrix-synapse = pinned.matrix-synapse; + matrix-synapse-unwrapped = pinned.matrix-synapse-unwrapped; + }; }; } diff --git a/matrix-synapse@1.146.0/flake.lock b/matrix-synapse@1.146.0/flake.lock index 1a527de..8fddee0 100644 --- a/matrix-synapse@1.146.0/flake.lock +++ b/matrix-synapse@1.146.0/flake.lock @@ -2,17 +2,17 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1770995673, - "narHash": "sha256-VSVDo5G9ZXFJ9Y9B7CBxhUU7BD07CV/ROuE0BF1a5+Q=", + "lastModified": 1769621888, + "narHash": "sha256-FP6ewnpdkQoNDlNDukiNevbi+NAvOvZAz4a08q2y8hs=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0a4980de41791938187f7001afff13f872fa6bf6", + "rev": "90c4130e5b1396c3c1cf733b547029b4edfa6cf0", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", - "rev": "0a4980de41791938187f7001afff13f872fa6bf6", + "rev": "90c4130e5b1396c3c1cf733b547029b4edfa6cf0", "type": "github" } }, diff --git a/matrix-synapse@1.146.0/flake.nix b/matrix-synapse@1.146.0/flake.nix index 29d0a58..e9c1240 100644 --- a/matrix-synapse@1.146.0/flake.nix +++ b/matrix-synapse@1.146.0/flake.nix @@ -1,7 +1,7 @@ { - description = "Matrix Synapse 1.146.0"; + description = "matrix-synapse 1.146.0"; - inputs.nixpkgs.url = "github:NixOS/nixpkgs/0a4980de41791938187f7001afff13f872fa6bf6"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/90c4130e5b1396c3c1cf733b547029b4edfa6cf0"; outputs = { nixpkgs, ... }: @@ -18,10 +18,13 @@ matrix-synapse-unwrapped = nixpkgs.legacyPackages.${system}.matrix-synapse-unwrapped; }); - overlays.default = _final: prev: { - matrix-synapse = (import nixpkgs { inherit (prev.stdenv.hostPlatform) system; }).matrix-synapse; - matrix-synapse-unwrapped = - (import nixpkgs { inherit (prev.stdenv.hostPlatform) system; }).matrix-synapse-unwrapped; - }; + overlays.default = _final: prev: + let + pinned = nixpkgs.legacyPackages.${prev.stdenv.hostPlatform.system}; + in + { + matrix-synapse = pinned.matrix-synapse; + matrix-synapse-unwrapped = pinned.matrix-synapse-unwrapped; + }; }; } diff --git a/matrix-synapse@1.147.1/flake.lock b/matrix-synapse@1.147.1/flake.lock index 8fe48c5..2c86939 100644 --- a/matrix-synapse@1.147.1/flake.lock +++ b/matrix-synapse@1.147.1/flake.lock @@ -2,17 +2,17 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1771679794, - "narHash": "sha256-7h8rLD33qRJe/mzp72WqgATbFPUbw+Vhz+QWJiunRIU=", + "lastModified": 1770995860, + "narHash": "sha256-pw2Sdtd4afTcxhG7oyQI1+XbORoO8T5ZWtniWY3T5i0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b3e92cc8c843d8a964ce48d46a28e674aa695a62", + "rev": "e751ac9e4c6d30349f4c0f1c27f9f6365f905e44", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", - "rev": "b3e92cc8c843d8a964ce48d46a28e674aa695a62", + "rev": "e751ac9e4c6d30349f4c0f1c27f9f6365f905e44", "type": "github" } }, diff --git a/matrix-synapse@1.147.1/flake.nix b/matrix-synapse@1.147.1/flake.nix index a529d1b..59678c6 100644 --- a/matrix-synapse@1.147.1/flake.nix +++ b/matrix-synapse@1.147.1/flake.nix @@ -1,7 +1,7 @@ { - description = "Matrix Synapse 1.147.1"; + description = "matrix-synapse 1.147.1"; - inputs.nixpkgs.url = "github:NixOS/nixpkgs/b3e92cc8c843d8a964ce48d46a28e674aa695a62"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/e751ac9e4c6d30349f4c0f1c27f9f6365f905e44"; outputs = { nixpkgs, ... }: @@ -18,10 +18,13 @@ matrix-synapse-unwrapped = nixpkgs.legacyPackages.${system}.matrix-synapse-unwrapped; }); - overlays.default = _final: prev: { - matrix-synapse = (import nixpkgs { inherit (prev.stdenv.hostPlatform) system; }).matrix-synapse; - matrix-synapse-unwrapped = - (import nixpkgs { inherit (prev.stdenv.hostPlatform) system; }).matrix-synapse-unwrapped; - }; + overlays.default = _final: prev: + let + pinned = nixpkgs.legacyPackages.${prev.stdenv.hostPlatform.system}; + in + { + matrix-synapse = pinned.matrix-synapse; + matrix-synapse-unwrapped = pinned.matrix-synapse-unwrapped; + }; }; } diff --git a/update.sh b/update.sh new file mode 100644 index 0000000..07a768d --- /dev/null +++ b/update.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env bash +set -euo pipefail +shopt -s nullglob + +REPO_ROOT="$(git rev-parse --show-toplevel)" +RULES_FILE="$REPO_ROOT/rules.nix" + +if [[ ! -f "$RULES_FILE" ]]; then + echo "ERROR: rules.nix not found at $RULES_FILE" >&2 + exit 1 +fi + +# --- Locate or clone nixpkgs --- +cleanup_nixpkgs=false +if [[ -z "${NIXPKGS_REPO:-}" ]]; then + NIXPKGS_REPO=$(mktemp -d) + cleanup_nixpkgs=true + echo "Cloning nixpkgs (partial clone, may take a moment)..." + git clone --filter=blob:none --single-branch --branch nixpkgs-unstable \ + https://github.com/NixOS/nixpkgs.git "$NIXPKGS_REPO" --quiet +fi + +cleanup() { + if "$cleanup_nixpkgs"; then + rm -rf "$NIXPKGS_REPO" + fi +} +trap cleanup EXIT + +# Determine the ref to walk. For a fresh clone we use HEAD (which is +# nixpkgs-unstable). For a user-supplied repo we prefer the remote tracking +# branch so the result is independent of which branch is checked out locally. +if git -C "$NIXPKGS_REPO" rev-parse --verify origin/nixpkgs-unstable >/dev/null 2>&1; then + NIXPKGS_REF="origin/nixpkgs-unstable" +else + NIXPKGS_REF="HEAD" +fi + +# --- Map package name to the nixpkgs file whose version we track --- +nixpkgs_path_for() { + case "$1" in + matrix-synapse) + echo "pkgs/by-name/ma/matrix-synapse-unwrapped/package.nix" + ;; + *) + echo "ERROR: no nixpkgs path mapping for package '$1'" >&2 + return 1 + ;; + esac +} + +# --- Extract version string from package.nix at a given commit --- +version_at_commit() { + local commit="$1" pkg_path="$2" + git -C "$NIXPKGS_REPO" show "${commit}:${pkg_path}" 2>/dev/null \ + | grep -m1 'version = ' \ + | sed 's/.*"\(.*\)".*/\1/' +} + +# --- Generate flake.nix for a matrix-synapse pin --- +generate_flake_nix() { + local pkg="$1" version="$2" commit="$3" outfile="$4" + cat > "$outfile" << FLAKE_EOF +{ + description = "${pkg} ${version}"; + + inputs.nixpkgs.url = "github:NixOS/nixpkgs/${commit}"; + + outputs = + { nixpkgs, ... }: + let + forAllSystems = nixpkgs.lib.genAttrs [ + "x86_64-linux" + "aarch64-linux" + ]; + in + { + packages = forAllSystems (system: { + default = nixpkgs.legacyPackages.\${system}.matrix-synapse; + matrix-synapse = nixpkgs.legacyPackages.\${system}.matrix-synapse; + matrix-synapse-unwrapped = nixpkgs.legacyPackages.\${system}.matrix-synapse-unwrapped; + }); + + overlays.default = _final: prev: + let + pinned = nixpkgs.legacyPackages.\${prev.stdenv.hostPlatform.system}; + in + { + matrix-synapse = pinned.matrix-synapse; + matrix-synapse-unwrapped = pinned.matrix-synapse-unwrapped; + }; + }; +} +FLAKE_EOF +} + +# --- Read rules --- +RULES_JSON=$(nix eval --json --file "$RULES_FILE") +mapfile -t packages < <(echo "$RULES_JSON" | jq -r 'keys[]') + +for pkg in "${packages[@]}"; do + latest_n=$(echo "$RULES_JSON" | jq -r ".[\"$pkg\"].\"latest-revisions\"") + mapfile -t pins < <(echo "$RULES_JSON" | jq -r ".[\"$pkg\"].pin // [] | .[]") + pkg_path=$(nixpkgs_path_for "$pkg") + + echo "=== $pkg: latest $latest_n + ${#pins[@]} pin(s) ===" + + # Collect commits that touched the package file (newest first, first-parent only) + mapfile -t commits < <( + git -C "$NIXPKGS_REPO" log --first-parent --format="%H" "$NIXPKGS_REF" -- "$pkg_path" \ + | head -300 + ) + echo " Scanning ${#commits[@]} commits..." + + # Build version -> commit map. First occurrence (newest) wins. + declare -A version_commit=() + declare -a version_order=() + + for commit in "${commits[@]}"; do + ver=$(version_at_commit "$commit" "$pkg_path") || true + [[ -n "${ver:-}" ]] || continue + if [[ -z "${version_commit[$ver]:-}" ]]; then + version_commit["$ver"]="$commit" + version_order+=("$ver") + fi + done + + echo " Found ${#version_order[@]} unique versions" + + # Decide which versions to keep + declare -A keep_versions=() + + for ((i = 0; i < latest_n && i < ${#version_order[@]}; i++)); do + ver="${version_order[$i]}" + keep_versions["$ver"]=1 + echo " [latest] $ver ${version_commit[$ver]:0:12}" + done + + for pin_ver in "${pins[@]}"; do + if [[ -n "${version_commit[$pin_ver]:-}" ]]; then + keep_versions["$pin_ver"]=1 + echo " [pinned] $pin_ver ${version_commit[$pin_ver]:0:12}" + else + echo " WARNING: pinned version $pin_ver not found in nixpkgs history" >&2 + fi + done + + # Create or update pin directories + for ver in "${!keep_versions[@]}"; do + dir="$REPO_ROOT/${pkg}@${ver}" + commit="${version_commit[$ver]}" + flake_file="$dir/flake.nix" + + if [[ -f "$flake_file" ]]; then + existing_commit=$(sed -n 's|.*github:NixOS/nixpkgs/\([a-f0-9]*\).*|\1|p' "$flake_file" | head -1) + if [[ "$existing_commit" == "$commit" ]]; then + echo " $ver: up to date" + continue + fi + echo " $ver: updating commit" + else + echo " $ver: creating" + fi + + mkdir -p "$dir" + generate_flake_nix "$pkg" "$ver" "$commit" "$flake_file" + # flake.nix must be tracked by git before nix flake lock can see it + git add "$flake_file" + echo " $ver: locking flake inputs..." + nix flake lock "$dir" + git add "$dir/flake.lock" + done + + # Remove directories no longer required by rules + for dir in "$REPO_ROOT/${pkg}@"*/; do + [[ -d "$dir" ]] || continue + dir_name=$(basename "$dir") + ver="${dir_name#"${pkg}@"}" + if [[ -z "${keep_versions[$ver]:-}" ]]; then + echo " Removing: $ver" + rm -rf "$dir" + fi + done + + unset version_commit version_order keep_versions +done + +echo "Done."