@vzn/vx 0.0.234 → 0.0.236
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -5
- package/src/cache/inputs.ts +47 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.236",
|
|
4
4
|
"description": "A fast, correct task runner and build cache for JavaScript monorepos.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
"node": ">=18"
|
|
18
18
|
},
|
|
19
19
|
"optionalDependencies": {
|
|
20
|
-
"@vzn/vx-linux-x64": "0.0.
|
|
21
|
-
"@vzn/vx-linux-arm64": "0.0.
|
|
22
|
-
"@vzn/vx-darwin-x64": "0.0.
|
|
23
|
-
"@vzn/vx-darwin-arm64": "0.0.
|
|
20
|
+
"@vzn/vx-linux-x64": "0.0.236",
|
|
21
|
+
"@vzn/vx-linux-arm64": "0.0.236",
|
|
22
|
+
"@vzn/vx-darwin-x64": "0.0.236",
|
|
23
|
+
"@vzn/vx-darwin-arm64": "0.0.236"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
package/src/cache/inputs.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
// be a git work tree; non-git environments are not supported.
|
|
18
18
|
|
|
19
19
|
import path from 'node:path'
|
|
20
|
-
import { lstatSync, readdirSync, realpathSync } from 'node:fs'
|
|
20
|
+
import { lstatSync, readdirSync, realpathSync, rmdirSync, rmSync } from 'node:fs'
|
|
21
21
|
import { rm, rmdir } from 'node:fs/promises'
|
|
22
22
|
import type { CacheInputs } from '../config.js'
|
|
23
23
|
import {
|
|
@@ -727,6 +727,14 @@ function changedSince(
|
|
|
727
727
|
return own
|
|
728
728
|
}
|
|
729
729
|
|
|
730
|
+
/**
|
|
731
|
+
* Up to this many paths, a clean removes synchronously: the threadpool round
|
|
732
|
+
* trip per `rm`/`rmdir` cost more than the unlink itself, 0.30 ms against
|
|
733
|
+
* 0.13 for one file and 1.7 against 1.5 for 128 (min of 7). Past a few
|
|
734
|
+
* hundred the parallel async removal wins (512: 4.5 against 5.4).
|
|
735
|
+
*/
|
|
736
|
+
const SYNC_CLEAN_MAX = 128
|
|
737
|
+
|
|
730
738
|
/**
|
|
731
739
|
* A declared output the process cannot remove (a `dist/` another user
|
|
732
740
|
* wrote, a read-only checkout) is the environment's failure, not vx's:
|
|
@@ -734,15 +742,28 @@ function changedSince(
|
|
|
734
742
|
* sends the reader to file a bug against a permission bit.
|
|
735
743
|
*/
|
|
736
744
|
async function removeAll(files: readonly string[], root: string): Promise<void> {
|
|
745
|
+
const refused = (f: string, err: NodeJS.ErrnoException): UserError => {
|
|
746
|
+
const rel = path.relative(root, f).split(path.sep).join('/')
|
|
747
|
+
return new UserError(
|
|
748
|
+
`cannot remove declared output ${rel}: ${err.code ?? err.message} — vx clears a task's ` +
|
|
749
|
+
`declared outputs before it runs and before a restore; make the path removable ` +
|
|
750
|
+
`by this user, or stop declaring it as an output`,
|
|
751
|
+
)
|
|
752
|
+
}
|
|
753
|
+
if (files.length <= SYNC_CLEAN_MAX) {
|
|
754
|
+
for (const f of files) {
|
|
755
|
+
try {
|
|
756
|
+
rmSync(f, { force: true })
|
|
757
|
+
} catch (err) {
|
|
758
|
+
throw refused(f, err as NodeJS.ErrnoException)
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
return
|
|
762
|
+
}
|
|
737
763
|
await Promise.all(
|
|
738
764
|
files.map((f) =>
|
|
739
765
|
rm(f, { force: true }).catch((err: NodeJS.ErrnoException) => {
|
|
740
|
-
|
|
741
|
-
throw new UserError(
|
|
742
|
-
`cannot remove declared output ${rel}: ${err.code ?? err.message} — vx clears a task's ` +
|
|
743
|
-
`declared outputs before it runs and before a restore; make the path removable ` +
|
|
744
|
-
`by this user, or stop declaring it as an output`,
|
|
745
|
-
)
|
|
766
|
+
throw refused(f, err)
|
|
746
767
|
}),
|
|
747
768
|
),
|
|
748
769
|
)
|
|
@@ -772,16 +793,26 @@ async function pruneEmptiedDirs(root: string, removed: readonly string[]): Promi
|
|
|
772
793
|
let level = new Set(removed.map((f) => path.dirname(f)))
|
|
773
794
|
while (level.size > 0) {
|
|
774
795
|
const parents = new Set<string>()
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
if (dir === rootResolved || !dir.startsWith(rootResolved + path.sep)) return
|
|
778
|
-
const gone = await rmdir(dir).then(
|
|
779
|
-
() => true,
|
|
780
|
-
(err: NodeJS.ErrnoException) => err.code === 'ENOENT',
|
|
781
|
-
)
|
|
782
|
-
if (gone) parents.add(path.dirname(dir))
|
|
783
|
-
}),
|
|
796
|
+
const dirs = [...level].filter(
|
|
797
|
+
(dir) => dir !== rootResolved && dir.startsWith(rootResolved + path.sep),
|
|
784
798
|
)
|
|
799
|
+
const gone = (err: NodeJS.ErrnoException): boolean => err.code === 'ENOENT'
|
|
800
|
+
if (dirs.length <= SYNC_CLEAN_MAX) {
|
|
801
|
+
for (const dir of dirs) {
|
|
802
|
+
try {
|
|
803
|
+
rmdirSync(dir)
|
|
804
|
+
parents.add(path.dirname(dir))
|
|
805
|
+
} catch (err) {
|
|
806
|
+
if (gone(err as NodeJS.ErrnoException)) parents.add(path.dirname(dir))
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
} else {
|
|
810
|
+
await Promise.all(
|
|
811
|
+
dirs.map(async (dir) => {
|
|
812
|
+
if (await rmdir(dir).then(() => true, gone)) parents.add(path.dirname(dir))
|
|
813
|
+
}),
|
|
814
|
+
)
|
|
815
|
+
}
|
|
785
816
|
level = parents
|
|
786
817
|
}
|
|
787
818
|
}
|