Skip to content

fix(nix): replace manual hash management with bun2nix#1021

Merged
cjpais merged 6 commits intocjpais:mainfrom
xilec:fix/nix-bun2nix-migration
Mar 13, 2026
Merged

fix(nix): replace manual hash management with bun2nix#1021
cjpais merged 6 commits intocjpais:mainfrom
xilec:fix/nix-bun2nix-migration

Conversation

@xilec
Copy link
Copy Markdown
Contributor

@xilec xilec commented Mar 12, 2026

Please confirm you have done the following:

If this is a feature or change that was previously closed/rejected:

  • I have explained in the description below why this should be reconsidered
  • I have gathered community feedback (link to discussion below)

Human Written Description

The Nix build (nix build .#handy) keeps breaking because the fixed-output derivation
hash for bun dependencies has to be manually updated every time bun.lock changes.
The same problem exists for cargo git dependency hashes. This makes maintaining the Nix
package tedious and results in frequent hash-update PRs.

This PR eliminates all manual hash management by switching to bun2nix (per-package
fetchurl expressions) for bun deps and allowBuiltinFetchGit for cargo git deps.
A postinstall hook auto-regenerates the Nix files whenever bun.lock changes, so
non-Nix developers won't accidentally break the Nix build.

Normally, when you update TS dependencies with bun add ... or
bun update ..., Nix dependency files are auto-updated via the postinstall hook.
A developer just needs to commit the updated files, same as with Cargo.lock.

If bun.lock is updated manually (without bun), the CI job nix build check will catch it
and show a red status with an error message explaining that you should run
bun scripts/check-nix-deps.ts to update Nix dependencies.

I believe this should eliminate 99% of problems with Nix dependencies.
After this PR, manual fixes are only expected when ferrous-opencc is updated
(it requires a special patch currently), or if you decide to publish the app in
nixpkgs (which prohibits allowBuiltinFetchGit — but for standalone flake packages
it's fine). In all other cases, Nix dependencies should be updated automatically
via the hook or by running the script in the same PR where the bun dependency changed,
without requiring a separate manual PR.

Note: The nix build check CI job is currently set to continue-on-error: false,
meaning it will block PRs with outdated Nix files. The fix is always straightforward
(just run bun install or bun scripts/check-nix-deps.ts), but if you'd prefer
this check to be non-blocking, simply change it to continue-on-error: true in
.github/workflows/nix-check.yml.

Note 2: The CI job now performs a full nix build .#handy in addition to dependency sync
and flake evaluation, to catch runtime build errors. This takes ~27 min on a cold cache.
In the future, this could potentially be reduced to ~5 min by adding
Cachix (requires an account and setup; the estimate is based on
the assumption that only changed derivations would be rebuilt, similar to how rust-cache
works for cargo in the rust-tests job).

@cjpais For this PR, you can choose:

  • Keep the full build — if ~27 min CI time is acceptable for the extra reliability
  • Remove the build step — I can drop the Build handy step, keeping only the dependency
    sync check + flake evaluation (~30s), which still catches most issues

Related Issues/Discussions

Supersedes the manual hash update approach from #948.

Community Feedback

This is a fix for a recurring maintenance burden that has required multiple PRs just to update hashes. It doesn't add any new features.

Testing

  • nix eval .#packages.x86_64-linux.handy.drvPath — flake evaluation passes
  • nix build .#handy — full build succeeds
  • Verified bun install triggers postinstall hook and regenerates .nix/bun.nix when bun.lock changes
  • Verified no regeneration occurs when bun.lock is unchanged (~2ms check)

Screenshots/Videos (if applicable)

N/A

AI Assistance

  • AI was used (please describe below)

If AI was used:

  • Tools used: Claude Code (Claude Opus)
  • How extensively: wrote the implementation code (flake.nix rewrite, check-nix-deps.ts script, CI workflow).

xilec added 2 commits March 13, 2026 03:04
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)
@xilec xilec mentioned this pull request Mar 12, 2026
6 tasks
@xilec
Copy link
Copy Markdown
Contributor Author

xilec commented Mar 12, 2026

@CaptainSpof @pomarec @kakapt @y0usaf please verify nix build .#handy works on your end.

@y0usaf
Copy link
Copy Markdown
Contributor

y0usaf commented Mar 12, 2026

Confirmed, builds on my system.

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",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

process.exit(1) blocks bun install for non-Nix devs when bun2nix fails. Since CI validates bun.nix independently, this should be process.exit(0) with a warning.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 802ab6d

- 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
@kakapt
Copy link
Copy Markdown
Contributor

kakapt commented Mar 13, 2026

It fails to build on my system:

nix build .
error: Cannot build '/nix/store/yd1q851rxs4l39n8v4f3wxb923xfv8xm-bun2nix-cache-entry-creator-2.0.1.drv'.
       Reason: builder failed with exit code 1.
       Output paths:
         /nix/store/mbsrfnhv7r7085d0gp69q4fl6rvwrba8-bun2nix-cache-entry-creator-2.0.1
       Last 5 log lines:
       > Running phase: unpackPhase
       > unpacking source archive /nix/store/ijw0ha56sxaskfr23kk3nq7fiymffrpr-cache-entry-creator
       > source root is cache-entry-creator
       > Running phase: patchPhase
       > ln: failed to create symbolic link '/p': Permission denied
       For full logs, run:
         nix log /nix/store/yd1q851rxs4l39n8v4f3wxb923xfv8xm-bun2nix-cache-entry-creator-2.0.1.drv
error: Cannot build '/nix/store/zi2pmx16539qs4x8ycmzmb9qy1l4w889-bun-pkg--babel-code-frame-7.27.1.drv'.
       Reason: 1 dependency failed.
       Output paths:
         /nix/store/mqqdm7a6s8257scq9yq8ipikwr9k2iph-bun-pkg--babel-code-frame-7.27.1
error: Cannot build '/nix/store/zrimgq2bxchplq6iqjkjlnircwb1z7yc-bun-cache.drv'.
       Reason: 1 dependency failed.
       Output paths:
         /nix/store/nxwaybqrr2nm5f5ccm44dp1vv8j05kna-bun-cache
error: Cannot build '/nix/store/ypgyf5rzbn6sxma3hmnbdfcwp62db3ik-handy-0.7.10.drv'.
       Reason: 1 dependency failed.
       Output paths:
         /nix/store/akcs82qbk28z12l41l46mr7c1fsf8rm3-handy-0.7.10

Output of nix log /nix/store/yd1q851rxs4l39n8v4f3wxb923xfv8xm-bun2nix-cache-entry-creator-2.0.1.drv:

Running phase: unpackPhase
@nix { "action": "setPhase", "phase": "unpackPhase" }
unpacking source archive /nix/store/ijw0ha56sxaskfr23kk3nq7fiymffrpr-cache-entry-creator
source root is cache-entry-creator
Running phase: patchPhase
@nix { "action": "setPhase", "phase": "patchPhase" }
ln: failed to create symbolic link '/p': Permission denied

@kakapt
Copy link
Copy Markdown
Contributor

kakapt commented Mar 13, 2026

05901b builds but 802ab6 does not!

xilec added 2 commits March 13, 2026 13:16
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.
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.
@xilec
Copy link
Copy Markdown
Contributor Author

xilec commented Mar 13, 2026

05901b builds but 802ab6 does not!

@kakapt Fixed in 4f9b294

@xilec xilec requested a review from y0usaf March 13, 2026 07:34
@kakapt
Copy link
Copy Markdown
Contributor

kakapt commented Mar 13, 2026

@kakapt Fixed in 4f9b294

LGTM!

@github-actions
Copy link
Copy Markdown

🧪 Test Build Ready

Build artifacts for PR #1021 are available for testing.

Download artifacts from workflow run

Artifacts expire after 30 days.

@CaptainSpof
Copy link
Copy Markdown

LGTM

I confirm that nix build .#handy worked on my system.
I've also tried adding a new dummy dependency to the project, via bun add. The postinstall script picked it up and updated the hashes in .nix/bun-lock-hash and .nix/bun.nix

@cjpais
Copy link
Copy Markdown
Owner

cjpais commented Mar 13, 2026

Okay everyone seems to be happy with it, to be honest I'm not going to read the changes. But you NixOS folks are so responsive. More responsive than any other community. Mad respect. I expect y'all will continue to fix issues as they come up.

If you need me to do something in particular just let me know

@cjpais cjpais merged commit 7056edc into cjpais:main Mar 13, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants