@vibe-agent-toolkit/utils 0.2.0-rc.11 → 0.2.0-rc.12
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/README.md +111 -9
- package/dist/archive/archive.d.ts +129 -0
- package/dist/archive/archive.d.ts.map +1 -0
- package/dist/archive/archive.js +223 -0
- package/dist/archive/archive.js.map +1 -0
- package/dist/archive/entries.d.ts +132 -0
- package/dist/archive/entries.d.ts.map +1 -0
- package/dist/archive/entries.js +223 -0
- package/dist/archive/entries.js.map +1 -0
- package/dist/archive/limits.d.ts +39 -0
- package/dist/archive/limits.d.ts.map +1 -0
- package/dist/archive/limits.js +59 -0
- package/dist/archive/limits.js.map +1 -0
- package/dist/archive/records.d.ts +14 -0
- package/dist/archive/records.d.ts.map +1 -0
- package/dist/archive/records.js +3 -0
- package/dist/archive/records.js.map +1 -0
- package/dist/archive/tar-reader.d.ts +18 -0
- package/dist/archive/tar-reader.d.ts.map +1 -0
- package/dist/archive/tar-reader.js +173 -0
- package/dist/archive/tar-reader.js.map +1 -0
- package/dist/archive/zip-reader.d.ts +76 -0
- package/dist/archive/zip-reader.d.ts.map +1 -0
- package/dist/archive/zip-reader.js +376 -0
- package/dist/archive/zip-reader.js.map +1 -0
- package/dist/archive.d.ts +14 -0
- package/dist/archive.d.ts.map +1 -0
- package/dist/archive.js +12 -0
- package/dist/archive.js.map +1 -0
- package/dist/asset-reference.d.ts +17 -1
- package/dist/asset-reference.d.ts.map +1 -1
- package/dist/asset-reference.js +31 -7
- package/dist/asset-reference.js.map +1 -1
- package/dist/dirent-kind.d.ts +13 -40
- package/dist/dirent-kind.d.ts.map +1 -1
- package/dist/dirent-kind.js +21 -69
- package/dist/dirent-kind.js.map +1 -1
- package/dist/entrypoint.d.ts +2 -2
- package/dist/entrypoint.d.ts.map +1 -1
- package/dist/entrypoint.js +4 -3
- package/dist/entrypoint.js.map +1 -1
- package/dist/env-flag.d.ts +2 -0
- package/dist/env-flag.d.ts.map +1 -1
- package/dist/env-flag.js +2 -0
- package/dist/env-flag.js.map +1 -1
- package/dist/errors/confirmed-absent.d.ts +41 -0
- package/dist/errors/confirmed-absent.d.ts.map +1 -0
- package/dist/errors/confirmed-absent.js +43 -0
- package/dist/errors/confirmed-absent.js.map +1 -0
- package/dist/errors/errno-table.d.ts +177 -0
- package/dist/errors/errno-table.d.ts.map +1 -0
- package/dist/errors/errno-table.js +343 -0
- package/dist/errors/errno-table.js.map +1 -0
- package/dist/errors/fs-boundary.d.ts +36 -0
- package/dist/errors/fs-boundary.d.ts.map +1 -0
- package/dist/errors/fs-boundary.js +121 -0
- package/dist/errors/fs-boundary.js.map +1 -0
- package/dist/errors/fs-fault.d.ts +176 -0
- package/dist/errors/fs-fault.d.ts.map +1 -0
- package/dist/errors/fs-fault.js +215 -0
- package/dist/errors/fs-fault.js.map +1 -0
- package/dist/errors/git-errno.d.ts +13 -0
- package/dist/errors/git-errno.d.ts.map +1 -0
- package/dist/errors/git-errno.js +45 -0
- package/dist/errors/git-errno.js.map +1 -0
- package/dist/errors/path-present.d.ts +72 -0
- package/dist/errors/path-present.d.ts.map +1 -0
- package/dist/errors/path-present.js +110 -0
- package/dist/errors/path-present.js.map +1 -0
- package/dist/errors/rag-index-empty.d.ts +16 -0
- package/dist/errors/rag-index-empty.d.ts.map +1 -0
- package/dist/errors/rag-index-empty.js +16 -0
- package/dist/errors/rag-index-empty.js.map +1 -0
- package/dist/errors/suppressed-faults.d.ts +34 -0
- package/dist/errors/suppressed-faults.d.ts.map +1 -0
- package/dist/errors/suppressed-faults.js +66 -0
- package/dist/errors/suppressed-faults.js.map +1 -0
- package/dist/file-crawler.d.ts +13 -18
- package/dist/file-crawler.d.ts.map +1 -1
- package/dist/file-crawler.js +140 -24
- package/dist/file-crawler.js.map +1 -1
- package/dist/fs-utils.d.ts +75 -50
- package/dist/fs-utils.d.ts.map +1 -1
- package/dist/fs-utils.js +148 -158
- package/dist/fs-utils.js.map +1 -1
- package/dist/fs.d.ts +4 -4
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +4 -4
- package/dist/fs.js.map +1 -1
- package/dist/git-snapshot.d.ts +25 -17
- package/dist/git-snapshot.d.ts.map +1 -1
- package/dist/git-snapshot.js +65 -11
- package/dist/git-snapshot.js.map +1 -1
- package/dist/git-tracker.d.ts +11 -3
- package/dist/git-tracker.d.ts.map +1 -1
- package/dist/git-tracker.js +29 -6
- package/dist/git-tracker.js.map +1 -1
- package/dist/git-utils.d.ts.map +1 -1
- package/dist/git-utils.js +7 -35
- package/dist/git-utils.js.map +1 -1
- package/dist/git.d.ts +1 -1
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +1 -1
- package/dist/git.js.map +1 -1
- package/dist/gitignore-checker.d.ts.map +1 -1
- package/dist/gitignore-checker.js +5 -4
- package/dist/gitignore-checker.js.map +1 -1
- package/dist/in-order.d.ts +93 -0
- package/dist/in-order.d.ts.map +1 -0
- package/dist/in-order.js +165 -0
- package/dist/in-order.js.map +1 -0
- package/dist/index.d.ts +20 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -4
- package/dist/index.js.map +1 -1
- package/dist/kill-process-tree.d.ts +43 -0
- package/dist/kill-process-tree.d.ts.map +1 -0
- package/dist/kill-process-tree.js +48 -0
- package/dist/kill-process-tree.js.map +1 -0
- package/dist/link-following.d.ts +115 -0
- package/dist/link-following.d.ts.map +1 -0
- package/dist/link-following.js +283 -0
- package/dist/link-following.js.map +1 -0
- package/dist/listing-refusal.d.ts +44 -0
- package/dist/listing-refusal.d.ts.map +1 -1
- package/dist/listing-refusal.js +79 -2
- package/dist/listing-refusal.js.map +1 -1
- package/dist/name-fold.d.ts +25 -0
- package/dist/name-fold.d.ts.map +1 -0
- package/dist/name-fold.js +40 -0
- package/dist/name-fold.js.map +1 -0
- package/dist/path-containment.d.ts +3 -1
- package/dist/path-containment.d.ts.map +1 -1
- package/dist/path-containment.js +13 -7
- package/dist/path-containment.js.map +1 -1
- package/dist/path-utils.d.ts +14 -17
- package/dist/path-utils.d.ts.map +1 -1
- package/dist/path-utils.js +37 -55
- package/dist/path-utils.js.map +1 -1
- package/dist/process.d.ts +2 -0
- package/dist/process.d.ts.map +1 -1
- package/dist/process.js +2 -0
- package/dist/process.js.map +1 -1
- package/dist/project-utils.d.ts.map +1 -1
- package/dist/project-utils.js +8 -9
- package/dist/project-utils.js.map +1 -1
- package/dist/safe-exec.d.ts +6 -2
- package/dist/safe-exec.d.ts.map +1 -1
- package/dist/safe-exec.js +1 -1
- package/dist/safe-exec.js.map +1 -1
- package/dist/skill-targets.d.ts.map +1 -1
- package/dist/skill-targets.js +3 -1
- package/dist/skill-targets.js.map +1 -1
- package/dist/skill-test/spawn-claude.d.ts +0 -15
- package/dist/skill-test/spawn-claude.d.ts.map +1 -1
- package/dist/skill-test/spawn-claude.js +11 -50
- package/dist/skill-test/spawn-claude.js.map +1 -1
- package/dist/special-file.d.ts +18 -0
- package/dist/special-file.d.ts.map +1 -0
- package/dist/special-file.js +21 -0
- package/dist/special-file.js.map +1 -0
- package/dist/terminating-signals.d.ts +129 -0
- package/dist/terminating-signals.d.ts.map +1 -0
- package/dist/terminating-signals.js +210 -0
- package/dist/terminating-signals.js.map +1 -0
- package/dist/test-helpers.d.ts +9 -5
- package/dist/test-helpers.d.ts.map +1 -1
- package/dist/test-helpers.js +18 -21
- package/dist/test-helpers.js.map +1 -1
- package/dist/test-scratch-guard.d.ts +34 -0
- package/dist/test-scratch-guard.d.ts.map +1 -0
- package/dist/test-scratch-guard.js +45 -0
- package/dist/test-scratch-guard.js.map +1 -0
- package/dist/testing/archive-fixtures.d.ts +147 -0
- package/dist/testing/archive-fixtures.d.ts.map +1 -0
- package/dist/testing/archive-fixtures.js +449 -0
- package/dist/testing/archive-fixtures.js.map +1 -0
- package/dist/testing/executables.d.ts +6 -0
- package/dist/testing/executables.d.ts.map +1 -1
- package/dist/testing/executables.js +20 -9
- package/dist/testing/executables.js.map +1 -1
- package/dist/testing/fault-fs-preload.d.ts +16 -0
- package/dist/testing/fault-fs-preload.d.ts.map +1 -0
- package/dist/testing/fault-fs-preload.js +22 -0
- package/dist/testing/fault-fs-preload.js.map +1 -0
- package/dist/testing/fault-fs.d.ts +115 -0
- package/dist/testing/fault-fs.d.ts.map +1 -0
- package/dist/testing/fault-fs.js +411 -0
- package/dist/testing/fault-fs.js.map +1 -0
- package/dist/testing/fault-spec.d.ts +83 -0
- package/dist/testing/fault-spec.d.ts.map +1 -0
- package/dist/testing/fault-spec.js +132 -0
- package/dist/testing/fault-spec.js.map +1 -0
- package/dist/testing/hostile-tree.d.ts.map +1 -1
- package/dist/testing/hostile-tree.js +3 -4
- package/dist/testing/hostile-tree.js.map +1 -1
- package/dist/testing/platform-gates.d.ts +8 -0
- package/dist/testing/platform-gates.d.ts.map +1 -1
- package/dist/testing/platform-gates.js +24 -0
- package/dist/testing/platform-gates.js.map +1 -1
- package/dist/testing/temp-dir.d.ts +31 -0
- package/dist/testing/temp-dir.d.ts.map +1 -1
- package/dist/testing/temp-dir.js +63 -0
- package/dist/testing/temp-dir.js.map +1 -1
- package/dist/testing/tier-timeout.d.ts +34 -0
- package/dist/testing/tier-timeout.d.ts.map +1 -0
- package/dist/testing/tier-timeout.js +45 -0
- package/dist/testing/tier-timeout.js.map +1 -0
- package/dist/testing/tree-snapshot.d.ts +71 -0
- package/dist/testing/tree-snapshot.d.ts.map +1 -0
- package/dist/testing/tree-snapshot.js +163 -0
- package/dist/testing/tree-snapshot.js.map +1 -0
- package/dist/testing.d.ts +6 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +8 -1
- package/dist/testing.js.map +1 -1
- package/dist/text-file.d.ts +14 -1
- package/dist/text-file.d.ts.map +1 -1
- package/dist/text-file.js +41 -8
- package/dist/text-file.js.map +1 -1
- package/dist/timing-dump.d.ts.map +1 -1
- package/dist/timing-dump.js +2 -10
- package/dist/timing-dump.js.map +1 -1
- package/dist/tree-change/apply-decisions.d.ts +101 -0
- package/dist/tree-change/apply-decisions.d.ts.map +1 -0
- package/dist/tree-change/apply-decisions.js +139 -0
- package/dist/tree-change/apply-decisions.js.map +1 -0
- package/dist/tree-change/apply.d.ts +98 -0
- package/dist/tree-change/apply.d.ts.map +1 -0
- package/dist/tree-change/apply.js +364 -0
- package/dist/tree-change/apply.js.map +1 -0
- package/dist/tree-change/copy-decisions.d.ts +58 -0
- package/dist/tree-change/copy-decisions.d.ts.map +1 -0
- package/dist/tree-change/copy-decisions.js +66 -0
- package/dist/tree-change/copy-decisions.js.map +1 -0
- package/dist/tree-change/copy-tree.d.ts +125 -0
- package/dist/tree-change/copy-tree.d.ts.map +1 -0
- package/dist/tree-change/copy-tree.js +279 -0
- package/dist/tree-change/copy-tree.js.map +1 -0
- package/dist/tree-change/files.d.ts +167 -0
- package/dist/tree-change/files.d.ts.map +1 -0
- package/dist/tree-change/files.js +423 -0
- package/dist/tree-change/files.js.map +1 -0
- package/dist/tree-change/followed-walk.d.ts +54 -0
- package/dist/tree-change/followed-walk.d.ts.map +1 -0
- package/dist/tree-change/followed-walk.js +81 -0
- package/dist/tree-change/followed-walk.js.map +1 -0
- package/dist/tree-change/host-chain.d.ts +48 -0
- package/dist/tree-change/host-chain.d.ts.map +1 -0
- package/dist/tree-change/host-chain.js +85 -0
- package/dist/tree-change/host-chain.js.map +1 -0
- package/dist/tree-change/identity-compare.d.ts +61 -0
- package/dist/tree-change/identity-compare.d.ts.map +1 -0
- package/dist/tree-change/identity-compare.js +115 -0
- package/dist/tree-change/identity-compare.js.map +1 -0
- package/dist/tree-change/identity.d.ts +62 -0
- package/dist/tree-change/identity.d.ts.map +1 -0
- package/dist/tree-change/identity.js +152 -0
- package/dist/tree-change/identity.js.map +1 -0
- package/dist/tree-change/index.d.ts +24 -0
- package/dist/tree-change/index.d.ts.map +1 -0
- package/dist/tree-change/index.js +14 -0
- package/dist/tree-change/index.js.map +1 -0
- package/dist/tree-change/link-chain.d.ts +180 -0
- package/dist/tree-change/link-chain.d.ts.map +1 -0
- package/dist/tree-change/link-chain.js +377 -0
- package/dist/tree-change/link-chain.js.map +1 -0
- package/dist/tree-change/link-containment.d.ts +105 -0
- package/dist/tree-change/link-containment.d.ts.map +1 -0
- package/dist/tree-change/link-containment.js +196 -0
- package/dist/tree-change/link-containment.js.map +1 -0
- package/dist/tree-change/link-walk.d.ts +49 -0
- package/dist/tree-change/link-walk.d.ts.map +1 -0
- package/dist/tree-change/link-walk.js +69 -0
- package/dist/tree-change/link-walk.js.map +1 -0
- package/dist/tree-change/plan.d.ts +206 -0
- package/dist/tree-change/plan.d.ts.map +1 -0
- package/dist/tree-change/plan.js +320 -0
- package/dist/tree-change/plan.js.map +1 -0
- package/dist/tree-change/readable-tree.d.ts +44 -0
- package/dist/tree-change/readable-tree.d.ts.map +1 -0
- package/dist/tree-change/readable-tree.js +52 -0
- package/dist/tree-change/readable-tree.js.map +1 -0
- package/dist/tree-change/rollback-error.d.ts +29 -0
- package/dist/tree-change/rollback-error.d.ts.map +1 -0
- package/dist/tree-change/rollback-error.js +31 -0
- package/dist/tree-change/rollback-error.js.map +1 -0
- package/dist/tree-change/staging-names.d.ts +27 -0
- package/dist/tree-change/staging-names.d.ts.map +1 -0
- package/dist/tree-change/staging-names.js +40 -0
- package/dist/tree-change/staging-names.js.map +1 -0
- package/dist/tree-change/tree-walk.d.ts +81 -0
- package/dist/tree-change/tree-walk.d.ts.map +1 -0
- package/dist/tree-change/tree-walk.js +212 -0
- package/dist/tree-change/tree-walk.js.map +1 -0
- package/dist/win32-namespace.d.ts +24 -0
- package/dist/win32-namespace.d.ts.map +1 -0
- package/dist/win32-namespace.js +31 -0
- package/dist/win32-namespace.js.map +1 -0
- package/dist/yaml/surgical-yaml.d.ts +12 -3
- package/dist/yaml/surgical-yaml.d.ts.map +1 -1
- package/dist/yaml/surgical-yaml.js +16 -6
- package/dist/yaml/surgical-yaml.js.map +1 -1
- package/eslint/README.md +12 -4
- package/eslint/rules/fs-binding-scan.cjs +278 -0
- package/eslint/rules/no-adhoc-errno.cjs +364 -0
- package/eslint/rules/no-bare-symlink-in-tests.cjs +2 -3
- package/eslint/rules/no-blind-catch.cjs +1 -1
- package/eslint/rules/no-destructive-fs.cjs +359 -0
- package/eslint/rules/no-existssync.cjs +70 -0
- package/eslint/rules/no-fragile-entrypoint-guard.cjs +3 -2
- package/eslint/rules/no-link-following-fs.cjs +68 -0
- package/eslint/rules/no-literal-process-exit.cjs +3 -16
- package/eslint/rules/no-literal-test-timeout.cjs +214 -0
- package/eslint/rules/no-raw-signal-listener.cjs +224 -0
- package/eslint/rules/no-stdout-outside-writer.cjs +135 -0
- package/package.json +10 -2
- package/dist/errors/errno.d.ts +0 -51
- package/dist/errors/errno.d.ts.map +0 -1
- package/dist/errors/errno.js +0 -112
- package/dist/errors/errno.js.map +0 -1
- package/eslint/rules/no-fs-promises-cp.cjs +0 -43
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The decisions of the apply half of the tree-change primitive, and of its file helpers, that touch
|
|
3
|
+
* no filesystem: each is handed what was read and answers what to do. `apply.ts` and `files.ts` are
|
|
4
|
+
* the halves that make the calls — and hold nothing else to decide.
|
|
5
|
+
*/
|
|
6
|
+
import { pathsActedOn } from '../errors/errno-table.js';
|
|
7
|
+
import { FsFaultError } from '../errors/fs-fault.js';
|
|
8
|
+
import { VatError } from '../errors/vat-error.js';
|
|
9
|
+
import { relativeEscapesRoot, safePath } from '../path-core.js';
|
|
10
|
+
/** {@link tempDirRefusal}: a directory to dispose of that is not strictly under the temp directory — a defect in the caller. */
|
|
11
|
+
export const TEMP_DIR_OUTSIDE_TMPDIR_CODE = 'TEMP_DIR_OUTSIDE_TMPDIR';
|
|
12
|
+
/** A replaced entry, parked once the new one was live, that could not be removed. */
|
|
13
|
+
export const TREE_CLEANUP_INCOMPLETE_CODE = 'TREE_CLEANUP_INCOMPLETE';
|
|
14
|
+
/**
|
|
15
|
+
* Whether a `write` fill's failure is the DESTINATION's: a path the failing call acted on
|
|
16
|
+
* ({@link pathsActedOn} — the one reading of an errno's two paths, so never a symlink's target
|
|
17
|
+
* text) is under the staged tree, all the callback may write. Anything else, an input the
|
|
18
|
+
* callback read (a sibling of the destination included), is not: it is rethrown as it was, for
|
|
19
|
+
* the verb's boundary to classify.
|
|
20
|
+
*
|
|
21
|
+
* @param facts - The errno, the call and the paths the OS named
|
|
22
|
+
* @param sideOf - The side a path is on, with the staged tree as the only `destination`
|
|
23
|
+
*/
|
|
24
|
+
export function fillFaultIsDestinations(facts, sideOf) {
|
|
25
|
+
return pathsActedOn(facts).some((named) => sideOf(named) === 'destination');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Whether a destination is no longer what the plan decided on — staging (a whole copy, a whole
|
|
29
|
+
* build) runs between the plan and the first rename, and anything can write there meanwhile:
|
|
30
|
+
* - another KIND of entry than the plan saw (nothing where it parks; something where it creates);
|
|
31
|
+
* - a directory a `must-be-free` change took because it was EMPTY, and now is not.
|
|
32
|
+
*
|
|
33
|
+
* @returns What changed, for the refusal's wording; `undefined` when it is as planned
|
|
34
|
+
*/
|
|
35
|
+
export function changedSincePlan(planned, now) {
|
|
36
|
+
if (now.kind !== planned.existing) {
|
|
37
|
+
return `it was ${describeKind(planned.existing)} when the change was planned and is ${describeKind(now.kind)} now`;
|
|
38
|
+
}
|
|
39
|
+
const tookAsFree = planned.change.ownership.kind === 'must-be-free' && planned.existing === 'directory';
|
|
40
|
+
return tookAsFree && !now.emptyDirectory ? 'it was an empty directory when the change was planned and holds entries now' : undefined;
|
|
41
|
+
}
|
|
42
|
+
const describeKind = (kind) => (kind === 'absent' ? 'absent' : `a ${kind}`);
|
|
43
|
+
/**
|
|
44
|
+
* The refusal of a destination that changed under the apply: the table's `occupied` destination
|
|
45
|
+
* fault (something appeared while the command wrote), naming it and what changed. The entry is
|
|
46
|
+
* left exactly as it was found.
|
|
47
|
+
*/
|
|
48
|
+
export function changedDestinationFault(planned, what) {
|
|
49
|
+
const { dest, label } = planned.change;
|
|
50
|
+
return new FsFaultError({
|
|
51
|
+
side: 'destination',
|
|
52
|
+
faultClass: 'occupied',
|
|
53
|
+
errno: 'EEXIST',
|
|
54
|
+
path: dest,
|
|
55
|
+
origin: 'argument',
|
|
56
|
+
action: `put ${label} in place: something else changed the destination while it was being prepared (${what}); it was left as found`,
|
|
57
|
+
cause: undefined,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* What a finalize does with the parked entries it could not remove: a REMOVE's is thrown (removal
|
|
62
|
+
* was the job; the first one, with every other recorded beside it), a replace's is a warning — the
|
|
63
|
+
* new tree is live.
|
|
64
|
+
*
|
|
65
|
+
* @param refused - Each parked entry that would not go, with the op of its change
|
|
66
|
+
* @returns The index of the one to throw, or `undefined` when every one is a warning
|
|
67
|
+
*/
|
|
68
|
+
export function finalizeThrows(refused) {
|
|
69
|
+
const index = refused.findIndex((each) => each.op === 'remove');
|
|
70
|
+
return index === -1 ? undefined : index;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Where the removal of the parents a create made goes next: `dir` is removed only while it is
|
|
74
|
+
* `top` (the first directory `mkdir` made) or under it, and the walk stops once `top` itself went.
|
|
75
|
+
*
|
|
76
|
+
* @param top - The first directory staging made, canonical
|
|
77
|
+
* @param dir - The directory about to be removed, canonical
|
|
78
|
+
* @returns `stop` (outside what staging made: never touched), `last` (it is `top`), or `continue` (go on to its parent)
|
|
79
|
+
*/
|
|
80
|
+
export function madeParentStep(top, dir) {
|
|
81
|
+
const below = safePath.relative(top, dir);
|
|
82
|
+
if (relativeEscapesRoot(below))
|
|
83
|
+
return 'stop';
|
|
84
|
+
return below === '' ? 'last' : 'continue';
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The refusal of a file VAT writes into a tree it is building, where what was copied into that tree
|
|
88
|
+
* already holds an entry on the way — a file or a link at the file's own name, or a link (or a file)
|
|
89
|
+
* where one of its directories goes. Whatever is there came with the tree, so it is the SOURCE's
|
|
90
|
+
* layout (origin `content`), never something to write over or through.
|
|
91
|
+
*
|
|
92
|
+
* @param entry - The entry in the way, as a path
|
|
93
|
+
* @param writing - What VAT was writing, for the message: `VAT's marketplace marker`
|
|
94
|
+
* @param cause - The errno that reported it, when one did
|
|
95
|
+
*/
|
|
96
|
+
export function entryInTheWayFault(entry, writing, cause) {
|
|
97
|
+
return new FsFaultError({
|
|
98
|
+
side: 'source',
|
|
99
|
+
faultClass: 'occupied',
|
|
100
|
+
errno: 'EEXIST',
|
|
101
|
+
path: entry,
|
|
102
|
+
origin: 'content',
|
|
103
|
+
action: `write ${writing}: the tree it goes into already holds an entry there, which VAT never writes over or through`,
|
|
104
|
+
cause,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/** A rename is tried this many times under win32 when the OS reports contention; the waits between are 50, 100, 200, 400, 800 ms. */
|
|
108
|
+
export const RENAME_TRIES = 6;
|
|
109
|
+
const FIRST_BACKOFF_MS = 50;
|
|
110
|
+
/**
|
|
111
|
+
* Whether a refused rename is tried again, and after how long: only under win32, only for
|
|
112
|
+
* contention (a scanner, an indexer, a handle still closing), and only while tries are left.
|
|
113
|
+
*
|
|
114
|
+
* @param platform - `process.platform`
|
|
115
|
+
* @param attempt - The 0-based try that just failed
|
|
116
|
+
* @param contention - Whether the errno is one a rename race raises there
|
|
117
|
+
* @returns The wait in milliseconds before the next try, or `undefined` when the refusal is final
|
|
118
|
+
*/
|
|
119
|
+
export function renameRetryDelay(platform, attempt, contention) {
|
|
120
|
+
if (platform !== 'win32' || !contention || attempt + 1 >= RENAME_TRIES)
|
|
121
|
+
return undefined;
|
|
122
|
+
return FIRST_BACKOFF_MS * 2 ** attempt;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* The refusal — a defect in the caller — of a directory to dispose of that is not strictly under
|
|
126
|
+
* the temp directory: the disposal makes a read-only tree writable before it deletes it, so a wrong
|
|
127
|
+
* argument (an empty string, a project directory) must be refused before anything is touched.
|
|
128
|
+
*
|
|
129
|
+
* @param dir - The directory handed to the disposal
|
|
130
|
+
* @param tmp - The temp directory
|
|
131
|
+
* @param containment - Where `dir` is against `tmp`, as `isUnderRoot` judged it
|
|
132
|
+
* @returns The error to throw, or `undefined` when `dir` may be disposed of
|
|
133
|
+
*/
|
|
134
|
+
export function tempDirRefusal(dir, tmp, containment) {
|
|
135
|
+
if (containment !== 'outside')
|
|
136
|
+
return undefined;
|
|
137
|
+
return new VatError(TEMP_DIR_OUTSIDE_TMPDIR_CODE, `Refusing to dispose of ${dir}: it is not inside the temporary directory ${tmp}`);
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=apply-decisions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-decisions.js","sourceRoot":"","sources":["../../src/tree-change/apply-decisions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The apply half of the tree-change primitive: carry out a {@link TreePlan} as one
|
|
3
|
+
* transaction, in a fixed order —
|
|
4
|
+
*
|
|
5
|
+
* 1. **Stage** every new entry beside its destination, on the same filesystem (so
|
|
6
|
+
* a swap never crosses devices): a `mkdtemp` directory filled by `copyTree`, a
|
|
7
|
+
* fresh directory (plain `mkdir`, the caller's mode) filled by the `write`
|
|
8
|
+
* callback, or a fresh name for a file or a link. A failure removes
|
|
9
|
+
* every staged entry, and every parent directory a create made; no destination
|
|
10
|
+
* has changed.
|
|
11
|
+
* 2. **Park** every entry being replaced or removed: `rename(dest, <staged>.previous)`.
|
|
12
|
+
* Every park happens before any swap, so a name is free before anything lands
|
|
13
|
+
* on it — on a case-folding filesystem `Old` and `old` are one name. Each
|
|
14
|
+
* destination is examined again first: one that is no longer what the plan decided
|
|
15
|
+
* on (another writer filled a directory the plan took as empty, or put an entry
|
|
16
|
+
* where it found none) is a `destination` fault, class `occupied`, and is left as
|
|
17
|
+
* found — the plan is rolled back.
|
|
18
|
+
* 3. **Swap** every staged entry in: `rename(staged, dest)`.
|
|
19
|
+
* 4. **`afterSwap()`** — the caller's own writes that must agree with the tree
|
|
20
|
+
* (a registry). A throw rolls back every swap.
|
|
21
|
+
* 5. **Rollback**, when 2–4 throw: in reverse, each swapped entry is moved off its
|
|
22
|
+
* destination and its parked entry renamed back, then the parents a create made
|
|
23
|
+
* are removed. A parked entry is NEVER deleted on a failure path: if one cannot
|
|
24
|
+
* be put back — or a create's new entry cannot be moved off — the error is
|
|
25
|
+
* {@link TreeRollbackIncompleteError}, naming each.
|
|
26
|
+
* 6. **Finalize**: each parked entry is removed, its modes notwithstanding. For a
|
|
27
|
+
* replace a refusal is only a warning ({@link TREE_CLEANUP_INCOMPLETE_CODE}): the
|
|
28
|
+
* new tree is live. For a remove, removal is the job, so it is a `destination`
|
|
29
|
+
* fault naming the parked path — the data is already off the user's path.
|
|
30
|
+
*
|
|
31
|
+
* Every rename is {@link renameFileAtomic}'s, retried under win32 on contention.
|
|
32
|
+
* The primitive's own filesystem faults are classified `destination` (staging sits
|
|
33
|
+
* beside the user's destination); a `copy` source's read is already classified on
|
|
34
|
+
* the fill's declared side; a
|
|
35
|
+
* `write` fill's raw errno is `destination` only when it names a path under the
|
|
36
|
+
* destination's parent — anything else (an input the callback read) is rethrown
|
|
37
|
+
* raw, for the verb's boundary to classify.
|
|
38
|
+
*
|
|
39
|
+
* A thrown failure is never mutated. What a failure path could not clean up (a
|
|
40
|
+
* staged entry, a parent, a replaced tree beside a failed remove) is recorded
|
|
41
|
+
* beside it, off its cause chain: `suppressedFaultsOf(error)`.
|
|
42
|
+
*/
|
|
43
|
+
import { TREE_CLEANUP_INCOMPLETE_CODE } from './apply-decisions.js';
|
|
44
|
+
import { type TreePlan } from './plan.js';
|
|
45
|
+
export { TREE_CLEANUP_INCOMPLETE_CODE } from './apply-decisions.js';
|
|
46
|
+
export interface ApplyOptions {
|
|
47
|
+
/**
|
|
48
|
+
* Runs once every swap is done; a throw rolls every change back and is rethrown.
|
|
49
|
+
* ⚠️ Its own filesystem faults must be classified `destination` (it writes user
|
|
50
|
+
* state beside the tree): should the rollback then fail, the error becomes
|
|
51
|
+
* `TREE_ROLLBACK_INCOMPLETE` (`RUN_INCOMPLETE`), which agrees with every
|
|
52
|
+
* destination row of the refusal table and with no other side's.
|
|
53
|
+
*/
|
|
54
|
+
readonly afterSwap?: () => Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
/** A finding a successful apply reports: the change is done, something beside it is left. */
|
|
57
|
+
export interface TreeChangeWarning {
|
|
58
|
+
readonly code: typeof TREE_CLEANUP_INCOMPLETE_CODE;
|
|
59
|
+
/** The entry left behind. */
|
|
60
|
+
readonly path: string;
|
|
61
|
+
readonly message: string;
|
|
62
|
+
}
|
|
63
|
+
export interface ApplyResult {
|
|
64
|
+
readonly warnings: readonly TreeChangeWarning[];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Carry out `plan`: stage, park, swap, `afterSwap`, finalize — or roll back so
|
|
68
|
+
* every destination is exactly as it was.
|
|
69
|
+
*
|
|
70
|
+
* @param plan - What `planTreeChanges` decided; `keep` and `subsumed` changes are not touched
|
|
71
|
+
* @param options - `afterSwap`, run once the new tree is in place
|
|
72
|
+
* @returns The warnings of a change that is done: a previous tree left beside a replaced one
|
|
73
|
+
* @throws the first failure, after the rollback and unchanged: an `FsFaultError` (side
|
|
74
|
+
* `destination`, or the fill's declared side for a copy source's read), a `write` fill's own error or raw
|
|
75
|
+
* errno, or whatever `afterSwap` threw — with what could not be cleaned up in
|
|
76
|
+
* `suppressedFaultsOf(error)`; {@link TreeRollbackIncompleteError} (cause: that
|
|
77
|
+
* failure) when the rollback could not undo every change; for a `remove` whose
|
|
78
|
+
* parked entry cannot be removed, an `FsFaultError` side `destination` naming it
|
|
79
|
+
*/
|
|
80
|
+
export declare function applyTreePlan(plan: TreePlan, options?: ApplyOptions): Promise<ApplyResult>;
|
|
81
|
+
/** What {@link applyTreePlanOrLeftover} finished with: the warnings of a clean apply, or the failure that came after the commit. */
|
|
82
|
+
export interface ApplyOutcome extends ApplyResult {
|
|
83
|
+
/**
|
|
84
|
+
* The failure that came once every change was in place (and `afterSwap` had run): a parked entry of
|
|
85
|
+
* a `remove` the OS would not delete. It cannot be undone and is no refusal of the change — the
|
|
86
|
+
* change is DONE, every destination as planned — so it is returned, naming what is left (its `path`
|
|
87
|
+
* the parked entry), for the verb to report beside the work it finished. Absent when the apply finished clean.
|
|
88
|
+
*/
|
|
89
|
+
readonly leftover?: unknown;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* {@link applyTreePlan}, for a verb that reports a change it finished even when what it parked could
|
|
93
|
+
* not then be deleted (an uninstall, a clear): a failure before the commit — every swap made and
|
|
94
|
+
* `afterSwap` run — rolled back and is thrown, as by `applyTreePlan`; one after it is returned as
|
|
95
|
+
* `leftover`. The commit is the one line between "nothing finished" and "the change is done".
|
|
96
|
+
*/
|
|
97
|
+
export declare function applyTreePlanOrLeftover(plan: TreePlan, options?: ApplyOptions): Promise<ApplyOutcome>;
|
|
98
|
+
//# sourceMappingURL=apply.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/tree-change/apply.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAcH,OAAO,EAAsG,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AAIxK,OAAO,EAAgD,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAIxF,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AAKpE,MAAM,WAAW,YAAY;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,6FAA6F;AAC7F,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,OAAO,4BAA4B,CAAC;IACnD,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACjD;AAiQD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAE9F;AAED,oIAAoI;AACpI,MAAM,WAAW,YAAa,SAAQ,WAAW;IAC/C;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAa/G"}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The apply half of the tree-change primitive: carry out a {@link TreePlan} as one
|
|
3
|
+
* transaction, in a fixed order —
|
|
4
|
+
*
|
|
5
|
+
* 1. **Stage** every new entry beside its destination, on the same filesystem (so
|
|
6
|
+
* a swap never crosses devices): a `mkdtemp` directory filled by `copyTree`, a
|
|
7
|
+
* fresh directory (plain `mkdir`, the caller's mode) filled by the `write`
|
|
8
|
+
* callback, or a fresh name for a file or a link. A failure removes
|
|
9
|
+
* every staged entry, and every parent directory a create made; no destination
|
|
10
|
+
* has changed.
|
|
11
|
+
* 2. **Park** every entry being replaced or removed: `rename(dest, <staged>.previous)`.
|
|
12
|
+
* Every park happens before any swap, so a name is free before anything lands
|
|
13
|
+
* on it — on a case-folding filesystem `Old` and `old` are one name. Each
|
|
14
|
+
* destination is examined again first: one that is no longer what the plan decided
|
|
15
|
+
* on (another writer filled a directory the plan took as empty, or put an entry
|
|
16
|
+
* where it found none) is a `destination` fault, class `occupied`, and is left as
|
|
17
|
+
* found — the plan is rolled back.
|
|
18
|
+
* 3. **Swap** every staged entry in: `rename(staged, dest)`.
|
|
19
|
+
* 4. **`afterSwap()`** — the caller's own writes that must agree with the tree
|
|
20
|
+
* (a registry). A throw rolls back every swap.
|
|
21
|
+
* 5. **Rollback**, when 2–4 throw: in reverse, each swapped entry is moved off its
|
|
22
|
+
* destination and its parked entry renamed back, then the parents a create made
|
|
23
|
+
* are removed. A parked entry is NEVER deleted on a failure path: if one cannot
|
|
24
|
+
* be put back — or a create's new entry cannot be moved off — the error is
|
|
25
|
+
* {@link TreeRollbackIncompleteError}, naming each.
|
|
26
|
+
* 6. **Finalize**: each parked entry is removed, its modes notwithstanding. For a
|
|
27
|
+
* replace a refusal is only a warning ({@link TREE_CLEANUP_INCOMPLETE_CODE}): the
|
|
28
|
+
* new tree is live. For a remove, removal is the job, so it is a `destination`
|
|
29
|
+
* fault naming the parked path — the data is already off the user's path.
|
|
30
|
+
*
|
|
31
|
+
* Every rename is {@link renameFileAtomic}'s, retried under win32 on contention.
|
|
32
|
+
* The primitive's own filesystem faults are classified `destination` (staging sits
|
|
33
|
+
* beside the user's destination); a `copy` source's read is already classified on
|
|
34
|
+
* the fill's declared side; a
|
|
35
|
+
* `write` fill's raw errno is `destination` only when it names a path under the
|
|
36
|
+
* destination's parent — anything else (an input the callback read) is rethrown
|
|
37
|
+
* raw, for the verb's boundary to classify.
|
|
38
|
+
*
|
|
39
|
+
* A thrown failure is never mutated. What a failure path could not clean up (a
|
|
40
|
+
* staged entry, a parent, a replaced tree beside a failed remove) is recorded
|
|
41
|
+
* beside it, off its cause chain: `suppressedFaultsOf(error)`.
|
|
42
|
+
*/
|
|
43
|
+
import fs from 'node:fs/promises';
|
|
44
|
+
import path from 'node:path';
|
|
45
|
+
import { fsFaultOf, isAlreadyExistsError, isOccupiedError } from '../errors/errno-table.js';
|
|
46
|
+
import { fsBoundary } from '../errors/fs-boundary.js';
|
|
47
|
+
import { classifyFsFault, isFsFaultError, withFsFault } from '../errors/fs-fault.js';
|
|
48
|
+
import { recordSuppressedFault } from '../errors/suppressed-faults.js';
|
|
49
|
+
import { isVatError } from '../errors/vat-error.js';
|
|
50
|
+
import { forEachInOrder, mapInOrder } from '../in-order.js';
|
|
51
|
+
import { safePath, toForwardSlash } from '../path-core.js';
|
|
52
|
+
import { withoutWin32Namespace } from '../win32-namespace.js';
|
|
53
|
+
import { changedDestinationFault, changedSincePlan, fillFaultIsDestinations, finalizeThrows, madeParentStep, TREE_CLEANUP_INCOMPLETE_CODE } from './apply-decisions.js';
|
|
54
|
+
import { copyTree } from './copy-tree.js';
|
|
55
|
+
import { removeEntry, renameFileAtomic } from './files.js';
|
|
56
|
+
import { sameEntry } from './identity.js';
|
|
57
|
+
import { destinationNow, isActive } from './plan.js';
|
|
58
|
+
import { TreeRollbackIncompleteError } from './rollback-error.js';
|
|
59
|
+
import { PARKED_SUFFIX, stagingName, stagingPrefix } from './staging-names.js';
|
|
60
|
+
export { TREE_CLEANUP_INCOMPLETE_CODE } from './apply-decisions.js';
|
|
61
|
+
/** Suffix of a swapped-in entry moved back off its destination by a rollback. */
|
|
62
|
+
const DISCARD_SUFFIX = '.discard';
|
|
63
|
+
const destOf = (slot) => slot.planned.change.dest;
|
|
64
|
+
const labelOf = (slot) => slot.planned.change.label;
|
|
65
|
+
const messageOf = (error) => (error instanceof Error ? error.message : String(error));
|
|
66
|
+
/** Run `work` for `slot`, a raw errno classified `destination` with `action`. */
|
|
67
|
+
function onDestination(slot, action, work) {
|
|
68
|
+
return withFsFault({ side: 'destination', action: `${action} ${labelOf(slot)}`, path: destOf(slot) }, work);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A `write` fill's failure: a raw errno naming a path under the staged tree — all the
|
|
72
|
+
* callback may write — is the destination's; anything else, an input the callback read
|
|
73
|
+
* (a sibling of the destination included), is rethrown as it was, for the verb's
|
|
74
|
+
* boundary to classify.
|
|
75
|
+
*/
|
|
76
|
+
function writeFillFault(error, slot, staged) {
|
|
77
|
+
const facts = fsFaultOf(error);
|
|
78
|
+
if (isVatError(error) || facts === undefined)
|
|
79
|
+
return error;
|
|
80
|
+
const ours = fsBoundary({ destination: [staged] });
|
|
81
|
+
if (!fillFaultIsDestinations(facts, (named) => ours.sideOf(named)))
|
|
82
|
+
return error;
|
|
83
|
+
return classifyFsFault(error, { side: 'destination', action: `stage the new ${labelOf(slot)}`, path: destOf(slot) });
|
|
84
|
+
}
|
|
85
|
+
/** The parent of the destination, made when absent; the first directory made is remembered. */
|
|
86
|
+
async function makeParent(slot) {
|
|
87
|
+
const made = await onDestination(slot, 'make the parent directory of', () => fs.mkdir(path.dirname(destOf(slot)), { recursive: true }));
|
|
88
|
+
slot.createdParent = made === undefined ? undefined : toForwardSlash(withoutWin32Namespace(made));
|
|
89
|
+
}
|
|
90
|
+
/** How many fresh names a `write` fill tries before an `EEXIST` is the answer (as `mkdtemp` retries its own). */
|
|
91
|
+
const STAGING_NAME_TRIES = 8;
|
|
92
|
+
/** The staged directory beside `dest`: `mkdtemp` for a copy, a plain `mkdir` of a fresh name for a `write` (see {@link stageTree}). */
|
|
93
|
+
async function makeStagedDirectory(dest, from, attempt = 1) {
|
|
94
|
+
if (from === 'copy')
|
|
95
|
+
return fs.mkdtemp(stagingPrefix(dest));
|
|
96
|
+
const name = stagingName(dest);
|
|
97
|
+
try {
|
|
98
|
+
await fs.mkdir(name);
|
|
99
|
+
return name;
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
// A collision with a leftover of the same random name: draw another, as `mkdtemp` does.
|
|
103
|
+
if (!isAlreadyExistsError(error) || attempt >= STAGING_NAME_TRIES)
|
|
104
|
+
throw error;
|
|
105
|
+
return makeStagedDirectory(dest, from, attempt + 1);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Stage a directory tree beside the destination, filled by the copy or the caller's `write`. A copy
|
|
110
|
+
* stages in a `mkdtemp` directory (the copy gives it its source's mode). A `write` stages in a fresh
|
|
111
|
+
* name made by a plain `mkdir`, so the tree it becomes gets the mode any directory the caller makes
|
|
112
|
+
* gets — never a temp directory's 0700 (`dist/skills`, a marketplace). The name is as unique: a
|
|
113
|
+
* collision is `EEXIST`, never a shared directory.
|
|
114
|
+
*/
|
|
115
|
+
async function stageTree(slot, fill) {
|
|
116
|
+
const staged = toForwardSlash(await onDestination(slot, 'stage the new', () => makeStagedDirectory(destOf(slot), fill.from)));
|
|
117
|
+
slot.staged = staged;
|
|
118
|
+
if (fill.from === 'copy') {
|
|
119
|
+
await onDestination(slot, 'copy the new', () => copyTree(fill.source, staged, '', { links: fill.links, side: fill.side, onto: 'fresh', ...(fill.filter === undefined ? {} : { filter: fill.filter }) }));
|
|
120
|
+
}
|
|
121
|
+
else if (fill.from === 'write') {
|
|
122
|
+
// `try`/`await`, not `.catch`: a callback that throws synchronously is judged the same way.
|
|
123
|
+
try {
|
|
124
|
+
await fill.write(staged);
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
throw writeFillFault(error, slot, staged);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** Make the new entry beside the destination. */
|
|
132
|
+
async function stage(slot) {
|
|
133
|
+
const { change } = slot.planned;
|
|
134
|
+
if (change.op === 'remove')
|
|
135
|
+
return;
|
|
136
|
+
await makeParent(slot);
|
|
137
|
+
if (change.op === 'replace-file') {
|
|
138
|
+
const staged = stagingName(change.dest);
|
|
139
|
+
slot.staged = staged;
|
|
140
|
+
const { contents } = change;
|
|
141
|
+
await onDestination(slot, 'stage the new', () => fs.writeFile(staged, typeof contents === 'function' ? contents() : contents, { flag: 'wx' }));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (change.fill.from !== 'link') {
|
|
145
|
+
await stageTree(slot, change.fill);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const staged = stagingName(change.dest);
|
|
149
|
+
slot.staged = staged;
|
|
150
|
+
const { target } = change.fill;
|
|
151
|
+
// `dir`: parity with today's `--dev` lanes, both of which refuse win32 before staging. Should a win32
|
|
152
|
+
// `--dev` lane ever exist, the repo's precedent is `junction` (dev-tools `link-workspace-packages.ts`),
|
|
153
|
+
// which needs no symlink privilege.
|
|
154
|
+
await onDestination(slot, 'stage the link for', () => fs.symlink(target, staged, 'dir'));
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* The name `dest` has on disk. On a case-folding filesystem a plan may spell a
|
|
158
|
+
* destination `plugins/old` while the directory is `plugins/Old`: a rollback must
|
|
159
|
+
* put it back as `Old`. When the parent lists `dest`'s own name, that is it (two
|
|
160
|
+
* names one fold apart cannot both exist); otherwise the sibling that is the same
|
|
161
|
+
* entry, judged by identity, never by comparing names.
|
|
162
|
+
*/
|
|
163
|
+
async function spelledOnDisk(dest) {
|
|
164
|
+
const parent = path.dirname(dest);
|
|
165
|
+
const names = await fs.readdir(parent);
|
|
166
|
+
if (names.includes(toForwardSlash(path.basename(dest))))
|
|
167
|
+
return dest;
|
|
168
|
+
const alias = names.find((name) => sameEntry(safePath.join(parent, name), dest) === 'same');
|
|
169
|
+
return alias === undefined ? dest : safePath.join(parent, alias);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Refuse a destination that is no longer what the plan decided on (`changedSincePlan`): staging runs
|
|
173
|
+
* between the plan and the first rename, and a `must-be-free` destination another writer filled
|
|
174
|
+
* meanwhile must not be parked and deleted, nor a file that appeared at a `create` renamed over.
|
|
175
|
+
* Asked immediately before the rename it guards; the entry is left exactly as found.
|
|
176
|
+
*/
|
|
177
|
+
function requireAsPlanned(slot) {
|
|
178
|
+
const changed = changedSincePlan(slot.planned, destinationNow(destOf(slot), slot.planned));
|
|
179
|
+
if (changed !== undefined)
|
|
180
|
+
throw changedDestinationFault(slot.planned, changed);
|
|
181
|
+
}
|
|
182
|
+
async function park(slot) {
|
|
183
|
+
requireAsPlanned(slot);
|
|
184
|
+
const parked = `${slot.staged ?? stagingName(destOf(slot))}${PARKED_SUFFIX}`;
|
|
185
|
+
await onDestination(slot, 'move aside the previous', async () => {
|
|
186
|
+
slot.spelled = await spelledOnDisk(destOf(slot));
|
|
187
|
+
await renameFileAtomic(destOf(slot), parked);
|
|
188
|
+
});
|
|
189
|
+
slot.parked = parked;
|
|
190
|
+
}
|
|
191
|
+
async function swap(slot) {
|
|
192
|
+
// A destination the plan found absent was never parked: nothing has vouched for it since the plan.
|
|
193
|
+
if (slot.planned.existing === 'absent')
|
|
194
|
+
requireAsPlanned(slot);
|
|
195
|
+
const staged = slot.staged;
|
|
196
|
+
await onDestination(slot, 'put in place the new', () => renameFileAtomic(staged, destOf(slot)));
|
|
197
|
+
slot.swapped = true;
|
|
198
|
+
}
|
|
199
|
+
/** Remove `entry`, VAT's own leftover; a refusal is recorded beside `error`, never thrown over it. */
|
|
200
|
+
async function discard(entry, error) {
|
|
201
|
+
if (entry === undefined)
|
|
202
|
+
return;
|
|
203
|
+
try {
|
|
204
|
+
await removeEntry(entry);
|
|
205
|
+
}
|
|
206
|
+
catch (error_) {
|
|
207
|
+
recordSuppressedFault(error, classifyFsFault(error_, { side: 'destination', action: `remove the staged ${entry}`, path: entry }));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Remove, deepest first, the empty parents staging made for `slot`: from the
|
|
212
|
+
* destination's parent up to the first directory `mkdir` made, never past it — both
|
|
213
|
+
* in the canonical spelling, bounded by containment, not by comparing strings. A
|
|
214
|
+
* parent still holding entries (another change's, stranded) is left without a
|
|
215
|
+
* word; one the OS refuses is recorded beside `error`.
|
|
216
|
+
*/
|
|
217
|
+
function removeMadeParents(slot, error) {
|
|
218
|
+
if (slot.createdParent === undefined)
|
|
219
|
+
return Promise.resolve();
|
|
220
|
+
const top = safePath.resolve(slot.createdParent);
|
|
221
|
+
const removeFrom = (dir) => {
|
|
222
|
+
const step = madeParentStep(top, dir);
|
|
223
|
+
if (step === 'stop')
|
|
224
|
+
return Promise.resolve();
|
|
225
|
+
return fs.rmdir(dir).then(() => (step === 'last' ? undefined : removeFrom(safePath.resolve(path.dirname(dir)))), (error_) => {
|
|
226
|
+
if (isOccupiedError(error_))
|
|
227
|
+
return;
|
|
228
|
+
recordSuppressedFault(error, classifyFsFault(error_, { side: 'destination', action: 'remove the directory made for', path: dir }));
|
|
229
|
+
});
|
|
230
|
+
};
|
|
231
|
+
return removeFrom(safePath.resolve(path.dirname(destOf(slot))));
|
|
232
|
+
}
|
|
233
|
+
/** Move a swapped-in entry back off its destination, to be discarded. What could not move is returned. */
|
|
234
|
+
async function unswap(slot) {
|
|
235
|
+
const discarded = `${slot.staged}${DISCARD_SUFFIX}`;
|
|
236
|
+
try {
|
|
237
|
+
await renameFileAtomic(destOf(slot), discarded);
|
|
238
|
+
slot.staged = discarded;
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
catch (error_) {
|
|
242
|
+
return { dest: destOf(slot), parked: slot.parked, why: `the new content could not be moved off it: ${messageOf(error_)}` };
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/** Undo one slot: the new entry off the destination, the previous one back on. What could not be undone is returned. */
|
|
246
|
+
async function restore(slot, error) {
|
|
247
|
+
const stuck = slot.swapped ? await unswap(slot) : undefined;
|
|
248
|
+
if (stuck !== undefined)
|
|
249
|
+
return stuck;
|
|
250
|
+
await discard(slot.staged, error);
|
|
251
|
+
if (slot.parked === undefined)
|
|
252
|
+
return undefined;
|
|
253
|
+
try {
|
|
254
|
+
await renameFileAtomic(slot.parked, slot.spelled ?? destOf(slot));
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
catch (error_) {
|
|
258
|
+
return { dest: destOf(slot), parked: slot.parked, why: messageOf(error_) };
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/** Remove the parents staging made, for every slot fully undone (newest first). */
|
|
262
|
+
function removeAllMadeParents(slots, error, stranded = []) {
|
|
263
|
+
return forEachInOrder(slots.toReversed().filter((slot) => !stranded.includes(slot)), (slot) => removeMadeParents(slot, error));
|
|
264
|
+
}
|
|
265
|
+
/** Undo every slot, newest first; the error to throw is `error`, or a rollback-incomplete one carrying it. */
|
|
266
|
+
async function rolledBack(slots, error) {
|
|
267
|
+
const outcomes = await mapInOrder(slots.toReversed(), async (slot) => ({ slot, stranded: await restore(slot, error) }));
|
|
268
|
+
const stuck = outcomes.filter((o) => o.stranded !== undefined);
|
|
269
|
+
await removeAllMadeParents(slots, error, stuck.map((o) => o.slot));
|
|
270
|
+
return stuck.length === 0 ? error : new TreeRollbackIncompleteError(error, stuck.map((o) => o.stranded));
|
|
271
|
+
}
|
|
272
|
+
/** Remove a parked entry: `undefined` when gone, else the classified fault naming the parked path. */
|
|
273
|
+
async function removeParked(slot) {
|
|
274
|
+
const parked = slot.parked;
|
|
275
|
+
try {
|
|
276
|
+
await removeEntry(parked);
|
|
277
|
+
return undefined;
|
|
278
|
+
}
|
|
279
|
+
catch (error_) {
|
|
280
|
+
const fault = classifyFsFault(error_, { side: 'destination', action: `remove the previous ${labelOf(slot)}, parked at ${parked}`, path: parked });
|
|
281
|
+
if (!isFsFaultError(fault))
|
|
282
|
+
throw error_;
|
|
283
|
+
return fault;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Remove every parked entry. A replace's refusal is a warning; a remove's is thrown
|
|
288
|
+
* (after every removal was tried), with every other refusal recorded beside it.
|
|
289
|
+
*/
|
|
290
|
+
async function finalize(slots) {
|
|
291
|
+
const parked = slots.filter((slot) => slot.parked !== undefined);
|
|
292
|
+
const outcomes = (await mapInOrder(parked, async (slot) => ({ slot, fault: await removeParked(slot) }))).filter((o) => o.fault !== undefined);
|
|
293
|
+
const thrownAt = finalizeThrows(outcomes.map((o) => ({ op: o.slot.planned.change.op })));
|
|
294
|
+
const thrown = thrownAt === undefined ? undefined : outcomes[thrownAt];
|
|
295
|
+
if (thrown !== undefined) {
|
|
296
|
+
for (const other of outcomes)
|
|
297
|
+
if (other !== thrown)
|
|
298
|
+
recordSuppressedFault(thrown.fault, other.fault);
|
|
299
|
+
throw thrown.fault;
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
warnings: outcomes.map(({ slot, fault }) => ({ code: TREE_CLEANUP_INCOMPLETE_CODE, path: slot.parked, message: messageOf(fault) })),
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Carry out `plan`: stage, park, swap, `afterSwap`, finalize — or roll back so
|
|
307
|
+
* every destination is exactly as it was.
|
|
308
|
+
*
|
|
309
|
+
* @param plan - What `planTreeChanges` decided; `keep` and `subsumed` changes are not touched
|
|
310
|
+
* @param options - `afterSwap`, run once the new tree is in place
|
|
311
|
+
* @returns The warnings of a change that is done: a previous tree left beside a replaced one
|
|
312
|
+
* @throws the first failure, after the rollback and unchanged: an `FsFaultError` (side
|
|
313
|
+
* `destination`, or the fill's declared side for a copy source's read), a `write` fill's own error or raw
|
|
314
|
+
* errno, or whatever `afterSwap` threw — with what could not be cleaned up in
|
|
315
|
+
* `suppressedFaultsOf(error)`; {@link TreeRollbackIncompleteError} (cause: that
|
|
316
|
+
* failure) when the rollback could not undo every change; for a `remove` whose
|
|
317
|
+
* parked entry cannot be removed, an `FsFaultError` side `destination` naming it
|
|
318
|
+
*/
|
|
319
|
+
export function applyTreePlan(plan, options = {}) {
|
|
320
|
+
return applyStages(plan, options);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* {@link applyTreePlan}, for a verb that reports a change it finished even when what it parked could
|
|
324
|
+
* not then be deleted (an uninstall, a clear): a failure before the commit — every swap made and
|
|
325
|
+
* `afterSwap` run — rolled back and is thrown, as by `applyTreePlan`; one after it is returned as
|
|
326
|
+
* `leftover`. The commit is the one line between "nothing finished" and "the change is done".
|
|
327
|
+
*/
|
|
328
|
+
export async function applyTreePlanOrLeftover(plan, options = {}) {
|
|
329
|
+
let committed = false;
|
|
330
|
+
try {
|
|
331
|
+
return await applyStages(plan, {
|
|
332
|
+
afterSwap: async () => {
|
|
333
|
+
await options.afterSwap?.();
|
|
334
|
+
committed = true;
|
|
335
|
+
},
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
if (!committed)
|
|
340
|
+
throw error;
|
|
341
|
+
return { warnings: [], leftover: error };
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
async function applyStages(plan, options) {
|
|
345
|
+
const slots = plan.changes.filter(isActive).map((planned) => ({ planned, createdParent: undefined, staged: undefined, parked: undefined, spelled: undefined, swapped: false }));
|
|
346
|
+
try {
|
|
347
|
+
await forEachInOrder(slots, stage);
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
await forEachInOrder(slots, (slot) => discard(slot.staged, error));
|
|
351
|
+
await removeAllMadeParents(slots, error);
|
|
352
|
+
throw error;
|
|
353
|
+
}
|
|
354
|
+
try {
|
|
355
|
+
await forEachInOrder(slots.filter((slot) => slot.planned.existing !== 'absent'), park);
|
|
356
|
+
await forEachInOrder(slots.filter((slot) => slot.staged !== undefined), swap);
|
|
357
|
+
await options.afterSwap?.();
|
|
358
|
+
}
|
|
359
|
+
catch (error) {
|
|
360
|
+
throw await rolledBack(slots, error);
|
|
361
|
+
}
|
|
362
|
+
return finalize(slots);
|
|
363
|
+
}
|
|
364
|
+
//# sourceMappingURL=apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/tree-change/apply.ts"],"names":[],"mappings":"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"}
|