Atomic writes: convert bun init and test a write that fails
Stacked on #39689, which adds File::write_file_atomically and converts the package.json and snapshot writers. This PR holds what that branch leaves out: one more writer, and tests in which the write itself fails.
Problem
bun initon a project with apackage.jsonwrites the new text over the old bytes and truncates afterwards (init_command.rs,'write_package_json). A write that stops early leaves the start of the new file in front of the rest of the old one:package.json failed to write due to error EFBIG, file changed.- #39689 tests writers that succeed. Nothing tests a write that fails, which is what the atomic write is for.
Fix
bun initwritespackage.jsonwithwrite_file_atomically, after it closes the handle it read the file with. The Windows-only save and restore of that handle's position around the read is deleted: it only served the write through the same handle.- A failed
.snapwrite at the end of a serialbun testrun sets the exit code, like a failed inline snapshot write. It used to leavemainas an internal error. The--parallelworker (test/parallel/runner.rs,worker_flush_aggregates) still drops both results and exits 0. That needs a worker to coordinator message and is left out here on purpose. It is reported separately. - Verified:
withFileSizeLimit(blocks, cmd)intest/harness.tsruns a command underulimit -f. New tests inbun-pm-pkg,bun-pm-version,initandnew-snapshot.test.tscheck that the old file is intact and no.tmpfile is left, afterEFBIGand after aprocess.exit()under--update-snapshots. All fail on 1.4 canary. On #39689 alone theinittest and the exit code assertion fail.
Background
- Bun ignores
SIGXFSZ, so a write pastRLIMIT_FSIZEreturnsEFBIG. A limit of 0 fails every write at once, which exposes a truncate-then-write writer. A limit of one block makes Linux cut the write short, which exposes a write-then-truncate writer. The tests only check that the file is intact, so they also pass on macOS, where the whole write fails. write_file_atomicallyin #39689 returns the write error without trying the in-place fallback, so these tests hold with its fallback in place.bun createstill writes in place. It rewrites the package.json it has just copied.
Notes
The first version of this PR also made write_file_atomically keep the owner of the old file. #39689 took that change (35bb9d3), together with a fix for its two-writer test, so this PR was rebuilt on top of it as one commit without the file.rs part. The review notes on the earlier commits (drained pipes, one-line comments, the deleted Windows seek pair, the --parallel exclusion) are all folded into the current commit.
no test proof · iteration 1 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/js/bun/test/snapshot-tests/new-snapshot.test.ts, test/cli/install/bun-pm-version.test.ts, test/cli/install/bun-pm-pkg.test.ts, test/cli/init/init.test.ts