* fix(nix): replace manual hash management with bun2nix Eliminate the recurring problem of Nix build hashes breaking whenever bun dependencies change or the bun version in nixpkgs updates. Changes: - Add bun2nix flake input (pinned to v2.0.1) for per-package fetchurl expressions from bun.lock, replacing the single FOD hash approach - Use allowBuiltinFetchGit for cargo git dependencies, removing manual outputHashes that required updates on every git dep change - Add scripts/check-nix-deps.ts (cross-platform, runs via bun) that auto-regenerates .nix/bun.nix when bun.lock changes, triggered by the postinstall hook in package.json - Update CI workflow to verify bun.nix is in sync and evaluate flake - Remove scripts/update-nix-hashes.sh (no longer needed) * style: format check-nix-deps.ts with prettier * ci(nix): make nix-check job a required check * fix(nix): address review feedback - Fix bun2nix input pinning: use path syntax (github:owner/repo/tag) instead of ?tag= query parameter so flake.lock records the ref and `nix flake update` respects the pin - Make check-nix-deps.ts exit with 0 on bun2nix failure so that `bun install` is not blocked for non-Nix developers (CI validates bun.nix independently) - Fix stale reference to check-nix-deps.sh in flake.nix comment * ci(nix): add full nix build step to CI workflow Add `nix build .#handy -L --show-trace` after flake evaluation to catch runtime build errors (broken dependencies, sandbox issues, compilation failures) that flake eval alone cannot detect. * fix(nix): update bun2nix pin from 2.0.1 to 2.0.8 bun2nix 2.0.1 has a bug in cache-entry-creator that causes "ln: failed to create symbolic link '/p': Permission denied" during the build. Version 2.0.8 fixes this.
81 lines
2.8 KiB
TypeScript
81 lines
2.8 KiB
TypeScript
// scripts/check-nix-deps.ts — Keep .nix/bun.nix in sync with bun.lock
|
|
//
|
|
// Handy uses bun2nix to generate per-package Nix fetchurl expressions from
|
|
// bun.lock. This replaces the old FOD (Fixed-Output Derivation) approach
|
|
// where a single hash covered the entire node_modules — that hash would
|
|
// break whenever the bun version in nixpkgs changed, even without any
|
|
// dependency updates.
|
|
//
|
|
// How it works:
|
|
// 1. Computes sha256 of bun.lock
|
|
// 2. Compares with stored hash in .nix/bun-lock-hash
|
|
// 3. If they match — nothing to do (~2ms)
|
|
// 4. If they differ — runs `bunx bun2nix` to regenerate .nix/bun.nix
|
|
//
|
|
// When it runs:
|
|
// - Automatically via "postinstall" in package.json — triggers after every
|
|
// bun install / bun add / bun remove / bun update
|
|
// - Can also be run manually: bun scripts/check-nix-deps.ts
|
|
//
|
|
// What to commit:
|
|
// If the script regenerated .nix/bun.nix, commit it together with bun.lock:
|
|
// git add bun.lock .nix/bun.nix .nix/bun-lock-hash
|
|
|
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
import { join, resolve } from "path";
|
|
|
|
const root = resolve(import.meta.dirname, "..");
|
|
const nixDir = join(root, ".nix");
|
|
const lockFile = join(root, "bun.lock");
|
|
const hashFile = join(nixDir, "bun-lock-hash");
|
|
const nixFile = join(nixDir, "bun.nix");
|
|
|
|
// No bun.lock — nothing to do
|
|
if (!existsSync(lockFile)) process.exit(0);
|
|
|
|
// Ensure .nix directory exists
|
|
mkdirSync(nixDir, { recursive: true });
|
|
|
|
// Compute sha256 of the current bun.lock
|
|
const currentHash = new Bun.CryptoHasher("sha256")
|
|
.update(readFileSync(lockFile))
|
|
.digest("hex");
|
|
|
|
// Read the previously stored hash (empty if first run)
|
|
const storedHash = existsSync(hashFile)
|
|
? readFileSync(hashFile, "utf-8").trim()
|
|
: "";
|
|
|
|
// If hashes match, bun.nix is up to date — nothing to do
|
|
if (currentHash === storedHash) process.exit(0);
|
|
|
|
// bun.lock has changed — regenerate the Nix dependency file
|
|
console.log(
|
|
`[check-nix-deps] bun.lock has changed, regenerating ${nixFile}...`,
|
|
);
|
|
|
|
const result = Bun.spawnSync(["bunx", "bun2nix", "-o", nixFile], {
|
|
cwd: root,
|
|
stdio: ["inherit", "inherit", "inherit"],
|
|
});
|
|
|
|
if (result.exitCode !== 0) {
|
|
console.warn(
|
|
"[check-nix-deps] Warning: bunx bun2nix failed. .nix/bun.nix may be outdated.",
|
|
);
|
|
console.warn(
|
|
"[check-nix-deps] Nix users: run `bunx bun2nix -o .nix/bun.nix` manually.",
|
|
);
|
|
console.warn(
|
|
"[check-nix-deps] Non-Nix users: this is safe to ignore, CI will catch it.",
|
|
);
|
|
// Exit 0 so that `bun install` is not blocked for non-Nix developers.
|
|
// CI validates bun.nix independently.
|
|
process.exit(0);
|
|
}
|
|
|
|
writeFileSync(hashFile, currentHash + "\n");
|
|
console.log(`[check-nix-deps] Updated ${nixFile}`);
|
|
console.log(
|
|
"[check-nix-deps] Don't forget to commit: .nix/bun.nix .nix/bun-lock-hash",
|
|
);
|