Skip to content
File

Blob: src/worker/do/repo/repoDO/seeding.ts

typescript95 lines
1import { buildPackV2 } from "@/worker/git/pack/build";
2import { encodeGitObject } from "@/worker/git/core";
3import { scanPack, resolveDeltasAndWriteIdx } from "@/worker/git/pack/indexer";
4import { createLogger } from "@/worker/common/logger";
5import { r2PackKey } from "@/worker/keys";
6import type { Limiter } from "@/worker/git/operations/limits";
7 
8import { asTypedStorage, objKey } from "../repoState";
9import type { RepoStateSchema } from "../repoState";
10import { getDb, upsertPackCatalogRow } from "../db";
11 
12/** No-op limiter for test-only seeding path (no real concurrency limits). */
13const seedLimiter: Limiter = { run: (_label, fn) => fn() };
14const seedLog = createLogger(undefined, { service: "seed" });
15 
16export async function seedMinimalRepoState(args: {
17 ctx: DurableObjectState;
18 env: Env;
19 prefix: string;
20 withPack: boolean;
21}): Promise<{ commitOid: string; treeOid: string }> {
22 const store = asTypedStorage<RepoStateSchema>(args.ctx.storage);
23 const db = getDb(args.ctx.storage);
24 
25 const treeContent = new Uint8Array(0);
26 const { oid: treeOid, zdata: treeZ } = await encodeGitObject("tree", treeContent);
27 
28 const author = `You <you@example.com> 0 +0000`;
29 const message = "initial\n";
30 const commitPayload =
31 `tree ${treeOid}\n` + `author ${author}\n` + `committer ${author}\n` + `\n${message}`;
32 const { oid: commitOid, zdata: commitZ } = await encodeGitObject(
33 "commit",
34 new TextEncoder().encode(commitPayload)
35 );
36 
37 if (args.withPack) {
38 const packData = await buildPackV2([
39 { type: "tree", payload: treeContent },
40 { type: "commit", payload: new TextEncoder().encode(commitPayload) },
41 ]);
42 
43 const packKey = r2PackKey(args.prefix, `pack-test-${Date.now()}.pack`);
44 await args.env.REPO_BUCKET.put(packKey, packData);
45 
46 // Index the pack to produce .idx in R2
47 const scanResult = await scanPack({
48 env: args.env,
49 packKey,
50 packSize: packData.byteLength,
51 limiter: seedLimiter,
52 countSubrequest: () => {},
53 log: seedLog,
54 });
55 const resolveResult = await resolveDeltasAndWriteIdx({
56 env: args.env,
57 packKey,
58 packSize: packData.byteLength,
59 limiter: seedLimiter,
60 countSubrequest: () => {},
61 log: seedLog,
62 scanResult,
63 repoId: "test",
64 });
65 
66 // Register in pack catalog
67 const seq = (await store.get("nextPackSeq")) || 1;
68 await upsertPackCatalogRow(db, {
69 packKey,
70 kind: "receive",
71 state: "active",
72 tier: 0,
73 seqLo: seq,
74 seqHi: seq,
75 objectCount: resolveResult.objectCount,
76 packBytes: packData.byteLength,
77 idxBytes: resolveResult.idxBytes,
78 createdAt: Date.now(),
79 supersededBy: null,
80 });
81 
82 const packsetVersion = ((await store.get("packsetVersion")) || 0) + 1;
83 await store.put("packsetVersion", packsetVersion);
84 await store.put("nextPackSeq", seq + 1);
85 } else {
86 await store.put(objKey(treeOid), treeZ);
87 await store.put(objKey(commitOid), commitZ);
88 }
89 
90 await store.put("refs", [{ name: "refs/heads/main", oid: commitOid }]);
91 await store.put("head", { target: "refs/heads/main" });
92 
93 return { treeOid, commitOid };
94}