@vibe-agent-toolkit/utils 0.2.0-rc.10 → 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 +112 -10
- 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 +13 -5
- package/dist/env-flag.d.ts.map +1 -1
- package/dist/env-flag.js +13 -5
- 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 +5 -4
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +5 -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 +17 -0
- package/dist/path-containment.d.ts.map +1 -1
- package/dist/path-containment.js +28 -5
- 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-content.d.ts +29 -0
- package/dist/text-content.d.ts.map +1 -1
- package/dist/text-content.js +64 -0
- package/dist/text-content.js.map +1 -1
- package/dist/text-file.d.ts +58 -6
- package/dist/text-file.d.ts.map +1 -1
- package/dist/text-file.js +111 -11
- package/dist/text-file.js.map +1 -1
- package/dist/text.d.ts +1 -1
- package/dist/text.d.ts.map +1 -1
- package/dist/text.js +1 -1
- package/dist/text.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 +96 -8
- 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,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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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The decisions of a tree copy that touch no filesystem: what it does about an entry already at a
|
|
3
|
+
* name it is about to create, when two names are one, and the refusal two source entries with one
|
|
4
|
+
* destination name get. `copy-tree.ts` is the half that makes the calls.
|
|
5
|
+
*/
|
|
6
|
+
import { FsFaultError } from '../errors/fs-fault.js';
|
|
7
|
+
/**
|
|
8
|
+
* What a tree copy does about an entry ALREADY at a name it is about to create, below its root:
|
|
9
|
+
* - `fresh`: the destination is new (a staged tree): anything there is refused (`EEXIST`), never adopted.
|
|
10
|
+
* - `merge`: the destination is the caller's own output written again (a build directory): a real
|
|
11
|
+
* directory is adopted; a file or a link is REMOVED and made anew — never written through.
|
|
12
|
+
*
|
|
13
|
+
* Under both, an entry the copy itself made is never taken for one that was "already there": two
|
|
14
|
+
* source names that are one name at the destination are refused ({@link aliasFault}).
|
|
15
|
+
*/
|
|
16
|
+
export type CopyOnto = 'fresh' | 'merge';
|
|
17
|
+
/** One entry the walk hands the copy: where it is, and where it is relative to the root (forward slashes). */
|
|
18
|
+
export interface CopiedEntry {
|
|
19
|
+
readonly path: string;
|
|
20
|
+
readonly relative: string;
|
|
21
|
+
}
|
|
22
|
+
/** The directory, relative to the root, that `relative` is in (`''`: the root). */
|
|
23
|
+
export declare const parentOf: (relative: string) => string;
|
|
24
|
+
/** The entry name of `relative`. */
|
|
25
|
+
export declare const nameOf: (relative: string) => string;
|
|
26
|
+
/**
|
|
27
|
+
* Whether two entry names are one name on a filesystem that folds letter case or Unicode form
|
|
28
|
+
* (APFS, NTFS, exFAT, SMB). Asked only AFTER the OS answered `EEXIST` for the second of them, to say
|
|
29
|
+
* which earlier entry it collided with: it names the pair, it never decides that there is one.
|
|
30
|
+
*/
|
|
31
|
+
export declare function sameNameWhereFolded(a: string, b: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Whether a sibling this copy made, whose name folds to the name that just answered `EEXIST`, is the
|
|
34
|
+
* entry it collided with — asked only when identity did not find one that is.
|
|
35
|
+
*
|
|
36
|
+
* It is not when the OS proved them TWO entries: both are there, each with an identity, none shared.
|
|
37
|
+
* That is a tree that keeps the two names apart (case-sensitive), and what stands at the colliding
|
|
38
|
+
* name was there before this copy — a `merge`'s previous output, to take over as any other.
|
|
39
|
+
*
|
|
40
|
+
* @param sameness - What identity answered for the sibling's copy against the colliding name
|
|
41
|
+
* @param collidingPresent - Whether the colliding name holds an entry the copy can examine
|
|
42
|
+
*/
|
|
43
|
+
export declare function foldedNameIsTwin(sameness: 'same' | 'different' | 'unknown', collidingPresent: boolean): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* What a copy does at a name that already holds an entry it did not make.
|
|
46
|
+
*
|
|
47
|
+
* @param onto - The copy's mode
|
|
48
|
+
* @param kind - What the copy is about to make there
|
|
49
|
+
* @param thereIsDirectory - Whether the entry there is a real directory (not a link to one); read only under `merge`
|
|
50
|
+
* @returns `refuse` (rethrow the `EEXIST`), `adopt` (keep the directory), or `replace` (remove the file or link, make it anew)
|
|
51
|
+
*/
|
|
52
|
+
export declare function mayTakeOver(onto: CopyOnto, kind: 'directory' | 'leaf', thereIsDirectory: boolean): 'refuse' | 'adopt' | 'replace';
|
|
53
|
+
/**
|
|
54
|
+
* Two source entries that are ONE name where the copy goes: the source's own layout cannot be
|
|
55
|
+
* copied there. A `source` fault (origin `content`) whatever side the tree is read on, naming both.
|
|
56
|
+
*/
|
|
57
|
+
export declare function aliasFault(first: CopiedEntry, second: CopiedEntry, cause: unknown): FsFaultError;
|
|
58
|
+
//# sourceMappingURL=copy-decisions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-decisions.d.ts","sourceRoot":"","sources":["../../src/tree-change/copy-decisions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;AAEzC,8GAA8G;AAC9G,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,mFAAmF;AACnF,eAAO,MAAM,QAAQ,GAAI,UAAU,MAAM,KAAG,MAAsF,CAAC;AAEnI,oCAAoC;AACpC,eAAO,MAAM,MAAM,GAAI,UAAU,MAAM,KAAG,MAAuD,CAAC;AAKlG;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,EAAE,gBAAgB,EAAE,OAAO,GAAG,OAAO,CAE/G;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,GAAG,MAAM,EAAE,gBAAgB,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAKjI;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,GAAG,YAAY,CAUhG"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The decisions of a tree copy that touch no filesystem: what it does about an entry already at a
|
|
3
|
+
* name it is about to create, when two names are one, and the refusal two source entries with one
|
|
4
|
+
* destination name get. `copy-tree.ts` is the half that makes the calls.
|
|
5
|
+
*/
|
|
6
|
+
import { FsFaultError } from '../errors/fs-fault.js';
|
|
7
|
+
/** The directory, relative to the root, that `relative` is in (`''`: the root). */
|
|
8
|
+
export const parentOf = (relative) => (relative.includes('/') ? relative.slice(0, relative.lastIndexOf('/')) : '');
|
|
9
|
+
/** The entry name of `relative`. */
|
|
10
|
+
export const nameOf = (relative) => relative.slice(relative.lastIndexOf('/') + 1);
|
|
11
|
+
/** A name as a case- and normalisation-insensitive filesystem compares it, near enough to find a pair to name. */
|
|
12
|
+
const folded = (name) => name.normalize('NFKD').toLowerCase();
|
|
13
|
+
/**
|
|
14
|
+
* Whether two entry names are one name on a filesystem that folds letter case or Unicode form
|
|
15
|
+
* (APFS, NTFS, exFAT, SMB). Asked only AFTER the OS answered `EEXIST` for the second of them, to say
|
|
16
|
+
* which earlier entry it collided with: it names the pair, it never decides that there is one.
|
|
17
|
+
*/
|
|
18
|
+
export function sameNameWhereFolded(a, b) {
|
|
19
|
+
return folded(a) === folded(b);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Whether a sibling this copy made, whose name folds to the name that just answered `EEXIST`, is the
|
|
23
|
+
* entry it collided with — asked only when identity did not find one that is.
|
|
24
|
+
*
|
|
25
|
+
* It is not when the OS proved them TWO entries: both are there, each with an identity, none shared.
|
|
26
|
+
* That is a tree that keeps the two names apart (case-sensitive), and what stands at the colliding
|
|
27
|
+
* name was there before this copy — a `merge`'s previous output, to take over as any other.
|
|
28
|
+
*
|
|
29
|
+
* @param sameness - What identity answered for the sibling's copy against the colliding name
|
|
30
|
+
* @param collidingPresent - Whether the colliding name holds an entry the copy can examine
|
|
31
|
+
*/
|
|
32
|
+
export function foldedNameIsTwin(sameness, collidingPresent) {
|
|
33
|
+
return !(sameness === 'different' && collidingPresent);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* What a copy does at a name that already holds an entry it did not make.
|
|
37
|
+
*
|
|
38
|
+
* @param onto - The copy's mode
|
|
39
|
+
* @param kind - What the copy is about to make there
|
|
40
|
+
* @param thereIsDirectory - Whether the entry there is a real directory (not a link to one); read only under `merge`
|
|
41
|
+
* @returns `refuse` (rethrow the `EEXIST`), `adopt` (keep the directory), or `replace` (remove the file or link, make it anew)
|
|
42
|
+
*/
|
|
43
|
+
export function mayTakeOver(onto, kind, thereIsDirectory) {
|
|
44
|
+
if (onto === 'fresh')
|
|
45
|
+
return 'refuse';
|
|
46
|
+
// A merge never swaps one kind for the other: a directory is not deleted for a file, nor a file for a directory.
|
|
47
|
+
if (thereIsDirectory !== (kind === 'directory'))
|
|
48
|
+
return 'refuse';
|
|
49
|
+
return kind === 'directory' ? 'adopt' : 'replace';
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Two source entries that are ONE name where the copy goes: the source's own layout cannot be
|
|
53
|
+
* copied there. A `source` fault (origin `content`) whatever side the tree is read on, naming both.
|
|
54
|
+
*/
|
|
55
|
+
export function aliasFault(first, second, cause) {
|
|
56
|
+
return new FsFaultError({
|
|
57
|
+
side: 'source',
|
|
58
|
+
faultClass: 'occupied',
|
|
59
|
+
errno: 'EEXIST',
|
|
60
|
+
path: second.path,
|
|
61
|
+
origin: 'content',
|
|
62
|
+
action: `copy both ${first.path} and ${second.path}: where the copy goes their two names are one name (they differ only in letter case or Unicode form), so one would overwrite the other`,
|
|
63
|
+
cause,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=copy-decisions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-decisions.js","sourceRoot":"","sources":["../../src/tree-change/copy-decisions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAmBrD,mFAAmF;AACnF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,QAAgB,EAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAEnI,oCAAoC;AACpC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,QAAgB,EAAU,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAElG,kHAAkH;AAClH,MAAM,MAAM,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;AAE9E;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,CAAS,EAAE,CAAS;IACtD,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAA0C,EAAE,gBAAyB;IACpG,OAAO,CAAC,CAAC,QAAQ,KAAK,WAAW,IAAI,gBAAgB,CAAC,CAAC;AACzD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,IAAc,EAAE,IAA0B,EAAE,gBAAyB;IAC/F,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,QAAQ,CAAC;IACtC,iHAAiH;IACjH,IAAI,gBAAgB,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC;QAAE,OAAO,QAAQ,CAAC;IACjE,OAAO,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AACpD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAkB,EAAE,MAAmB,EAAE,KAAc;IAChF,OAAO,IAAI,YAAY,CAAC;QACtB,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,UAAU;QACtB,KAAK,EAAE,QAAQ;QACf,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,aAAa,KAAK,CAAC,IAAI,QAAQ,MAAM,CAAC,IAAI,wIAAwI;QAC1L,KAAK;KACN,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `copyTree`: copy a directory tree by the same walk `proveTreeReadable` proves it
|
|
3
|
+
* with, reading each file from the very handle the walk judged a regular file.
|
|
4
|
+
*/
|
|
5
|
+
import { type FsSide } from '../errors/fs-fault.js';
|
|
6
|
+
import { type CopyOnto } from './copy-decisions.js';
|
|
7
|
+
import { type FileUnderOptions } from './files.js';
|
|
8
|
+
import type { ProveTreeReadableOptions } from './readable-tree.js';
|
|
9
|
+
import { type TreeVisitor } from './tree-walk.js';
|
|
10
|
+
/** Where a tree copy goes: `relative` (forward slashes; `''` for the root itself) under `root`. */
|
|
11
|
+
interface CopyDestination {
|
|
12
|
+
/**
|
|
13
|
+
* A directory that is the CALLER's: one it made, or one its user named. Made with its parents
|
|
14
|
+
* when absent — whatever stands above it is the caller's too, a link in the user's own layout
|
|
15
|
+
* (`~/.claude` kept in a dotfiles repository) included — and adopted when a real directory. A link
|
|
16
|
+
* or a file AT its name is never adopted ({@link claimRoot}).
|
|
17
|
+
*/
|
|
18
|
+
readonly root: string;
|
|
19
|
+
/**
|
|
20
|
+
* Where under `root` the copy goes. Everything between the two is inside a tree that may hold
|
|
21
|
+
* what an earlier copy kept — links included — so each component must be a real directory
|
|
22
|
+
* (`makeDirectoryUnder`): a link or a file standing there refuses the copy, naming it.
|
|
23
|
+
*/
|
|
24
|
+
readonly relative: string;
|
|
25
|
+
}
|
|
26
|
+
/** What {@link copyTree} is told: the walk, the side its reads are on, and what it does about what is already there. */
|
|
27
|
+
export interface CopyTreeOptions extends ProveTreeReadableOptions {
|
|
28
|
+
/** Required: only the caller knows whether its destination is new ({@link CopyOnto}). */
|
|
29
|
+
readonly onto: CopyOnto;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The visitor that writes the copy of each entry the walk accepts under `dest`; every read of the
|
|
33
|
+
* copied tree is on `side`.
|
|
34
|
+
*
|
|
35
|
+
* Every create below the root is EXCLUSIVE and never follows a link: a file is opened `wx`, a
|
|
36
|
+
* directory made by a plain `mkdir`, a link made only where nothing is. So a create that finds
|
|
37
|
+
* something answers `EEXIST`, and what happens then is decided in this order:
|
|
38
|
+
*
|
|
39
|
+
* 1. The entry there is one THIS copy made — the same entry by identity, or (where the OS will not
|
|
40
|
+
* say) a sibling whose name is the same once case and Unicode form are folded: two source names,
|
|
41
|
+
* one destination name. Refused as the source's layout (`aliasFault`), under either mode.
|
|
42
|
+
* 2. `fresh`: refused as it is (`EEXIST`), for the caller's boundary to classify.
|
|
43
|
+
* 3. `merge`: a real directory is adopted; a file or a link is removed (the link, never its target)
|
|
44
|
+
* and the entry made anew; anything else — a directory where a file goes, a link where a
|
|
45
|
+
* directory goes — is refused as it is (`mayTakeOver`).
|
|
46
|
+
*
|
|
47
|
+
* Where the copy goes is made by {@link claimDestination}: the root is the caller's (made with its
|
|
48
|
+
* parents when absent, adopted when a real directory, refused `EEXIST` when a link or a file — a link
|
|
49
|
+
* taken for it would put the whole copy where it points), and every directory from the root down to
|
|
50
|
+
* the copy is a real one or is refused as the layout of the tree it is in.
|
|
51
|
+
*
|
|
52
|
+
* Exported for `copyTree` and for the suite that hands it two entries by name — a real alias needs
|
|
53
|
+
* a case-sensitive source and a case-folding destination, which no one temp directory offers.
|
|
54
|
+
*/
|
|
55
|
+
export declare function copyVisitor(where: CopyDestination, copied: string, side: FsSide, onto: CopyOnto): TreeVisitor;
|
|
56
|
+
/**
|
|
57
|
+
* Copy the directory `source` to `relative` under `root` ({@link CopyDestination}).
|
|
58
|
+
*
|
|
59
|
+
* `root` is a directory the caller made or its user named: created, with its parents, when absent;
|
|
60
|
+
* adopted when a real directory; refused, `EEXIST`, when a link or a file stands there. `relative`
|
|
61
|
+
* is `''` for a copy onto `root` itself. A copy that goes INSIDE a tree — a pool skill into a staged
|
|
62
|
+
* plugin that earlier copies filled, links kept — names that tree's root and where under it, and
|
|
63
|
+
* every directory between the two must then be a real one (made when absent): a link or a file
|
|
64
|
+
* there is a `source` fault (origin `content`, class `occupied`) naming it, never followed. So a
|
|
65
|
+
* caller cannot reach through a link by how deep its destination is: the only directory taken on
|
|
66
|
+
* trust is the one it declares as `root`.
|
|
67
|
+
*
|
|
68
|
+
* Entries are walked, and refused, exactly as `proveTreeReadable` proves them (see
|
|
69
|
+
* `tree-walk.ts`): a `follow-contained` link is copied as what it points at, inside
|
|
70
|
+
* the source only; a `preserve` link is copied as a link, its target string
|
|
71
|
+
* verbatim and never followed — its chain is read by text alone to give the copy its `file`/`dir`
|
|
72
|
+
* type, and one through a network or device path is refused (a `refused` fault on `options.side`)
|
|
73
|
+
* before anything is made; an entry `filter` excludes is never touched; a named
|
|
74
|
+
* pipe, socket or device is refused unopened. Each file is copied from the handle
|
|
75
|
+
* `fstat` judged, with its mode. Each directory takes its source's mode with the
|
|
76
|
+
* owner's rwx kept (`| 0o700`): a read-only source must not become a copy nothing
|
|
77
|
+
* can fill or remove.
|
|
78
|
+
*
|
|
79
|
+
* Below the copy's own directory nothing already there is ever adopted or written through, and two source
|
|
80
|
+
* entries that are one name there are refused as the source's layout (a `source` fault
|
|
81
|
+
* naming both): see {@link copyVisitor} and `options.onto`.
|
|
82
|
+
*
|
|
83
|
+
* The copy names no side for what it WRITES: a failure writing the copy is the raw
|
|
84
|
+
* errno, for the caller's boundary to classify — a link this host cannot create, and an
|
|
85
|
+
* `EEXIST` for something already at a name of a `fresh` destination, included. What it READS is on the side the caller names, as the proof's reads
|
|
86
|
+
* are: a refusal is a classified fault on `options.side` (origin `content`) naming
|
|
87
|
+
* the entry. Only the caller knows whether the tree is an input (`source`), VAT's
|
|
88
|
+
* staging (`environment`) or a copy already made into user state (`destination`).
|
|
89
|
+
*
|
|
90
|
+
* @param source - The directory to copy
|
|
91
|
+
* @param root - The directory the caller made or owns, which the copy goes into or under
|
|
92
|
+
* @param relative - Where under `root` the copy goes, forward slashes; `''` for `root` itself
|
|
93
|
+
* @param options - `links`, `filter` and `side`, exactly as `proveTreeReadable` was given them, and `onto`
|
|
94
|
+
*/
|
|
95
|
+
export declare function copyTree(source: string, root: string, relative: string, options: CopyTreeOptions): Promise<void>;
|
|
96
|
+
/** What {@link copyRegularFile} is told: the file it reads, and (as `writeFileUnder` is) the entry already where the copy goes. */
|
|
97
|
+
export interface CopyRegularFileOptions extends FileUnderOptions {
|
|
98
|
+
/** The side of the verb the file is on, as for {@link copyTree}. */
|
|
99
|
+
readonly side: FsSide;
|
|
100
|
+
/** What the file is, for a refused read's message: `read <reading>` (`linked file docs/a.md`). */
|
|
101
|
+
readonly reading: string;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Copy ONE regular file to `relative` under `root`, as {@link copyTree} copies a file: opened
|
|
105
|
+
* without blocking and judged by `fstat` on that handle (a named pipe, socket or device is refused
|
|
106
|
+
* before a byte is read, never waited on), its bytes copied from that very handle, its mode
|
|
107
|
+
* carried over.
|
|
108
|
+
*
|
|
109
|
+
* The copy is made as `writeFileUnder` makes a file — it is the same primitive: every directory of
|
|
110
|
+
* `relative` must be a real directory (made by a plain `mkdir` when absent), the file is created
|
|
111
|
+
* exclusively, and its bytes and mode go to that handle. So it never writes through a link, at the
|
|
112
|
+
* file's name or on the way to it; `options.existing` decides a regular file already there.
|
|
113
|
+
*
|
|
114
|
+
* Every read is a classified fault on `options.side` (origin `content`), naming what was read. An
|
|
115
|
+
* entry in the copy's way is a `source` fault (origin `content`, class `occupied`) naming it; any
|
|
116
|
+
* other failure writing is the raw errno, for the caller's boundary to classify.
|
|
117
|
+
*
|
|
118
|
+
* @param source - The file to copy
|
|
119
|
+
* @param root - The root of the tree the copy goes into, which the caller made
|
|
120
|
+
* @param relative - Where the copy goes, relative to `root`, forward slashes
|
|
121
|
+
* @param options - The side `source` is on and what it is; `existing` and `writing`, for the copy
|
|
122
|
+
*/
|
|
123
|
+
export declare function copyRegularFile(source: string, root: string, relative: string, options: CopyRegularFileOptions): Promise<void>;
|
|
124
|
+
export {};
|
|
125
|
+
//# sourceMappingURL=copy-tree.d.ts.map
|