docs(build-hooks): correct staging-dir cleanup comment
The previous comment claimed "rmdir-on-non-empty is a no-op" — that is factually wrong. fs.rmdirSync throws ENOTEMPTY on non-empty directories. The actual race-safety mechanism is: 1. fs.readdirSync(STAGE_DIR) -> leftovers 2. fs.rmdirSync(STAGE_DIR) only when leftovers.length === 0 3. Outer try/catch swallows TOCTOU ENOTEMPTY (peer added a file between readdir and rmdir) and ENOENT (peer already cleaned up). Comment now references the leftovers variable and both fs calls so a future reader can map narrative to code without reverse-engineering it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -165,14 +165,21 @@ function build() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Best-effort cleanup of the staging dir. If concurrent builders are still
|
// Best-effort cleanup of the staging dir. If concurrent builders are still
|
||||||
// running, leftover files belong to them and will be cleaned up on their
|
// running, their staged files will be left in STAGE_DIR and cleaned up by
|
||||||
// own renames; rmdir-on-non-empty is a no-op so this is race-safe.
|
// whichever builder calls fs.rmdirSync last. fs.rmdirSync throws ENOTEMPTY
|
||||||
|
// on a non-empty directory (it is NOT a silent no-op), so we first read
|
||||||
|
// the directory via fs.readdirSync(STAGE_DIR) -> leftovers and only call
|
||||||
|
// fs.rmdirSync(STAGE_DIR) when leftovers.length === 0. A TOCTOU window
|
||||||
|
// remains: another builder can drop a staged file between the readdirSync
|
||||||
|
// and the rmdirSync, in which case rmdirSync still throws ENOTEMPTY — the
|
||||||
|
// outer try/catch swallows that, plus ENOENT if the dir was already
|
||||||
|
// removed by a peer. Either way, build proceeds; cleanup is best-effort.
|
||||||
try {
|
try {
|
||||||
const leftovers = fs.readdirSync(STAGE_DIR);
|
const leftovers = fs.readdirSync(STAGE_DIR);
|
||||||
if (leftovers.length === 0) {
|
if (leftovers.length === 0) {
|
||||||
fs.rmdirSync(STAGE_DIR);
|
fs.rmdirSync(STAGE_DIR);
|
||||||
}
|
}
|
||||||
} catch (e) { /* tolerate races / missing dir */ }
|
} catch (e) { /* tolerate TOCTOU ENOTEMPTY or ENOENT from peer cleanup */ }
|
||||||
|
|
||||||
if (hasErrors) {
|
if (hasErrors) {
|
||||||
console.error('\n\x1b[31mBuild failed: fix syntax errors above before publishing.\x1b[0m');
|
console.error('\n\x1b[31mBuild failed: fix syntax errors above before publishing.\x1b[0m');
|
||||||
|
|||||||
Reference in New Issue
Block a user