@tinyrack/devsync 1.1.0 → 1.3.0
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 +230 -62
- package/dist/cli/base-command.d.ts +14 -0
- package/dist/cli/base-command.d.ts.map +1 -0
- package/dist/cli/base-command.js +22 -0
- package/dist/cli/base-command.js.map +1 -0
- package/dist/cli/commands/dir.d.ts +8 -0
- package/dist/cli/commands/dir.d.ts.map +1 -0
- package/dist/cli/commands/dir.js +16 -0
- package/dist/cli/commands/dir.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +8 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +18 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/index.d.ts +23 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +23 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/init.d.ts +15 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +43 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/machine/list.d.ts +7 -0
- package/dist/cli/commands/machine/list.d.ts.map +1 -0
- package/dist/cli/commands/machine/list.js +12 -0
- package/dist/cli/commands/machine/list.js.map +1 -0
- package/dist/cli/commands/machine/use.d.ts +11 -0
- package/dist/cli/commands/machine/use.d.ts.map +1 -0
- package/dist/cli/commands/machine/use.js +28 -0
- package/dist/cli/commands/machine/use.js.map +1 -0
- package/dist/cli/commands/pull.d.ts +12 -0
- package/dist/cli/commands/pull.d.ts.map +1 -0
- package/dist/cli/commands/pull.js +34 -0
- package/dist/cli/commands/pull.js.map +1 -0
- package/dist/cli/commands/push.d.ts +12 -0
- package/dist/cli/commands/push.d.ts.map +1 -0
- package/dist/cli/commands/push.js +34 -0
- package/dist/cli/commands/push.js.map +1 -0
- package/dist/cli/commands/status.d.ts +11 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +27 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/track.d.ts +16 -0
- package/dist/cli/commands/track.d.ts.map +1 -0
- package/dist/cli/commands/track.js +82 -0
- package/dist/cli/commands/track.js.map +1 -0
- package/dist/cli/commands/untrack.d.ts +11 -0
- package/dist/cli/commands/untrack.d.ts.map +1 -0
- package/dist/cli/commands/untrack.js +28 -0
- package/dist/cli/commands/untrack.js.map +1 -0
- package/dist/config/global-config.d.ts +21 -0
- package/dist/config/global-config.d.ts.map +1 -0
- package/dist/config/global-config.js +106 -0
- package/dist/config/global-config.js.map +1 -0
- package/dist/config/platform.d.ts +11 -0
- package/dist/config/platform.d.ts.map +1 -0
- package/dist/config/platform.js +19 -0
- package/dist/config/platform.js.map +1 -0
- package/dist/config/sync.d.ts +107 -0
- package/dist/config/sync.d.ts.map +1 -0
- package/dist/config/sync.js +424 -0
- package/dist/config/sync.js.map +1 -0
- package/dist/config/xdg.d.ts +14 -0
- package/dist/config/xdg.d.ts.map +1 -0
- package/dist/config/xdg.js +102 -0
- package/dist/config/xdg.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/{src/index.ts → dist/index.js} +1 -1
- package/dist/index.js.map +1 -0
- package/dist/lib/file-mode.d.ts +3 -0
- package/dist/lib/file-mode.d.ts.map +1 -0
- package/dist/lib/file-mode.js +7 -0
- package/dist/lib/file-mode.js.map +1 -0
- package/dist/lib/output.d.ts +31 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +198 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/path.d.ts +5 -0
- package/dist/lib/path.d.ts.map +1 -0
- package/dist/lib/path.js +25 -0
- package/dist/lib/path.js.map +1 -0
- package/dist/lib/string.d.ts +2 -0
- package/dist/lib/string.d.ts.map +1 -0
- package/dist/lib/string.js +4 -0
- package/dist/lib/string.js.map +1 -0
- package/dist/lib/validation.d.ts +3 -0
- package/dist/lib/validation.d.ts.map +1 -0
- package/dist/lib/validation.js +9 -0
- package/dist/lib/validation.js.map +1 -0
- package/dist/services/add.d.ts +20 -0
- package/dist/services/add.d.ts.map +1 -0
- package/dist/services/add.js +161 -0
- package/dist/services/add.js.map +1 -0
- package/dist/services/config-file.d.ts +45 -0
- package/dist/services/config-file.d.ts.map +1 -0
- package/dist/services/config-file.js +35 -0
- package/dist/services/config-file.js.map +1 -0
- package/dist/services/crypto.d.ts +9 -0
- package/dist/services/crypto.d.ts.map +1 -0
- package/dist/services/crypto.js +75 -0
- package/dist/services/crypto.js.map +1 -0
- package/dist/services/doctor.d.ts +16 -0
- package/dist/services/doctor.d.ts.map +1 -0
- package/dist/services/doctor.js +84 -0
- package/dist/services/doctor.js.map +1 -0
- package/dist/services/error.d.ts +14 -0
- package/dist/services/error.d.ts.map +1 -0
- package/dist/services/error.js +38 -0
- package/dist/services/error.js.map +1 -0
- package/dist/services/filesystem.d.ts +15 -0
- package/dist/services/filesystem.d.ts.map +1 -0
- package/dist/services/filesystem.js +113 -0
- package/dist/services/filesystem.js.map +1 -0
- package/dist/services/forget.d.ts +14 -0
- package/dist/services/forget.d.ts.map +1 -0
- package/dist/services/forget.js +124 -0
- package/dist/services/forget.js.map +1 -0
- package/dist/services/git.d.ts +10 -0
- package/dist/services/git.d.ts.map +1 -0
- package/dist/services/git.js +57 -0
- package/dist/services/git.js.map +1 -0
- package/dist/services/init.d.ts +19 -0
- package/dist/services/init.d.ts.map +1 -0
- package/dist/services/init.js +203 -0
- package/dist/services/init.js.map +1 -0
- package/dist/services/local-materialization.d.ts +28 -0
- package/dist/services/local-materialization.d.ts.map +1 -0
- package/dist/services/local-materialization.js +262 -0
- package/dist/services/local-materialization.js.map +1 -0
- package/dist/services/local-snapshot.d.ts +25 -0
- package/dist/services/local-snapshot.d.ts.map +1 -0
- package/dist/services/local-snapshot.js +93 -0
- package/dist/services/local-snapshot.js.map +1 -0
- package/dist/services/machine.d.ts +40 -0
- package/dist/services/machine.d.ts.map +1 -0
- package/dist/services/machine.js +113 -0
- package/dist/services/machine.js.map +1 -0
- package/dist/services/paths.d.ts +13 -0
- package/dist/services/paths.d.ts.map +1 -0
- package/dist/services/paths.js +71 -0
- package/dist/services/paths.js.map +1 -0
- package/dist/services/pull.d.ts +28 -0
- package/dist/services/pull.d.ts.map +1 -0
- package/dist/services/pull.js +67 -0
- package/dist/services/pull.js.map +1 -0
- package/dist/services/push.d.ts +35 -0
- package/dist/services/push.d.ts.map +1 -0
- package/dist/services/push.js +96 -0
- package/dist/services/push.js.map +1 -0
- package/dist/services/repo-artifacts.d.ts +52 -0
- package/dist/services/repo-artifacts.d.ts.map +1 -0
- package/dist/services/repo-artifacts.js +251 -0
- package/dist/services/repo-artifacts.js.map +1 -0
- package/dist/services/repo-snapshot.d.ts +6 -0
- package/dist/services/repo-snapshot.d.ts.map +1 -0
- package/dist/services/repo-snapshot.js +163 -0
- package/dist/services/repo-snapshot.js.map +1 -0
- package/dist/services/runtime.d.ts +40 -0
- package/dist/services/runtime.d.ts.map +1 -0
- package/dist/services/runtime.js +71 -0
- package/dist/services/runtime.js.map +1 -0
- package/dist/services/set.d.ts +38 -0
- package/dist/services/set.d.ts.map +1 -0
- package/dist/services/set.js +184 -0
- package/dist/services/set.js.map +1 -0
- package/dist/services/status.d.ts +30 -0
- package/dist/services/status.d.ts.map +1 -0
- package/dist/services/status.js +35 -0
- package/dist/services/status.js.map +1 -0
- package/package.json +15 -7
- package/src/cli/commands/add.ts +0 -40
- package/src/cli/commands/cd.ts +0 -80
- package/src/cli/commands/doctor.ts +0 -20
- package/src/cli/commands/forget.ts +0 -32
- package/src/cli/commands/index.ts +0 -23
- package/src/cli/commands/init.ts +0 -43
- package/src/cli/commands/list.ts +0 -17
- package/src/cli/commands/pull.ts +0 -31
- package/src/cli/commands/push.ts +0 -31
- package/src/cli/commands/set.ts +0 -47
- package/src/cli/commands/status.ts +0 -18
- package/src/cli/sync-output.test.ts +0 -173
- package/src/cli/sync-output.ts +0 -200
- package/src/config/sync.test.ts +0 -609
- package/src/config/sync.ts +0 -572
- package/src/config/xdg.ts +0 -138
- package/src/lib/string.test.ts +0 -13
- package/src/lib/string.ts +0 -3
- package/src/lib/validation.test.ts +0 -32
- package/src/lib/validation.ts +0 -11
- package/src/services/add.ts +0 -178
- package/src/services/config-file.test.ts +0 -161
- package/src/services/config-file.ts +0 -101
- package/src/services/crypto.test.ts +0 -132
- package/src/services/crypto.ts +0 -83
- package/src/services/doctor.ts +0 -142
- package/src/services/error.ts +0 -6
- package/src/services/filesystem.test.ts +0 -171
- package/src/services/filesystem.ts +0 -183
- package/src/services/forget.ts +0 -261
- package/src/services/git.test.ts +0 -83
- package/src/services/git.ts +0 -74
- package/src/services/init.test.ts +0 -109
- package/src/services/init.ts +0 -244
- package/src/services/list.ts +0 -63
- package/src/services/local-materialization.ts +0 -421
- package/src/services/local-snapshot.ts +0 -173
- package/src/services/paths.test.ts +0 -74
- package/src/services/paths.ts +0 -98
- package/src/services/pull.ts +0 -144
- package/src/services/push.ts +0 -168
- package/src/services/repo-artifacts.ts +0 -262
- package/src/services/repo-snapshot.ts +0 -197
- package/src/services/runtime.ts +0 -57
- package/src/services/set.ts +0 -383
- package/src/services/status.ts +0 -57
- package/src/services/sync.dry-run.test.ts +0 -179
- package/src/services/sync.runtime.test.ts +0 -756
- package/src/services/sync.service.test.ts +0 -1169
- package/src/test/helpers/sync-fixture.ts +0 -47
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { isAbsolute, relative, resolve } from "node:path";
|
|
2
|
+
import { normalizeSyncRepoPath, } from "#app/config/sync.js";
|
|
3
|
+
import { expandHomePath } from "#app/config/xdg.js";
|
|
4
|
+
import { isExplicitLocalPath } from "#app/lib/path.js";
|
|
5
|
+
export { buildDirectoryKey, doPathsOverlap, isExplicitLocalPath, isPathEqualOrNested, } from "#app/lib/path.js";
|
|
6
|
+
import { DevsyncError } from "./error.js";
|
|
7
|
+
export const resolveCommandTargetPath = (target, environment, cwd) => {
|
|
8
|
+
return resolve(cwd, expandHomePath(target, environment));
|
|
9
|
+
};
|
|
10
|
+
export const buildRepoPathWithinRoot = (absolutePath, rootPath, description) => {
|
|
11
|
+
const relativePath = relative(rootPath, absolutePath);
|
|
12
|
+
if (relativePath === "") {
|
|
13
|
+
throw new DevsyncError(`${description} resolves to the root directory, which cannot be tracked directly.`, {
|
|
14
|
+
code: "TARGET_ROOT_DISALLOWED",
|
|
15
|
+
details: [`Target: ${absolutePath}`, `Root: ${rootPath}`],
|
|
16
|
+
hint: `Choose a file or subdirectory inside ${rootPath}.`,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
if (isAbsolute(relativePath) ||
|
|
20
|
+
relativePath.startsWith("..") ||
|
|
21
|
+
relativePath === "..") {
|
|
22
|
+
throw new DevsyncError(`${description} must stay inside the configured home root.`, {
|
|
23
|
+
code: "TARGET_OUTSIDE_ROOT",
|
|
24
|
+
details: [`Target: ${absolutePath}`, `Allowed root: ${rootPath}`],
|
|
25
|
+
hint: `Use a path inside ${rootPath}.`,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return normalizeSyncRepoPath(relativePath);
|
|
29
|
+
};
|
|
30
|
+
export const buildConfiguredHomeLocalPath = (repoPath) => {
|
|
31
|
+
return { default: `~/${repoPath}` };
|
|
32
|
+
};
|
|
33
|
+
export const tryBuildRepoPathWithinRoot = (absolutePath, rootPath, description) => {
|
|
34
|
+
try {
|
|
35
|
+
return buildRepoPathWithinRoot(absolutePath, rootPath, description);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
export const tryNormalizeRepoPathInput = (value) => {
|
|
42
|
+
try {
|
|
43
|
+
return normalizeSyncRepoPath(value);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
export const resolveTrackedEntry = (target, entries, context) => {
|
|
50
|
+
const resolvedTargetPath = resolveCommandTargetPath(target, context.environment, context.cwd);
|
|
51
|
+
const byLocalPath = entries.filter((entry) => entry.localPath === resolvedTargetPath);
|
|
52
|
+
let matches;
|
|
53
|
+
if (byLocalPath.length > 0 || isExplicitLocalPath(target)) {
|
|
54
|
+
matches = byLocalPath;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const normalizedRepoPath = tryNormalizeRepoPathInput(target);
|
|
58
|
+
matches =
|
|
59
|
+
normalizedRepoPath === undefined
|
|
60
|
+
? []
|
|
61
|
+
: entries.filter((entry) => entry.repoPath === normalizedRepoPath);
|
|
62
|
+
}
|
|
63
|
+
if (matches.length > 1) {
|
|
64
|
+
throw new DevsyncError(`Multiple tracked sync entries match: ${target}`, {
|
|
65
|
+
code: "TARGET_CONFLICT",
|
|
66
|
+
hint: "Use an explicit local path to choose the tracked entry.",
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return matches[0];
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/services/paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { buildEntryMaterialization, buildPullCounts } from "./local-materialization.js";
|
|
2
|
+
import { type EffectiveSyncConfig, type SyncContext } from "./runtime.js";
|
|
3
|
+
export type SyncPullRequest = Readonly<{
|
|
4
|
+
dryRun: boolean;
|
|
5
|
+
machine?: string;
|
|
6
|
+
}>;
|
|
7
|
+
export type SyncPullResult = Readonly<{
|
|
8
|
+
configPath: string;
|
|
9
|
+
decryptedFileCount: number;
|
|
10
|
+
deletedLocalCount: number;
|
|
11
|
+
directoryCount: number;
|
|
12
|
+
dryRun: boolean;
|
|
13
|
+
plainFileCount: number;
|
|
14
|
+
symlinkCount: number;
|
|
15
|
+
syncDirectory: string;
|
|
16
|
+
}>;
|
|
17
|
+
export type PullPlan = Readonly<{
|
|
18
|
+
counts: ReturnType<typeof buildPullCounts>;
|
|
19
|
+
deletedLocalCount: number;
|
|
20
|
+
desiredKeys: ReadonlySet<string>;
|
|
21
|
+
existingKeys: ReadonlySet<string>;
|
|
22
|
+
materializations: readonly ReturnType<typeof buildEntryMaterialization>[];
|
|
23
|
+
}>;
|
|
24
|
+
export declare const buildPullPlan: (config: EffectiveSyncConfig, context: SyncContext) => Promise<PullPlan>;
|
|
25
|
+
export declare const buildPullPlanPreview: (plan: PullPlan) => string[];
|
|
26
|
+
export declare const buildPullResultFromPlan: (plan: PullPlan, context: SyncContext, dryRun: boolean) => SyncPullResult;
|
|
27
|
+
export declare const pullSync: (request: SyncPullRequest, context: SyncContext) => Promise<SyncPullResult>;
|
|
28
|
+
//# sourceMappingURL=pull.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/services/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,yBAAyB,EACzB,eAAe,EAEhB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,KAAK,mBAAmB,EAGxB,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC;IAC9B,MAAM,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;IAC3C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACjC,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAClC,gBAAgB,EAAE,SAAS,UAAU,CAAC,OAAO,yBAAyB,CAAC,EAAE,CAAC;CAC3E,CAAC,CAAC;AAEH,eAAO,MAAM,aAAa,GACxB,QAAQ,mBAAmB,EAC3B,SAAS,WAAW,KACnB,OAAO,CAAC,QAAQ,CAmClB,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,MAAM,QAAQ,aAalD,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,MAAM,QAAQ,EACd,SAAS,WAAW,EACpB,QAAQ,OAAO,KACd,cAQF,CAAC;AAEF,eAAO,MAAM,QAAQ,GACnB,SAAS,eAAe,EACxB,SAAS,WAAW,KACnB,OAAO,CAAC,cAAc,CAsBxB,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { applyEntryMaterialization, buildEntryMaterialization, buildPullCounts, countDeletedLocalNodes, } from "./local-materialization.js";
|
|
2
|
+
import { buildRepositorySnapshot } from "./repo-snapshot.js";
|
|
3
|
+
import { ensureSyncRepository, loadSyncConfig, } from "./runtime.js";
|
|
4
|
+
export const buildPullPlan = async (config, context) => {
|
|
5
|
+
const snapshot = await buildRepositorySnapshot(context.paths.syncDirectory, config);
|
|
6
|
+
const materializations = config.entries.map((entry) => {
|
|
7
|
+
return buildEntryMaterialization(entry, snapshot);
|
|
8
|
+
});
|
|
9
|
+
let deletedLocalCount = 0;
|
|
10
|
+
const existingKeys = new Set();
|
|
11
|
+
for (let index = 0; index < config.entries.length; index += 1) {
|
|
12
|
+
const entry = config.entries[index];
|
|
13
|
+
const materialization = materializations[index];
|
|
14
|
+
if (entry === undefined || materialization === undefined) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
deletedLocalCount += await countDeletedLocalNodes(entry, materialization.desiredKeys, config, existingKeys);
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
counts: buildPullCounts(materializations),
|
|
21
|
+
deletedLocalCount,
|
|
22
|
+
desiredKeys: new Set(materializations.flatMap((m) => [...m.desiredKeys])),
|
|
23
|
+
existingKeys,
|
|
24
|
+
materializations,
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
export const buildPullPlanPreview = (plan) => {
|
|
28
|
+
const desired = [...plan.desiredKeys].sort((left, right) => {
|
|
29
|
+
return left.localeCompare(right);
|
|
30
|
+
});
|
|
31
|
+
const deleted = [...plan.existingKeys]
|
|
32
|
+
.filter((key) => {
|
|
33
|
+
return !plan.desiredKeys.has(key);
|
|
34
|
+
})
|
|
35
|
+
.sort((left, right) => {
|
|
36
|
+
return left.localeCompare(right);
|
|
37
|
+
});
|
|
38
|
+
return [...desired.slice(0, 4), ...deleted.slice(0, 4)].slice(0, 6);
|
|
39
|
+
};
|
|
40
|
+
export const buildPullResultFromPlan = (plan, context, dryRun) => {
|
|
41
|
+
return {
|
|
42
|
+
configPath: context.paths.configPath,
|
|
43
|
+
deletedLocalCount: plan.deletedLocalCount,
|
|
44
|
+
dryRun,
|
|
45
|
+
syncDirectory: context.paths.syncDirectory,
|
|
46
|
+
...plan.counts,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
export const pullSync = async (request, context) => {
|
|
50
|
+
await ensureSyncRepository(context);
|
|
51
|
+
const { effectiveConfig: config } = await loadSyncConfig(context, {
|
|
52
|
+
...(request.machine === undefined ? {} : { machine: request.machine }),
|
|
53
|
+
});
|
|
54
|
+
const plan = await buildPullPlan(config, context);
|
|
55
|
+
for (let index = 0; index < config.entries.length; index += 1) {
|
|
56
|
+
const entry = config.entries[index];
|
|
57
|
+
const materialization = plan.materializations[index];
|
|
58
|
+
if (entry === undefined || materialization === undefined) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (!request.dryRun) {
|
|
62
|
+
await applyEntryMaterialization(entry, materialization, config);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return buildPullResultFromPlan(plan, context, request.dryRun);
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=pull.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/services/pull.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type SnapshotNode } from "./local-snapshot.js";
|
|
2
|
+
import { type EffectiveSyncConfig, type SyncContext } from "./runtime.js";
|
|
3
|
+
export type SyncPushRequest = Readonly<{
|
|
4
|
+
dryRun: boolean;
|
|
5
|
+
machine?: string;
|
|
6
|
+
}>;
|
|
7
|
+
export type SyncPushResult = Readonly<{
|
|
8
|
+
configPath: string;
|
|
9
|
+
deletedArtifactCount: number;
|
|
10
|
+
directoryCount: number;
|
|
11
|
+
dryRun: boolean;
|
|
12
|
+
encryptedFileCount: number;
|
|
13
|
+
plainFileCount: number;
|
|
14
|
+
symlinkCount: number;
|
|
15
|
+
syncDirectory: string;
|
|
16
|
+
}>;
|
|
17
|
+
export type PushPlan = Readonly<{
|
|
18
|
+
counts: ReturnType<typeof buildPushCounts>;
|
|
19
|
+
deletedArtifactCount: number;
|
|
20
|
+
desiredArtifactKeys: ReadonlySet<string>;
|
|
21
|
+
existingArtifactKeys: ReadonlySet<string>;
|
|
22
|
+
snapshot: ReadonlyMap<string, SnapshotNode>;
|
|
23
|
+
}>;
|
|
24
|
+
declare const buildPushCounts: (snapshot: ReadonlyMap<string, SnapshotNode>) => {
|
|
25
|
+
directoryCount: number;
|
|
26
|
+
encryptedFileCount: number;
|
|
27
|
+
plainFileCount: number;
|
|
28
|
+
symlinkCount: number;
|
|
29
|
+
};
|
|
30
|
+
export declare const buildPushPlan: (config: EffectiveSyncConfig, context: SyncContext) => Promise<PushPlan>;
|
|
31
|
+
export declare const buildPushPlanPreview: (plan: PushPlan) => string[];
|
|
32
|
+
export declare const buildPushResultFromPlan: (plan: PushPlan, context: SyncContext, dryRun: boolean) => SyncPushResult;
|
|
33
|
+
export declare const pushSync: (request: SyncPushRequest, context: SyncContext) => Promise<SyncPushResult>;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=push.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/services/push.ts"],"names":[],"mappings":"AAKA,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAO5E,OAAO,EACL,KAAK,mBAAmB,EAGxB,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC;IAC9B,MAAM,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;IAC3C,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC,oBAAoB,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1C,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CAC7C,CAAC,CAAC;AAEH,QAAA,MAAM,eAAe,GAAI,UAAU,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC;;;;;CA8BnE,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,QAAQ,mBAAmB,EAC3B,SAAS,WAAW,KACnB,OAAO,CAAC,QAAQ,CAuBlB,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,MAAM,QAAQ,aAalD,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,MAAM,QAAQ,EACd,SAAS,WAAW,EACpB,QAAQ,OAAO,KACd,cAQF,CAAC;AAEF,eAAO,MAAM,QAAQ,GACnB,SAAS,eAAe,EACxB,SAAS,WAAW,KACnB,OAAO,CAAC,cAAc,CA8BxB,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { resolveSyncArtifactsDirectoryPath } from "#app/config/sync.js";
|
|
3
|
+
import { removePathAtomically } from "./filesystem.js";
|
|
4
|
+
import { buildLocalSnapshot } from "./local-snapshot.js";
|
|
5
|
+
import { buildArtifactKey, buildRepoArtifacts, collectExistingArtifactKeys, writeArtifactsToDirectory, } from "./repo-artifacts.js";
|
|
6
|
+
import { ensureSyncRepository, loadSyncConfig, } from "./runtime.js";
|
|
7
|
+
const buildPushCounts = (snapshot) => {
|
|
8
|
+
let directoryCount = 0;
|
|
9
|
+
let encryptedFileCount = 0;
|
|
10
|
+
let plainFileCount = 0;
|
|
11
|
+
let symlinkCount = 0;
|
|
12
|
+
for (const node of snapshot.values()) {
|
|
13
|
+
if (node.type === "directory") {
|
|
14
|
+
directoryCount += 1;
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (node.type === "symlink") {
|
|
18
|
+
symlinkCount += 1;
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (node.secret) {
|
|
22
|
+
encryptedFileCount += 1;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
plainFileCount += 1;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
directoryCount,
|
|
30
|
+
encryptedFileCount,
|
|
31
|
+
plainFileCount,
|
|
32
|
+
symlinkCount,
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
export const buildPushPlan = async (config, context) => {
|
|
36
|
+
const snapshot = await buildLocalSnapshot(config);
|
|
37
|
+
const artifacts = await buildRepoArtifacts(snapshot, config);
|
|
38
|
+
const desiredArtifactKeys = new Set(artifacts.map((artifact) => {
|
|
39
|
+
return buildArtifactKey(artifact);
|
|
40
|
+
}));
|
|
41
|
+
const existingArtifactKeys = await collectExistingArtifactKeys(context.paths.syncDirectory, config);
|
|
42
|
+
const deletedArtifactCount = [...existingArtifactKeys].filter((key) => {
|
|
43
|
+
return !desiredArtifactKeys.has(key);
|
|
44
|
+
}).length;
|
|
45
|
+
return {
|
|
46
|
+
counts: buildPushCounts(snapshot),
|
|
47
|
+
deletedArtifactCount,
|
|
48
|
+
desiredArtifactKeys,
|
|
49
|
+
existingArtifactKeys,
|
|
50
|
+
snapshot,
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
export const buildPushPlanPreview = (plan) => {
|
|
54
|
+
const createdOrUpdated = [...plan.snapshot.keys()].sort((left, right) => {
|
|
55
|
+
return left.localeCompare(right);
|
|
56
|
+
});
|
|
57
|
+
const deleted = [...plan.existingArtifactKeys]
|
|
58
|
+
.filter((key) => {
|
|
59
|
+
return !plan.desiredArtifactKeys.has(key);
|
|
60
|
+
})
|
|
61
|
+
.sort((left, right) => {
|
|
62
|
+
return left.localeCompare(right);
|
|
63
|
+
});
|
|
64
|
+
return [...createdOrUpdated.slice(0, 4), ...deleted.slice(0, 4)].slice(0, 6);
|
|
65
|
+
};
|
|
66
|
+
export const buildPushResultFromPlan = (plan, context, dryRun) => {
|
|
67
|
+
return {
|
|
68
|
+
configPath: context.paths.configPath,
|
|
69
|
+
deletedArtifactCount: plan.deletedArtifactCount,
|
|
70
|
+
dryRun,
|
|
71
|
+
syncDirectory: context.paths.syncDirectory,
|
|
72
|
+
...plan.counts,
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
export const pushSync = async (request, context) => {
|
|
76
|
+
await ensureSyncRepository(context);
|
|
77
|
+
const { effectiveConfig: config } = await loadSyncConfig(context, {
|
|
78
|
+
...(request.machine === undefined ? {} : { machine: request.machine }),
|
|
79
|
+
});
|
|
80
|
+
const plan = await buildPushPlan(config, context);
|
|
81
|
+
if (!request.dryRun) {
|
|
82
|
+
const artifactsDirectory = resolveSyncArtifactsDirectoryPath(context.paths.syncDirectory);
|
|
83
|
+
const artifacts = await buildRepoArtifacts(plan.snapshot, config);
|
|
84
|
+
for (const staleKey of [...plan.existingArtifactKeys].filter((key) => {
|
|
85
|
+
return !plan.desiredArtifactKeys.has(key);
|
|
86
|
+
})) {
|
|
87
|
+
const relativePath = staleKey.endsWith("/")
|
|
88
|
+
? staleKey.slice(0, -1)
|
|
89
|
+
: staleKey;
|
|
90
|
+
await removePathAtomically(join(artifactsDirectory, ...relativePath.split("/")));
|
|
91
|
+
}
|
|
92
|
+
await writeArtifactsToDirectory(artifactsDirectory, artifacts, config.age);
|
|
93
|
+
}
|
|
94
|
+
return buildPushResultFromPlan(plan, context, request.dryRun);
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=push.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/services/push.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type ResolvedSyncConfigEntry } from "#app/config/sync.js";
|
|
2
|
+
import type { SnapshotNode } from "./local-snapshot.js";
|
|
3
|
+
import type { EffectiveSyncConfig } from "./runtime.js";
|
|
4
|
+
type ArtifactConfig = EffectiveSyncConfig;
|
|
5
|
+
export declare const collectArtifactNamespaces: (entries: readonly Pick<ResolvedSyncConfigEntry, "machines">[]) => Set<string>;
|
|
6
|
+
export type RepoArtifact = Readonly<{
|
|
7
|
+
category: "plain";
|
|
8
|
+
kind: "directory";
|
|
9
|
+
machine: string;
|
|
10
|
+
repoPath: string;
|
|
11
|
+
}> | Readonly<{
|
|
12
|
+
category: "plain";
|
|
13
|
+
kind: "file";
|
|
14
|
+
repoPath: string;
|
|
15
|
+
machine: string;
|
|
16
|
+
contents: Uint8Array;
|
|
17
|
+
executable: boolean;
|
|
18
|
+
}> | Readonly<{
|
|
19
|
+
category: "plain";
|
|
20
|
+
kind: "symlink";
|
|
21
|
+
machine: string;
|
|
22
|
+
repoPath: string;
|
|
23
|
+
linkTarget: string;
|
|
24
|
+
}> | Readonly<{
|
|
25
|
+
category: "secret";
|
|
26
|
+
kind: "file";
|
|
27
|
+
machine: string;
|
|
28
|
+
repoPath: string;
|
|
29
|
+
contents: Uint8Array;
|
|
30
|
+
executable: boolean;
|
|
31
|
+
}>;
|
|
32
|
+
export declare const buildArtifactKey: (artifact: RepoArtifact) => string;
|
|
33
|
+
export declare const isSecretArtifactPath: (relativePath: string) => boolean;
|
|
34
|
+
export declare const stripSecretArtifactSuffix: (relativePath: string) => string | undefined;
|
|
35
|
+
export declare const assertStorageSafeRepoPath: (repoPath: string) => void;
|
|
36
|
+
export declare const resolveArtifactRelativePath: (artifact: Pick<RepoArtifact, "category" | "machine" | "repoPath">) => string;
|
|
37
|
+
export declare const parseArtifactRelativePath: (relativePath: string) => {
|
|
38
|
+
machine: string;
|
|
39
|
+
repoPath: string;
|
|
40
|
+
secret: boolean;
|
|
41
|
+
};
|
|
42
|
+
export declare const resolveEntryArtifactRelativePath: (entry: Pick<ResolvedSyncConfigEntry, "repoPath">, machine: string) => string;
|
|
43
|
+
export declare const resolveEntryArtifactPath: (artifactsDirectory: string, entry: Pick<ResolvedSyncConfigEntry, "repoPath">, machine: string) => string;
|
|
44
|
+
export declare const buildRepoArtifacts: (snapshot: ReadonlyMap<string, SnapshotNode>, config: ArtifactConfig) => Promise<RepoArtifact[]>;
|
|
45
|
+
export declare const collectExistingArtifactKeys: (syncDirectory: string, config: ArtifactConfig) => Promise<Set<string>>;
|
|
46
|
+
type AgeWriteConfig = Readonly<{
|
|
47
|
+
identityFile: string;
|
|
48
|
+
recipients: readonly string[];
|
|
49
|
+
}>;
|
|
50
|
+
export declare const writeArtifactsToDirectory: (rootDirectory: string, artifacts: readonly RepoArtifact[], ageConfig?: AgeWriteConfig) => Promise<void>;
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=repo-artifacts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo-artifacts.d.ts","sourceRoot":"","sources":["../../src/services/repo-artifacts.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,uBAAuB,EAK7B,MAAM,qBAAqB,CAAC;AAU7B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD,KAAK,cAAc,GAAG,mBAAmB,CAAC;AAE1C,eAAO,MAAM,yBAAyB,GACpC,SAAS,SAAS,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC,EAAE,gBAY9D,CAAC;AAEF,MAAM,MAAM,YAAY,GACpB,QAAQ,CAAC;IACP,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,GACF,QAAQ,CAAC;IACP,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC,GACF,QAAQ,CAAC;IACP,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC,GACF,QAAQ,CAAC;IACP,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC,CAAC;AAEP,eAAO,MAAM,gBAAgB,GAAI,UAAU,YAAY,WAMtD,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,cAAc,MAAM,YAExD,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,cAAc,MAAM,uBAM7D,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,UAAU,MAAM,SAazD,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,UAAU,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC,WAOlE,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,cAAc,MAAM;;;;CAqB7D,CAAC;AAEF,eAAO,MAAM,gCAAgC,GAC3C,OAAO,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC,EAChD,SAAS,MAAM,WAOhB,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,oBAAoB,MAAM,EAC1B,OAAO,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC,EAChD,SAAS,MAAM,WAMhB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,UAAU,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,EAC3C,QAAQ,cAAc,4BAmFvB,CAAC;AAsCF,eAAO,MAAM,2BAA2B,GACtC,eAAe,MAAM,EACrB,QAAQ,cAAc,yBAyDvB,CAAC;AAEF,KAAK,cAAc,GAAG,QAAQ,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B,CAAC,CAAC;AA+BH,eAAO,MAAM,yBAAyB,GACpC,eAAe,MAAM,EACrB,WAAW,SAAS,YAAY,EAAE,EAClC,YAAY,cAAc,kBA6C3B,CAAC"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { lstat, mkdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { findOwningSyncEntry, hasReservedSyncArtifactSuffixSegment, resolveSyncArtifactsDirectoryPath, resolveSyncRule, syncDefaultMachine, syncSecretArtifactSuffix, } from "#app/config/sync.js";
|
|
4
|
+
import { buildDirectoryKey } from "#app/lib/path.js";
|
|
5
|
+
import { decryptSecretFile, encryptSecretFile } from "./crypto.js";
|
|
6
|
+
import { DevsyncError } from "./error.js";
|
|
7
|
+
import { getPathStats, listDirectoryEntries, writeFileNode, writeSymlinkNode, } from "./filesystem.js";
|
|
8
|
+
export const collectArtifactNamespaces = (entries) => {
|
|
9
|
+
const namespaces = new Set();
|
|
10
|
+
namespaces.add(syncDefaultMachine);
|
|
11
|
+
for (const entry of entries) {
|
|
12
|
+
for (const machine of entry.machines) {
|
|
13
|
+
namespaces.add(machine);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return namespaces;
|
|
17
|
+
};
|
|
18
|
+
export const buildArtifactKey = (artifact) => {
|
|
19
|
+
const relativePath = resolveArtifactRelativePath(artifact);
|
|
20
|
+
return artifact.kind === "directory"
|
|
21
|
+
? buildDirectoryKey(relativePath)
|
|
22
|
+
: relativePath;
|
|
23
|
+
};
|
|
24
|
+
export const isSecretArtifactPath = (relativePath) => {
|
|
25
|
+
return relativePath.endsWith(syncSecretArtifactSuffix);
|
|
26
|
+
};
|
|
27
|
+
export const stripSecretArtifactSuffix = (relativePath) => {
|
|
28
|
+
if (!isSecretArtifactPath(relativePath)) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
return relativePath.slice(0, -syncSecretArtifactSuffix.length);
|
|
32
|
+
};
|
|
33
|
+
export const assertStorageSafeRepoPath = (repoPath) => {
|
|
34
|
+
if (!hasReservedSyncArtifactSuffixSegment(repoPath)) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
throw new DevsyncError(`Tracked sync paths must not use the reserved suffix ${syncSecretArtifactSuffix}.`, {
|
|
38
|
+
code: "RESERVED_SECRET_SUFFIX",
|
|
39
|
+
details: [`Repository path: ${repoPath}`],
|
|
40
|
+
hint: "Rename the tracked path so no segment ends with the secret artifact suffix.",
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
export const resolveArtifactRelativePath = (artifact) => {
|
|
44
|
+
const machineRelativePath = `${artifact.machine}/${artifact.repoPath}`;
|
|
45
|
+
return artifact.category === "secret"
|
|
46
|
+
? `${machineRelativePath}${syncSecretArtifactSuffix}`
|
|
47
|
+
: machineRelativePath;
|
|
48
|
+
};
|
|
49
|
+
export const parseArtifactRelativePath = (relativePath) => {
|
|
50
|
+
const secret = relativePath.endsWith(syncSecretArtifactSuffix);
|
|
51
|
+
const logicalPath = secret
|
|
52
|
+
? relativePath.slice(0, -syncSecretArtifactSuffix.length)
|
|
53
|
+
: relativePath;
|
|
54
|
+
const segments = logicalPath.split("/");
|
|
55
|
+
if (segments.length < 2 || segments[0] === undefined) {
|
|
56
|
+
throw new DevsyncError("Repository artifact path is invalid.", {
|
|
57
|
+
code: "INVALID_REPO_ENTRY",
|
|
58
|
+
details: [`Repository path: ${relativePath}`],
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
const [machine, ...repoPathSegments] = segments;
|
|
62
|
+
return {
|
|
63
|
+
machine,
|
|
64
|
+
repoPath: repoPathSegments.join("/"),
|
|
65
|
+
secret,
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
export const resolveEntryArtifactRelativePath = (entry, machine) => {
|
|
69
|
+
return resolveArtifactRelativePath({
|
|
70
|
+
category: "plain",
|
|
71
|
+
machine,
|
|
72
|
+
repoPath: entry.repoPath,
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
export const resolveEntryArtifactPath = (artifactsDirectory, entry, machine) => {
|
|
76
|
+
return join(artifactsDirectory, ...resolveEntryArtifactRelativePath(entry, machine).split("/"));
|
|
77
|
+
};
|
|
78
|
+
export const buildRepoArtifacts = async (snapshot, config) => {
|
|
79
|
+
const artifacts = [];
|
|
80
|
+
const seenArtifactKeys = new Set();
|
|
81
|
+
const addArtifact = (artifact) => {
|
|
82
|
+
const key = buildArtifactKey(artifact);
|
|
83
|
+
if (seenArtifactKeys.has(key)) {
|
|
84
|
+
throw new DevsyncError("Duplicate repository artifact was generated.", {
|
|
85
|
+
code: "DUPLICATE_REPO_ARTIFACT",
|
|
86
|
+
details: [`Artifact key: ${key}`],
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
seenArtifactKeys.add(key);
|
|
90
|
+
artifacts.push(artifact);
|
|
91
|
+
};
|
|
92
|
+
for (const repoPath of [...snapshot.keys()].sort((left, right) => {
|
|
93
|
+
return left.localeCompare(right);
|
|
94
|
+
})) {
|
|
95
|
+
assertStorageSafeRepoPath(repoPath);
|
|
96
|
+
const node = snapshot.get(repoPath);
|
|
97
|
+
const owningEntry = findOwningSyncEntry(config, repoPath);
|
|
98
|
+
const resolvedRule = resolveSyncRule(config, repoPath, config.activeMachine);
|
|
99
|
+
if (node === undefined ||
|
|
100
|
+
owningEntry === undefined ||
|
|
101
|
+
resolvedRule === undefined) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (node.type === "directory") {
|
|
105
|
+
addArtifact({
|
|
106
|
+
category: "plain",
|
|
107
|
+
kind: "directory",
|
|
108
|
+
machine: resolvedRule.machine,
|
|
109
|
+
repoPath,
|
|
110
|
+
});
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (node.type === "symlink") {
|
|
114
|
+
addArtifact({
|
|
115
|
+
category: "plain",
|
|
116
|
+
kind: "symlink",
|
|
117
|
+
linkTarget: node.linkTarget,
|
|
118
|
+
machine: resolvedRule.machine,
|
|
119
|
+
repoPath,
|
|
120
|
+
});
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (!node.secret) {
|
|
124
|
+
addArtifact({
|
|
125
|
+
category: "plain",
|
|
126
|
+
contents: node.contents,
|
|
127
|
+
executable: node.executable,
|
|
128
|
+
kind: "file",
|
|
129
|
+
machine: resolvedRule.machine,
|
|
130
|
+
repoPath,
|
|
131
|
+
});
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
addArtifact({
|
|
135
|
+
category: "secret",
|
|
136
|
+
contents: node.contents,
|
|
137
|
+
executable: node.executable,
|
|
138
|
+
kind: "file",
|
|
139
|
+
machine: resolvedRule.machine,
|
|
140
|
+
repoPath,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return artifacts;
|
|
144
|
+
};
|
|
145
|
+
const collectArtifactLeafKeys = async (rootDirectory, keys, prefix) => {
|
|
146
|
+
const rootStats = await getPathStats(rootDirectory);
|
|
147
|
+
if (rootStats === undefined) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (!rootStats.isDirectory()) {
|
|
151
|
+
if (prefix !== undefined) {
|
|
152
|
+
keys.add(prefix);
|
|
153
|
+
}
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const entries = await listDirectoryEntries(rootDirectory);
|
|
157
|
+
for (const entry of entries) {
|
|
158
|
+
const absolutePath = join(rootDirectory, entry.name);
|
|
159
|
+
const relativePath = prefix === undefined ? entry.name : `${prefix}/${entry.name}`;
|
|
160
|
+
const stats = await lstat(absolutePath);
|
|
161
|
+
if (stats?.isDirectory()) {
|
|
162
|
+
await collectArtifactLeafKeys(absolutePath, keys, relativePath);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
keys.add(relativePath);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
export const collectExistingArtifactKeys = async (syncDirectory, config) => {
|
|
169
|
+
const keys = new Set();
|
|
170
|
+
const artifactsDirectory = resolveSyncArtifactsDirectoryPath(syncDirectory);
|
|
171
|
+
const namespaces = collectArtifactNamespaces(config.entries);
|
|
172
|
+
await Promise.all([...namespaces].map(async (namespace) => {
|
|
173
|
+
await collectArtifactLeafKeys(join(artifactsDirectory, namespace), keys, namespace);
|
|
174
|
+
}));
|
|
175
|
+
for (const key of [...keys]) {
|
|
176
|
+
if (key.startsWith("__dir__:")) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const artifact = parseArtifactRelativePath(key);
|
|
180
|
+
const rule = resolveSyncRule(config, artifact.repoPath, config.activeMachine);
|
|
181
|
+
if (rule === undefined || rule.machine !== artifact.machine) {
|
|
182
|
+
keys.delete(key);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
for (const entry of config.entries) {
|
|
186
|
+
if (entry.kind !== "directory") {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const rule = resolveSyncRule(config, entry.repoPath, config.activeMachine);
|
|
190
|
+
if (rule === undefined) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const relativePath = resolveArtifactRelativePath({
|
|
194
|
+
category: "plain",
|
|
195
|
+
machine: rule.machine,
|
|
196
|
+
repoPath: entry.repoPath,
|
|
197
|
+
});
|
|
198
|
+
const path = join(artifactsDirectory, ...relativePath.split("/"));
|
|
199
|
+
if ((await getPathStats(path))?.isDirectory()) {
|
|
200
|
+
keys.add(buildDirectoryKey(relativePath));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return keys;
|
|
204
|
+
};
|
|
205
|
+
const isSecretArtifactUnchanged = async (artifactPath, plaintext, identityFile) => {
|
|
206
|
+
let existingCiphertext;
|
|
207
|
+
try {
|
|
208
|
+
existingCiphertext = await readFile(artifactPath, "utf8");
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
const existingPlaintext = await decryptSecretFile(existingCiphertext, identityFile);
|
|
215
|
+
if (existingPlaintext.length !== plaintext.length) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
return existingPlaintext.every((byte, index) => byte === plaintext[index]);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
export const writeArtifactsToDirectory = async (rootDirectory, artifacts, ageConfig) => {
|
|
225
|
+
await mkdir(rootDirectory, { recursive: true });
|
|
226
|
+
for (const artifact of artifacts) {
|
|
227
|
+
const artifactPath = join(rootDirectory, ...resolveArtifactRelativePath(artifact).split("/"));
|
|
228
|
+
if (artifact.kind === "directory") {
|
|
229
|
+
await mkdir(artifactPath, { recursive: true });
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (artifact.kind === "symlink") {
|
|
233
|
+
await writeSymlinkNode(artifactPath, artifact.linkTarget);
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (artifact.category === "secret" && ageConfig !== undefined) {
|
|
237
|
+
const unchanged = await isSecretArtifactUnchanged(artifactPath, artifact.contents, ageConfig.identityFile);
|
|
238
|
+
if (unchanged) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const encrypted = await encryptSecretFile(artifact.contents, ageConfig.recipients);
|
|
242
|
+
await writeFileNode(artifactPath, {
|
|
243
|
+
contents: encrypted,
|
|
244
|
+
executable: artifact.executable,
|
|
245
|
+
});
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
await writeFileNode(artifactPath, artifact);
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
//# sourceMappingURL=repo-artifacts.js.map
|