Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/nix-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: "nix build check"
on: [pull_request]

jobs:
nix-build:
runs-on: ubuntu-24.04
continue-on-error: true
steps:
- uses: actions/checkout@v4

- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable

- name: Check flake evaluation
id: eval
run: |
if ! nix eval .#packages.x86_64-linux.handy.drvPath 2>eval_err.log; then
echo "failed=true" >> "$GITHUB_OUTPUT"
cat eval_err.log
fi

- name: Hint on evaluation failure
if: steps.eval.outputs.failed == 'true'
run: |
echo ""
echo "::warning::flake.nix evaluation failed — likely outdated outputHashes or bunDeps hash."
echo ""
echo "┌─────────────────────────────────────────────────────────────────┐"
echo "│ To fix, run on NixOS, Ubuntu/Debian, macOS with nix installed: │"
echo "│ │"
echo "│ ./scripts/update-nix-hashes.sh │"
echo "│ │"
echo "│ The script will update version keys and hashes in flake.nix │"
echo "│ automatically. Commit the resulting changes. │"
echo "└─────────────────────────────────────────────────────────────────┘"
echo ""
cat eval_err.log
exit 1
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ blob-report/

.direnv
.envrc

# Nix build output
result
4 changes: 2 additions & 2 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@

outputHashAlgo = "sha256";
outputHashMode = "recursive";
outputHash = "sha256-+hUANv0w3qnK5d2+4JW3XMazLRDhWCbOxUXQyTGta/0=";
outputHash = "sha256-84Aw9E2+fEZT+lIb9k1bodessoex+YFr0im2GMVAPnw=";
};
in
{
Expand All @@ -68,7 +68,7 @@
"rdev-0.5.0-2" = "sha256-0F7EaPF8Oa1nnSCAjzEAkitWVpMldL3nCp3c5DVFMe0=";
"rodio-0.20.1" = "sha256-wq72awTvN4fXZ9qZc5KLYS9oMxtNDZ4YGxfqz8msofs=";
"tauri-nspanel-2.1.0" = "sha256-gotQQ1DOhavdXU8lTEux0vdY880LLetk7VLvSm6/8TI=";
"tauri-runtime-2.9.1" = "sha256-sdneSI2kfRMgTkuqQoFPgtYvkqMPSuoyrffFwOph+ZM=";
"tauri-runtime-2.10.0" = "sha256-s1IBM9hOY+HRdl/E5r7BsRTE7aLaFCCMK/DdS+bvZRc=";
"vad-rs-0.1.5" = "sha256-Q9Dxq31npyUPY9wwi6OxqSJrEvFvG8/n0dbyT7XNcyI=";
};
};
Expand Down
203 changes: 203 additions & 0 deletions scripts/update-nix-hashes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
#!/usr/bin/env bash
# Updates outputHashes and bunDeps hash in flake.nix
# when Cargo or JS dependencies change.
#
# Usage: ./scripts/update-nix-hashes.sh
#
# Handles:
# - Version changes in git dependencies (Cargo.lock → outputHashes)
# - bun.lock changes (→ bunDeps outputHash)
#
# Requires: nix, awk, sed
# Works on: NixOS, Ubuntu/Debian, macOS

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"

FLAKE_NIX="$PROJECT_DIR/flake.nix"
CARGO_LOCK="$PROJECT_DIR/src-tauri/Cargo.lock"

FAKE_HASH="sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="

# Portable sed -i (macOS requires -i '', GNU sed requires just -i)
sedi() {
if sed --version >/dev/null 2>&1; then
sed -i "$@"
else
sed -i '' "$@"
fi
}

if ! command -v nix >/dev/null 2>&1; then
echo "error: nix is not installed. Install it from https://nixos.org/download/" >&2
exit 1
fi
if [ ! -f "$FLAKE_NIX" ]; then
echo "error: flake.nix not found at $FLAKE_NIX" >&2
exit 1
fi
if [ ! -f "$CARGO_LOCK" ]; then
echo "error: Cargo.lock not found at $CARGO_LOCK" >&2
exit 1
fi

# ---------------------------------------------------------------------------
# Step 1: Extract git dependency representative keys from Cargo.lock
#
# Cargo.lock format (consecutive lines per package):
# [[package]]
# name = "foo"
# version = "1.2.3"
# source = "git+https://...#commit"
#
# Multiple packages from the same git URL share one outputHash entry keyed
# by the alphabetically first "name-version" from that URL.
# ---------------------------------------------------------------------------

extract_cargo_git_keys() {
awk '
/^name = / { name = substr($3, 2, length($3) - 2) }
/^version = / { version = substr($3, 2, length($3) - 2) }
/^source = "git\+/ {
src = $3
gsub(/^"git\+/, "", src)
sub(/#.*/, "", src)
key = name "-" version
if (!(src in best) || key < best[src])
best[src] = key
}
END { for (s in best) print best[s] }
' "$CARGO_LOCK" | sort
}

# ---------------------------------------------------------------------------
# Step 2: Extract current outputHashes keys from flake.nix
# ---------------------------------------------------------------------------

extract_flake_keys() {
# Portable: no grep -P, use awk instead
sed -n '/outputHashes/,/};/p' "$FLAKE_NIX" \
| awk -F'"' '/sha256-/ { print $2 }' \
| sort
}

# ---------------------------------------------------------------------------
# Step 3: Compare keys and update flake.nix where needed
# ---------------------------------------------------------------------------

update_output_hash_keys() {
local cargo_keys flake_keys
cargo_keys=$(extract_cargo_git_keys)
flake_keys=$(extract_flake_keys)

local changed=0

# For each flake key, check if it still matches a Cargo.lock git dep.
# If the package name matches but version differs -> update.
echo "$flake_keys" | while IFS= read -r fk; do
[ -z "$fk" ] && continue

# Extract the package name prefix (everything before the version)
fname=$(echo "$fk" | sed 's/-[0-9][0-9.]*[-0-9]*$//')

if echo "$cargo_keys" | grep -qxF "$fk"; then
continue
fi

# Key not found in Cargo.lock — look for a replacement with the same name
replacement=$(echo "$cargo_keys" | while IFS= read -r ck; do
cname=$(echo "$ck" | sed 's/-[0-9][0-9.]*[-0-9]*$//')
if [ "$cname" = "$fname" ]; then
echo "$ck"
break
fi
done)

if [ -n "$replacement" ]; then
echo "outputHashes: $fk -> $replacement"
sedi "s|\"$fk\" = \"sha256-[^\"]*\"|\"$replacement\" = \"$FAKE_HASH\"|" "$FLAKE_NIX"
changed=1
else
echo "warning: $fk not found in Cargo.lock git deps and no replacement detected" >&2
echo " This entry may need to be removed or added manually." >&2
fi
done

# Check for new git deps not yet in flake.nix
echo "$cargo_keys" | while IFS= read -r ck; do
[ -z "$ck" ] && continue
if ! echo "$flake_keys" | grep -qxF "$ck" && ! grep -q "\"$ck\"" "$FLAKE_NIX"; then
echo "warning: git dep $ck exists in Cargo.lock but not in flake.nix outputHashes" >&2
echo " You may need to add it manually." >&2
fi
done

return $changed
}

# ---------------------------------------------------------------------------
# Step 4: Iteratively fix hashes by running nix build and parsing errors
# ---------------------------------------------------------------------------

fix_hashes() {
local max_attempts=10
local attempt=0

while [ "$attempt" -lt "$max_attempts" ]; do
attempt=$((attempt + 1))
echo ""
echo "=== nix build attempt $attempt/$max_attempts ==="

local output
if output=$(nix build .#handy 2>&1); then
echo "Build successful!"
return 0
fi

# Check for hash mismatch
if echo "$output" | grep -q "hash mismatch in fixed-output derivation"; then
local specified got
specified=$(echo "$output" | grep "specified:" | awk '{print $2}')
got=$(echo "$output" | grep "got:" | awk '{print $2}')

if [ -n "$specified" ] && [ -n "$got" ]; then
echo "Hash mismatch: $specified -> $got"
sedi "s|$specified|$got|" "$FLAKE_NIX"
continue
fi
fi

# If we can't parse the error, show it and bail out
echo ""
echo "Build failed with an error that cannot be fixed automatically:" >&2
echo "$output" | tail -20 >&2
return 1
done

echo "error: exceeded max attempts ($max_attempts)" >&2
return 1
}

# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------

cd "$PROJECT_DIR"

echo "=== Nix flake hash updater ==="
echo ""
echo "Checking outputHashes keys against Cargo.lock..."

if update_output_hash_keys; then
echo "All outputHashes keys are up to date."
fi

echo ""
echo "Running nix build to verify/fix hashes..."
fix_hashes

echo ""
echo "Done. Changes in flake.nix:"
git diff --stat -- flake.nix 2>/dev/null || true