pushwork 2.0.0-preview → 2.0.0-preview.2
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/dist/branches.d.ts +1 -0
- package/dist/branches.d.ts.map +1 -1
- package/dist/cli.js +16 -7
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/pushwork.d.ts +15 -1
- package/dist/pushwork.d.ts.map +1 -1
- package/dist/pushwork.js +151 -7
- package/dist/pushwork.js.map +1 -1
- package/dist/shapes/types.d.ts +1 -0
- package/dist/shapes/types.d.ts.map +1 -1
- package/dist/shapes/types.js.map +1 -1
- package/dist/shapes/vfs.d.ts.map +1 -1
- package/dist/shapes/vfs.js +6 -2
- package/dist/shapes/vfs.js.map +1 -1
- package/dist/version.d.ts +11 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +93 -0
- package/dist/version.js.map +1 -0
- package/package.json +5 -1
- package/.prettierrc +0 -9
- package/flake.lock +0 -128
- package/flake.nix +0 -66
- package/pnpm-workspace.yaml +0 -5
- package/src/branches.ts +0 -93
- package/src/cli.ts +0 -292
- package/src/config.ts +0 -64
- package/src/fs-tree.ts +0 -70
- package/src/ignore.ts +0 -33
- package/src/index.ts +0 -38
- package/src/log.ts +0 -8
- package/src/pushwork.ts +0 -1055
- package/src/repo.ts +0 -76
- package/src/shapes/custom.ts +0 -29
- package/src/shapes/file.ts +0 -115
- package/src/shapes/index.ts +0 -19
- package/src/shapes/patchwork-folder.ts +0 -156
- package/src/shapes/types.ts +0 -79
- package/src/shapes/vfs.ts +0 -93
- package/src/stash.ts +0 -106
- package/test/integration/branches.test.ts +0 -389
- package/test/integration/pushwork.test.ts +0 -547
- package/test/setup.ts +0 -29
- package/test/unit/doc-shape.test.ts +0 -612
- package/tsconfig.json +0 -22
- package/vitest.config.ts +0 -14
package/src/cli.ts
DELETED
|
@@ -1,292 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import "./log.js"; // sets up DEBUG=true → DEBUG=* before anything else
|
|
3
|
-
import { Command } from "@commander-js/extra-typings";
|
|
4
|
-
import * as path from "path";
|
|
5
|
-
import {
|
|
6
|
-
clone,
|
|
7
|
-
createBranch,
|
|
8
|
-
currentBranch,
|
|
9
|
-
cutWorkdir,
|
|
10
|
-
diff,
|
|
11
|
-
init,
|
|
12
|
-
listBranches,
|
|
13
|
-
mergeBranch,
|
|
14
|
-
pasteStash,
|
|
15
|
-
previewMerge,
|
|
16
|
-
save,
|
|
17
|
-
showStashes,
|
|
18
|
-
status,
|
|
19
|
-
switchBranch,
|
|
20
|
-
sync,
|
|
21
|
-
url,
|
|
22
|
-
} from "./pushwork.js";
|
|
23
|
-
import { log } from "./log.js";
|
|
24
|
-
|
|
25
|
-
const dlog = log("cli");
|
|
26
|
-
|
|
27
|
-
const collect = (value: string, prev: string[] | undefined) =>
|
|
28
|
-
(prev ?? []).concat(value);
|
|
29
|
-
|
|
30
|
-
const program = new Command()
|
|
31
|
-
.name("pushwork")
|
|
32
|
-
.description("Bidirectional directory synchronization using Automerge CRDTs");
|
|
33
|
-
|
|
34
|
-
program
|
|
35
|
-
.command("init")
|
|
36
|
-
.description("Initialize pushwork in a directory")
|
|
37
|
-
.argument("[dir]", "Directory to initialize", ".")
|
|
38
|
-
.option("--sub", "Use subduction backend")
|
|
39
|
-
.option(
|
|
40
|
-
"--shape <shape>",
|
|
41
|
-
"Document shape: vfs, patchwork-folder, or path to a custom shape module",
|
|
42
|
-
"vfs",
|
|
43
|
-
)
|
|
44
|
-
.option(
|
|
45
|
-
"--artifact-dir <dir>",
|
|
46
|
-
"Directory whose contents are stored as ImmutableString and pinned with heads in the root doc. Repeatable.",
|
|
47
|
-
collect,
|
|
48
|
-
undefined as string[] | undefined,
|
|
49
|
-
)
|
|
50
|
-
.option("--no-branches", "Skip wrapping the root doc in a branches doc")
|
|
51
|
-
.action(async (dir, opts) => {
|
|
52
|
-
dlog("init dir=%s opts=%o", dir, opts);
|
|
53
|
-
const u = await init({
|
|
54
|
-
dir: path.resolve(dir),
|
|
55
|
-
backend: opts.sub ? "subduction" : "legacy",
|
|
56
|
-
shape: opts.shape,
|
|
57
|
-
artifactDirectories: opts.artifactDir,
|
|
58
|
-
branches: opts.branches,
|
|
59
|
-
});
|
|
60
|
-
process.stderr.write(`initialized ${u}\n`);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
program
|
|
64
|
-
.command("clone")
|
|
65
|
-
.description("Clone an automerge URL into a directory")
|
|
66
|
-
.argument("<url>", "automerge: URL")
|
|
67
|
-
.argument("[dir]", "Target directory", ".")
|
|
68
|
-
.option("--sub", "Use subduction backend")
|
|
69
|
-
.option(
|
|
70
|
-
"--shape <shape>",
|
|
71
|
-
"Document shape: vfs, patchwork-folder, or path to a custom shape module",
|
|
72
|
-
"vfs",
|
|
73
|
-
)
|
|
74
|
-
.option(
|
|
75
|
-
"--artifact-dir <dir>",
|
|
76
|
-
"Directory whose contents are stored as ImmutableString and pinned with heads in the root doc. Repeatable.",
|
|
77
|
-
collect,
|
|
78
|
-
undefined as string[] | undefined,
|
|
79
|
-
)
|
|
80
|
-
.option("--branch <name>", "Branch to track when cloning a branches doc")
|
|
81
|
-
.action(async (u, dir, opts) => {
|
|
82
|
-
dlog("clone url=%s dir=%s opts=%o", u, dir, opts);
|
|
83
|
-
await clone({
|
|
84
|
-
url: u,
|
|
85
|
-
dir: path.resolve(dir),
|
|
86
|
-
backend: opts.sub ? "subduction" : "legacy",
|
|
87
|
-
shape: opts.shape,
|
|
88
|
-
artifactDirectories: opts.artifactDir,
|
|
89
|
-
branch: opts.branch,
|
|
90
|
-
});
|
|
91
|
-
process.stderr.write(`cloned into ${path.resolve(dir)}\n`);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
program
|
|
95
|
-
.command("url")
|
|
96
|
-
.description("Print the automerge URL of this pushwork repo")
|
|
97
|
-
.action(async () => {
|
|
98
|
-
dlog("url cwd=%s", process.cwd());
|
|
99
|
-
const u = await url(process.cwd());
|
|
100
|
-
process.stdout.write(u + "\n");
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
program
|
|
104
|
-
.command("sync")
|
|
105
|
-
.description("Sync local changes with peers")
|
|
106
|
-
.action(async () => {
|
|
107
|
-
dlog("sync cwd=%s", process.cwd());
|
|
108
|
-
await sync(process.cwd());
|
|
109
|
-
process.stderr.write("synced\n");
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
program
|
|
113
|
-
.command("save")
|
|
114
|
-
.alias("commit")
|
|
115
|
-
.description("Commit local changes to the current branch without contacting the sync server")
|
|
116
|
-
.action(async () => {
|
|
117
|
-
dlog("save cwd=%s", process.cwd());
|
|
118
|
-
await save(process.cwd());
|
|
119
|
-
process.stderr.write("saved\n");
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
program
|
|
123
|
-
.command("status")
|
|
124
|
-
.description("Show current branch and changes against it")
|
|
125
|
-
.action(async () => {
|
|
126
|
-
const { branch, diff: d } = await status(process.cwd());
|
|
127
|
-
const lines: string[] = [];
|
|
128
|
-
if (branch) lines.push(`On branch ${branch}`);
|
|
129
|
-
else lines.push("(no branches)");
|
|
130
|
-
const total = d.added.length + d.modified.length + d.deleted.length;
|
|
131
|
-
if (total === 0) {
|
|
132
|
-
lines.push("nothing to save, working tree clean");
|
|
133
|
-
} else {
|
|
134
|
-
lines.push("Changes:");
|
|
135
|
-
for (const p of d.modified) lines.push(` modified: ${p}`);
|
|
136
|
-
for (const p of d.added) lines.push(` added: ${p}`);
|
|
137
|
-
for (const p of d.deleted) lines.push(` deleted: ${p}`);
|
|
138
|
-
}
|
|
139
|
-
process.stdout.write(lines.join("\n") + "\n");
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
program
|
|
143
|
-
.command("diff")
|
|
144
|
-
.description("Show textual diffs of local changes against the current branch")
|
|
145
|
-
.argument("[path]", "Limit to a specific path")
|
|
146
|
-
.action(async (limitPath) => {
|
|
147
|
-
const entries = await diff(process.cwd(), limitPath);
|
|
148
|
-
if (entries.length === 0) {
|
|
149
|
-
process.stdout.write("(no changes)\n");
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
const { createPatch } = await import("diff");
|
|
153
|
-
const td = new TextDecoder("utf-8", { fatal: false });
|
|
154
|
-
for (const e of entries) {
|
|
155
|
-
const before = e.before ? td.decode(e.before) : "";
|
|
156
|
-
const after = e.after ? td.decode(e.after) : "";
|
|
157
|
-
const header =
|
|
158
|
-
e.kind === "added" ? `+++ ${e.path}` :
|
|
159
|
-
e.kind === "deleted" ? `--- ${e.path}` :
|
|
160
|
-
`*** ${e.path}`;
|
|
161
|
-
process.stdout.write(header + "\n");
|
|
162
|
-
process.stdout.write(createPatch(e.path, before, after, "", "") + "\n");
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
program
|
|
167
|
-
.command("branch")
|
|
168
|
-
.description("With no arg: print the current branch. With <name>: create a new branch from the current one (offline).")
|
|
169
|
-
.argument("[name]", "Name of the new branch")
|
|
170
|
-
.action(async (name) => {
|
|
171
|
-
if (!name) {
|
|
172
|
-
const cur = await currentBranch(process.cwd());
|
|
173
|
-
process.stdout.write((cur ?? "(none)") + "\n");
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
const newUrl = await createBranch(process.cwd(), name);
|
|
177
|
-
process.stderr.write(`created branch ${name} → ${newUrl}\n`);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
program
|
|
181
|
-
.command("switch")
|
|
182
|
-
.description("Switch to a branch (offline). With no name: list branches.")
|
|
183
|
-
.argument("[name]", "Name of the branch to switch to")
|
|
184
|
-
.action(async (name) => {
|
|
185
|
-
if (!name) {
|
|
186
|
-
const { current, names } = await listBranches(process.cwd());
|
|
187
|
-
for (const n of names) {
|
|
188
|
-
process.stdout.write(`${n === current ? "* " : " "}${n}\n`);
|
|
189
|
-
}
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
await switchBranch(process.cwd(), name);
|
|
193
|
-
process.stderr.write(`switched to ${name}\n`);
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
program
|
|
197
|
-
.command("merge")
|
|
198
|
-
.description("Apply changes from <source> branch onto the current branch (offline)")
|
|
199
|
-
.argument("<source>", "Branch to merge into the current one")
|
|
200
|
-
.option("--dry", "Preview the merge without applying")
|
|
201
|
-
.action(async (source, opts) => {
|
|
202
|
-
if (opts.dry) {
|
|
203
|
-
const preview = await previewMerge(process.cwd(), source);
|
|
204
|
-
const lines: string[] = [];
|
|
205
|
-
lines.push(`Merging ${preview.source} into ${preview.target} (preview)`);
|
|
206
|
-
if (preview.entries.length === 0) {
|
|
207
|
-
lines.push("(no changes)");
|
|
208
|
-
process.stdout.write(lines.join("\n") + "\n");
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
const { createPatch } = await import("diff");
|
|
212
|
-
const td = new TextDecoder("utf-8", { fatal: false });
|
|
213
|
-
for (const e of preview.entries) {
|
|
214
|
-
const before = e.before ? td.decode(e.before) : "";
|
|
215
|
-
const after = td.decode(e.after);
|
|
216
|
-
const tag = e.kind === "added" ? "added" : "merged";
|
|
217
|
-
lines.push(` ${tag}: ${e.path}`);
|
|
218
|
-
lines.push(createPatch(e.path, before, after, "", ""));
|
|
219
|
-
}
|
|
220
|
-
process.stdout.write(lines.join("\n") + "\n");
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
const report = await mergeBranch(process.cwd(), source);
|
|
224
|
-
const lines: string[] = [];
|
|
225
|
-
lines.push(`Merging ${report.source} into ${report.target}`);
|
|
226
|
-
if (report.merged.length === 0 && report.added.length === 0) {
|
|
227
|
-
lines.push("(no changes)");
|
|
228
|
-
} else {
|
|
229
|
-
for (const p of report.merged) lines.push(` merged: ${p}`);
|
|
230
|
-
for (const p of report.added) lines.push(` added: ${p}`);
|
|
231
|
-
}
|
|
232
|
-
process.stdout.write(lines.join("\n") + "\n");
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
program
|
|
236
|
-
.command("cut")
|
|
237
|
-
.description("Stash working-tree changes against the current branch and reset the tree to clean (offline)")
|
|
238
|
-
.argument("[name]", "Optional name for the stash entry")
|
|
239
|
-
.action(async (name) => {
|
|
240
|
-
const result = await cutWorkdir(process.cwd(), { name });
|
|
241
|
-
process.stderr.write(`cut #${result.id}: ${result.entries} entr${result.entries === 1 ? "y" : "ies"}\n`);
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
program
|
|
245
|
-
.command("paste")
|
|
246
|
-
.description("Re-apply a stashed set of changes; default is the most recent (offline)")
|
|
247
|
-
.argument("[id-or-name]", "Stash id or name")
|
|
248
|
-
.action(async (selector) => {
|
|
249
|
-
const result = await pasteStash(process.cwd(), selector);
|
|
250
|
-
process.stderr.write(
|
|
251
|
-
`pasted #${result.id}${result.name ? ` (${result.name})` : ""}: ${result.entries} entr${result.entries === 1 ? "y" : "ies"}\n`,
|
|
252
|
-
);
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
program
|
|
256
|
-
.command("cuts")
|
|
257
|
-
.description("List stashed change sets (newest first)")
|
|
258
|
-
.action(async () => {
|
|
259
|
-
const stashes = await showStashes(process.cwd());
|
|
260
|
-
if (stashes.length === 0) {
|
|
261
|
-
process.stdout.write("(no stashes)\n");
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
for (const s of stashes) {
|
|
265
|
-
const ts = new Date(s.createdAt).toISOString();
|
|
266
|
-
const label = s.name ? `"${s.name}"` : "";
|
|
267
|
-
const branch = s.branch ? ` on ${s.branch}` : "";
|
|
268
|
-
process.stdout.write(
|
|
269
|
-
`#${s.id}${label ? " " + label : ""}${branch} ${s.entries.length} entr${s.entries.length === 1 ? "y" : "ies"} ${ts}\n`,
|
|
270
|
-
);
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
program
|
|
275
|
-
.command("branches")
|
|
276
|
-
.description("List branches")
|
|
277
|
-
.action(async () => {
|
|
278
|
-
const { current, names } = await listBranches(process.cwd());
|
|
279
|
-
for (const n of names) {
|
|
280
|
-
process.stdout.write(`${n === current ? "* " : " "}${n}\n`);
|
|
281
|
-
}
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
program
|
|
285
|
-
.parseAsync(process.argv)
|
|
286
|
-
.then(() => process.exit(0))
|
|
287
|
-
.catch((err) => {
|
|
288
|
-
process.stderr.write(
|
|
289
|
-
`pushwork: ${err instanceof Error ? err.message : String(err)}\n`,
|
|
290
|
-
);
|
|
291
|
-
process.exit(1);
|
|
292
|
-
});
|
package/src/config.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import * as fs from "fs/promises";
|
|
2
|
-
import * as path from "path";
|
|
3
|
-
import type { AutomergeUrl } from "@automerge/automerge-repo";
|
|
4
|
-
|
|
5
|
-
export type Backend = "legacy" | "subduction";
|
|
6
|
-
|
|
7
|
-
export const CONFIG_VERSION = 3;
|
|
8
|
-
|
|
9
|
-
export interface PushworkConfig {
|
|
10
|
-
version: typeof CONFIG_VERSION;
|
|
11
|
-
rootUrl: AutomergeUrl;
|
|
12
|
-
backend: Backend;
|
|
13
|
-
shape: string;
|
|
14
|
-
artifactDirectories: string[];
|
|
15
|
-
branches: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const DIR = ".pushwork";
|
|
19
|
-
const CONFIG = "config.json";
|
|
20
|
-
const STORAGE = "storage";
|
|
21
|
-
|
|
22
|
-
export const pushworkDir = (root: string) => path.join(root, DIR);
|
|
23
|
-
export const storageDir = (root: string) => path.join(root, DIR, STORAGE);
|
|
24
|
-
|
|
25
|
-
export async function readConfig(root: string): Promise<PushworkConfig> {
|
|
26
|
-
const text = await fs.readFile(path.join(root, DIR, CONFIG), "utf8");
|
|
27
|
-
const parsed = JSON.parse(text) as Partial<PushworkConfig>;
|
|
28
|
-
if (parsed.version !== CONFIG_VERSION) {
|
|
29
|
-
throw new Error(
|
|
30
|
-
`pushwork config version mismatch: expected ${CONFIG_VERSION}, got ${parsed.version ?? "(missing)"}`,
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
if (!parsed.rootUrl) throw new Error("pushwork config missing rootUrl");
|
|
34
|
-
if (!parsed.backend) throw new Error("pushwork config missing backend");
|
|
35
|
-
if (!parsed.shape) throw new Error("pushwork config missing shape");
|
|
36
|
-
return {
|
|
37
|
-
version: CONFIG_VERSION,
|
|
38
|
-
rootUrl: parsed.rootUrl,
|
|
39
|
-
backend: parsed.backend,
|
|
40
|
-
shape: parsed.shape,
|
|
41
|
-
artifactDirectories: parsed.artifactDirectories ?? [],
|
|
42
|
-
branches: parsed.branches ?? true,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export async function writeConfig(
|
|
47
|
-
root: string,
|
|
48
|
-
config: PushworkConfig,
|
|
49
|
-
): Promise<void> {
|
|
50
|
-
await fs.mkdir(path.join(root, DIR), { recursive: true });
|
|
51
|
-
await fs.writeFile(
|
|
52
|
-
path.join(root, DIR, CONFIG),
|
|
53
|
-
JSON.stringify(config, null, 2) + "\n",
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export async function configExists(root: string): Promise<boolean> {
|
|
58
|
-
try {
|
|
59
|
-
await fs.access(path.join(root, DIR, CONFIG));
|
|
60
|
-
return true;
|
|
61
|
-
} catch {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
}
|
package/src/fs-tree.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import * as fs from "fs/promises";
|
|
2
|
-
import * as path from "path";
|
|
3
|
-
import type { Ignore } from "ignore";
|
|
4
|
-
import { isIgnored } from "./ignore.js";
|
|
5
|
-
import { log } from "./log.js";
|
|
6
|
-
|
|
7
|
-
const dlog = log("fs-tree");
|
|
8
|
-
|
|
9
|
-
export type FileTree = Map<string, Uint8Array>;
|
|
10
|
-
|
|
11
|
-
const toPosix = (p: string) => p.split(path.sep).join("/");
|
|
12
|
-
|
|
13
|
-
export async function walkDir(root: string, ig: Ignore): Promise<FileTree> {
|
|
14
|
-
dlog("walkDir root=%s", root);
|
|
15
|
-
const tree: FileTree = new Map();
|
|
16
|
-
await walk(root, root, ig, tree);
|
|
17
|
-
dlog("walkDir done: %d files", tree.size);
|
|
18
|
-
return tree;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async function walk(
|
|
22
|
-
root: string,
|
|
23
|
-
current: string,
|
|
24
|
-
ig: Ignore,
|
|
25
|
-
tree: FileTree,
|
|
26
|
-
): Promise<void> {
|
|
27
|
-
let names: string[];
|
|
28
|
-
try {
|
|
29
|
-
names = await fs.readdir(current);
|
|
30
|
-
} catch {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
for (const name of names) {
|
|
34
|
-
const full = path.join(current, name);
|
|
35
|
-
const rel = toPosix(path.relative(root, full));
|
|
36
|
-
if (isIgnored(ig, rel)) {
|
|
37
|
-
dlog("skip ignored: %s", rel);
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
let stat;
|
|
41
|
-
try {
|
|
42
|
-
stat = await fs.lstat(full);
|
|
43
|
-
} catch {
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
if (stat.isSymbolicLink()) continue;
|
|
47
|
-
if (stat.isDirectory()) {
|
|
48
|
-
await walk(root, full, ig, tree);
|
|
49
|
-
} else if (stat.isFile()) {
|
|
50
|
-
const bytes = await fs.readFile(full);
|
|
51
|
-
tree.set(rel, new Uint8Array(bytes));
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function byteEq(a: Uint8Array | undefined, b: Uint8Array): boolean {
|
|
57
|
-
if (!a) return false;
|
|
58
|
-
if (a.length !== b.length) return false;
|
|
59
|
-
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export async function writeFileAtomic(
|
|
64
|
-
target: string,
|
|
65
|
-
bytes: Uint8Array,
|
|
66
|
-
): Promise<void> {
|
|
67
|
-
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
68
|
-
await fs.writeFile(target, bytes);
|
|
69
|
-
}
|
|
70
|
-
|
package/src/ignore.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import * as fs from "fs/promises";
|
|
2
|
-
import * as path from "path";
|
|
3
|
-
import ignore, { type Ignore } from "ignore";
|
|
4
|
-
import { log } from "./log.js";
|
|
5
|
-
|
|
6
|
-
const dlog = log("ignore");
|
|
7
|
-
|
|
8
|
-
export const ALWAYS_IGNORE = [".pushwork", ".git", "node_modules"];
|
|
9
|
-
export const IGNORE_FILE = ".pushworkignore";
|
|
10
|
-
|
|
11
|
-
export async function loadIgnore(root: string): Promise<Ignore> {
|
|
12
|
-
const ig = ignore().add(ALWAYS_IGNORE);
|
|
13
|
-
dlog("always-ignored: %o", ALWAYS_IGNORE);
|
|
14
|
-
try {
|
|
15
|
-
const text = await fs.readFile(path.join(root, IGNORE_FILE), "utf8");
|
|
16
|
-
const patterns = text
|
|
17
|
-
.split(/\r?\n/)
|
|
18
|
-
.map((l) => l.trim())
|
|
19
|
-
.filter((l) => l && !l.startsWith("#"));
|
|
20
|
-
ig.add(patterns);
|
|
21
|
-
dlog("loaded %d patterns from %s", patterns.length, IGNORE_FILE);
|
|
22
|
-
} catch (err) {
|
|
23
|
-
const e = err as NodeJS.ErrnoException;
|
|
24
|
-
if (e.code !== "ENOENT") throw err;
|
|
25
|
-
dlog("no %s in %s", IGNORE_FILE, root);
|
|
26
|
-
}
|
|
27
|
-
return ig;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function isIgnored(ig: Ignore, relativePath: string): boolean {
|
|
31
|
-
if (relativePath === "" || relativePath === ".") return false;
|
|
32
|
-
return ig.ignores(relativePath);
|
|
33
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export {
|
|
2
|
-
init,
|
|
3
|
-
clone,
|
|
4
|
-
sync,
|
|
5
|
-
save,
|
|
6
|
-
status,
|
|
7
|
-
diff,
|
|
8
|
-
url,
|
|
9
|
-
currentBranch,
|
|
10
|
-
createBranch,
|
|
11
|
-
switchBranch,
|
|
12
|
-
listBranches,
|
|
13
|
-
mergeBranch,
|
|
14
|
-
previewMerge,
|
|
15
|
-
cutWorkdir,
|
|
16
|
-
pasteStash,
|
|
17
|
-
showStashes,
|
|
18
|
-
} from "./pushwork.js";
|
|
19
|
-
export type { MergeReport, MergePreview, MergePreviewEntry } from "./pushwork.js";
|
|
20
|
-
export type { Stash, StashEntry } from "./stash.js";
|
|
21
|
-
export type { Backend, PushworkConfig } from "./config.js";
|
|
22
|
-
export { CONFIG_VERSION } from "./config.js";
|
|
23
|
-
export type { Shape, VfsNode, UnixFileEntry } from "./shapes/index.js";
|
|
24
|
-
export {
|
|
25
|
-
vfsShape,
|
|
26
|
-
patchworkFolderShape,
|
|
27
|
-
isInArtifactDir,
|
|
28
|
-
normalizeArtifactDir,
|
|
29
|
-
pinUrl,
|
|
30
|
-
stripHeads,
|
|
31
|
-
} from "./shapes/index.js";
|
|
32
|
-
export {
|
|
33
|
-
DEFAULT_BRANCH,
|
|
34
|
-
detectDocType,
|
|
35
|
-
isBranchesDoc,
|
|
36
|
-
resolveEffectiveRoot,
|
|
37
|
-
type BranchesDoc,
|
|
38
|
-
} from "./branches.js";
|