@danieljvdm/dev-kit 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/path-digest.ts +17 -3
- package/src/sync.ts +47 -5
package/package.json
CHANGED
package/src/path-digest.ts
CHANGED
|
@@ -27,6 +27,7 @@ const textEncoder = new TextEncoder();
|
|
|
27
27
|
// Git preserves only the executable distinction for regular files. Canonicalizing
|
|
28
28
|
// the remaining bits keeps digests stable across checkout and copy umasks.
|
|
29
29
|
const canonicalFileMode = (mode: number): number => ((mode & 0o111) === 0 ? 0o644 : 0o755);
|
|
30
|
+
const rawFileMode = (mode: number): number => mode & 0o777;
|
|
30
31
|
|
|
31
32
|
const frame = (value: string | Uint8Array): Uint8Array => {
|
|
32
33
|
const bytes = typeof value === "string" ? textEncoder.encode(value) : value;
|
|
@@ -75,6 +76,7 @@ const digestFrames = Effect.fn("digestPathFrames")(function* (
|
|
|
75
76
|
|
|
76
77
|
const digestFileSystemPath = Effect.fn("digestFileSystemPath")(function* (
|
|
77
78
|
absolutePath: string,
|
|
79
|
+
fileMode: (mode: number) => number,
|
|
78
80
|
): Effect.fn.Return<
|
|
79
81
|
ObservedPath,
|
|
80
82
|
PlatformError.PlatformError | PathInspectionError,
|
|
@@ -107,7 +109,7 @@ const digestFileSystemPath = Effect.fn("digestFileSystemPath")(function* (
|
|
|
107
109
|
kind: "file",
|
|
108
110
|
digest: yield* digestFrames([
|
|
109
111
|
"file-v1",
|
|
110
|
-
String(
|
|
112
|
+
String(fileMode(info.mode)),
|
|
111
113
|
yield* fs.readFile(absolutePath),
|
|
112
114
|
]),
|
|
113
115
|
};
|
|
@@ -119,7 +121,7 @@ const digestFileSystemPath = Effect.fn("digestFileSystemPath")(function* (
|
|
|
119
121
|
|
|
120
122
|
for (const entry of entries) {
|
|
121
123
|
const childPath = path.join(absolutePath, entry);
|
|
122
|
-
const child = yield* digestFileSystemPath(childPath);
|
|
124
|
+
const child = yield* digestFileSystemPath(childPath, fileMode);
|
|
123
125
|
|
|
124
126
|
if (child.kind === "missing") {
|
|
125
127
|
return yield* new PathInspectionError({
|
|
@@ -142,7 +144,19 @@ const digestFileSystemPath = Effect.fn("digestFileSystemPath")(function* (
|
|
|
142
144
|
});
|
|
143
145
|
|
|
144
146
|
export const observePath = Effect.fn("observeManagedPath")(function* (absolutePath: string) {
|
|
145
|
-
return yield* digestFileSystemPath(absolutePath).pipe(
|
|
147
|
+
return yield* digestFileSystemPath(absolutePath, canonicalFileMode).pipe(
|
|
148
|
+
Effect.mapError((cause) =>
|
|
149
|
+
cause instanceof PathInspectionError
|
|
150
|
+
? cause
|
|
151
|
+
: new PathInspectionError({ path: absolutePath, operation: "inspect", cause }),
|
|
152
|
+
),
|
|
153
|
+
);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
export const observePathWithRawModes = Effect.fn("observeManagedPathWithRawModes")(function* (
|
|
157
|
+
absolutePath: string,
|
|
158
|
+
) {
|
|
159
|
+
return yield* digestFileSystemPath(absolutePath, rawFileMode).pipe(
|
|
146
160
|
Effect.mapError((cause) =>
|
|
147
161
|
cause instanceof PathInspectionError
|
|
148
162
|
? cause
|
package/src/sync.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
digestSymlinkTarget,
|
|
24
24
|
digestText,
|
|
25
25
|
observePath,
|
|
26
|
+
observePathWithRawModes,
|
|
26
27
|
type ObservedPath,
|
|
27
28
|
} from "./path-digest.ts";
|
|
28
29
|
import { readDirectDependencyNames } from "./project-package.ts";
|
|
@@ -430,6 +431,27 @@ const outputIdentity = (output: ManagedOutput) =>
|
|
|
430
431
|
: { sourcePath: output.sourcePath }),
|
|
431
432
|
});
|
|
432
433
|
|
|
434
|
+
const outputOwnershipIdentity = (output: ManagedOutput) =>
|
|
435
|
+
JSON.stringify({
|
|
436
|
+
resourceId: output.resourceId,
|
|
437
|
+
path: output.path,
|
|
438
|
+
mode: output.mode,
|
|
439
|
+
kind: output.kind,
|
|
440
|
+
...("skill" in output
|
|
441
|
+
? { skill: output.skill, target: output.target }
|
|
442
|
+
: { sourcePath: output.sourcePath }),
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
const usesRawFileModeDigests = (toolVersion: string): boolean => {
|
|
446
|
+
const match = /^(\d+)\.(\d+)\./.exec(toolVersion);
|
|
447
|
+
|
|
448
|
+
if (match === null) return false;
|
|
449
|
+
const major = Number(match[1]);
|
|
450
|
+
const minor = Number(match[2]);
|
|
451
|
+
|
|
452
|
+
return major === 0 && minor <= 6;
|
|
453
|
+
};
|
|
454
|
+
|
|
433
455
|
const validateInventory = Effect.fn("validateManagedInventory")(function* (
|
|
434
456
|
projectDir: string,
|
|
435
457
|
outputs: ReadonlyArray<ManagedOutput | OwnershipReceipt>,
|
|
@@ -743,12 +765,31 @@ const planDesiredOutputs = Effect.fn("planDesiredSkillOutputs")(function* (
|
|
|
743
765
|
const receipt = receiptsById.get(output.resourceId);
|
|
744
766
|
const sameReceipt = receipt?.path === output.path ? receipt : undefined;
|
|
745
767
|
const locked = lockById.get(output.resourceId);
|
|
746
|
-
const
|
|
768
|
+
const matchingLockedOutput =
|
|
769
|
+
locked !== undefined &&
|
|
770
|
+
outputOwnershipIdentity(locked) === outputOwnershipIdentity(output) &&
|
|
771
|
+
observed.kind === locked.kind
|
|
772
|
+
? locked
|
|
773
|
+
: undefined;
|
|
774
|
+
const rawModeObservation =
|
|
775
|
+
matchingLockedOutput !== undefined &&
|
|
776
|
+
observed.kind !== "missing" &&
|
|
777
|
+
observed.digest !== matchingLockedOutput.digest &&
|
|
778
|
+
currentLock !== undefined &&
|
|
779
|
+
usesRawFileModeDigests(currentLock.toolVersion)
|
|
780
|
+
? yield* observePathWithRawModes(output.destination)
|
|
781
|
+
: undefined;
|
|
782
|
+
const lockedOwnsObserved =
|
|
783
|
+
matchingLockedOutput !== undefined &&
|
|
784
|
+
observed.kind !== "missing" &&
|
|
785
|
+
(observed.digest === matchingLockedOutput.digest ||
|
|
786
|
+
(rawModeObservation?.kind === matchingLockedOutput.kind &&
|
|
787
|
+
rawModeObservation.digest === matchingLockedOutput.digest));
|
|
747
788
|
|
|
748
789
|
if (observed.kind === "missing") {
|
|
749
790
|
actions.push({ action: "create", desired: output, observed });
|
|
750
791
|
} else if (observed.kind === output.kind && observed.digest === output.digest) {
|
|
751
|
-
if (sameReceipt ||
|
|
792
|
+
if (sameReceipt || lockedOwnsObserved || ("adoptIfExact" in output && output.adoptIfExact)) {
|
|
752
793
|
actions.push({ action: "unchanged", desired: output, observed, adopted: !sameReceipt });
|
|
753
794
|
} else {
|
|
754
795
|
actions.push({
|
|
@@ -758,9 +799,10 @@ const planDesiredOutputs = Effect.fn("planDesiredSkillOutputs")(function* (
|
|
|
758
799
|
});
|
|
759
800
|
}
|
|
760
801
|
} else if (
|
|
761
|
-
sameReceipt &&
|
|
762
|
-
|
|
763
|
-
|
|
802
|
+
(sameReceipt !== undefined &&
|
|
803
|
+
observed.kind === sameReceipt.kind &&
|
|
804
|
+
observed.digest === sameReceipt.digest) ||
|
|
805
|
+
lockedOwnsObserved
|
|
764
806
|
) {
|
|
765
807
|
actions.push({ action: "update", desired: output, observed });
|
|
766
808
|
} else {
|