170 lines · 6.4 KB
import { env } from "cloudflare:workers";
import { batch, chunks, first, placeholders, run, stmt } from "../db";
import { loadRepoById } from "../repos";
import { branchSha, listRefs } from "../git/refs";
import { withStore } from "../git/store";
import type { GitStore } from "../git/store";
import { diffTreesBounded } from "../git/diff";

const FILES_PER_MESSAGE = 100;
const MAX_INDEXED_FILES = 5000;
const MAX_INDEXED_BYTES = 128 * 1024;
const BINARY_SNIFF = 8000;
const READ_CONCURRENCY = 8;
const SKIPPED_MODES = new Set(["120000", "160000"]);
const decoder = new TextDecoder("utf-8", { fatal: true });

type IndexJob = { commit: string; tree: string; base: string | null; offset: number };

export type CodeIndexMessage = { kind: "code.index"; repoId: string; job?: IndexJob };

type Plan = { full: boolean; upserts: Array<{ path: string; sha: string }>; deletes: string[] };

async function planChanges(store: GitStore, base: string | null, tree: string): Promise<Plan> {
  if (base) {
    const { changes, truncated } = await diffTreesBounded(store, base, tree);
    if (!truncated) {
      const upserts: Plan["upserts"] = [];
      const deletes: string[] = [];
      for (const change of changes) {
        if (change.oldPath) deletes.push(change.oldPath);
        if (change.status === "deleted" || !change.newSha || SKIPPED_MODES.has(change.newMode ?? "")) {
          deletes.push(change.path);
        } else {
          upserts.push({ path: change.path, sha: change.newSha });
        }
      }
      return { full: false, upserts, deletes };
    }
  }
  const { entries } = await store.walk(tree, MAX_INDEXED_FILES);