188 lines
5.4 KiB
Bash
188 lines
5.4 KiB
Bash
#!/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."
|