2024-11-01 17:51:14 +00:00
|
|
|
import { exec } from "child_process";
|
2025-02-27 17:39:55 +00:00
|
|
|
import { AppContext, RepoMetadata } from "./types.js";
|
2025-01-14 21:37:31 +00:00
|
|
|
import { Repo } from "@sourcebot/db";
|
|
|
|
|
import { getRepoPath } from "./utils.js";
|
|
|
|
|
import { DEFAULT_SETTINGS } from "./constants.js";
|
2025-01-29 17:05:20 +00:00
|
|
|
import { getShardPrefix } from "./utils.js";
|
2025-02-27 17:39:55 +00:00
|
|
|
import { getBranches, getTags } from "./git.js";
|
|
|
|
|
import micromatch from "micromatch";
|
|
|
|
|
import { createLogger } from "./logger.js";
|
|
|
|
|
import { captureEvent } from "./posthog.js";
|
|
|
|
|
|
|
|
|
|
const logger = createLogger('zoekt');
|
2024-11-01 17:51:14 +00:00
|
|
|
|
2025-01-14 21:37:31 +00:00
|
|
|
export const indexGitRepository = async (repo: Repo, ctx: AppContext) => {
|
2025-02-27 17:39:55 +00:00
|
|
|
let revisions = [
|
2025-01-14 21:37:31 +00:00
|
|
|
'HEAD'
|
2024-11-07 02:28:10 +00:00
|
|
|
];
|
2025-02-27 17:39:55 +00:00
|
|
|
|
2025-01-14 21:37:31 +00:00
|
|
|
const repoPath = getRepoPath(repo, ctx);
|
2025-02-27 17:39:55 +00:00
|
|
|
const shardPrefix = getShardPrefix(repo.orgId, repo.id);
|
|
|
|
|
const metadata = repo.metadata as RepoMetadata;
|
|
|
|
|
|
|
|
|
|
if (metadata.branches) {
|
|
|
|
|
const branchGlobs = metadata.branches
|
|
|
|
|
const allBranches = await getBranches(repoPath);
|
|
|
|
|
const matchingBranches =
|
|
|
|
|
allBranches
|
|
|
|
|
.filter((branch) => micromatch.isMatch(branch, branchGlobs))
|
|
|
|
|
.map((branch) => `refs/heads/${branch}`);
|
|
|
|
|
|
|
|
|
|
revisions = [
|
|
|
|
|
...revisions,
|
|
|
|
|
...matchingBranches
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (metadata.tags) {
|
|
|
|
|
const tagGlobs = metadata.tags;
|
|
|
|
|
const allTags = await getTags(repoPath);
|
|
|
|
|
const matchingTags =
|
|
|
|
|
allTags
|
|
|
|
|
.filter((tag) => micromatch.isMatch(tag, tagGlobs))
|
|
|
|
|
.map((tag) => `refs/tags/${tag}`);
|
|
|
|
|
|
|
|
|
|
revisions = [
|
|
|
|
|
...revisions,
|
|
|
|
|
...matchingTags
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// zoekt has a limit of 64 branches/tags to index.
|
|
|
|
|
if (revisions.length > 64) {
|
|
|
|
|
logger.warn(`Too many revisions (${revisions.length}) for repo ${repo.id}, truncating to 64`);
|
|
|
|
|
captureEvent('backend_revisions_truncated', {
|
|
|
|
|
repoId: repo.id,
|
|
|
|
|
revisionCount: revisions.length,
|
|
|
|
|
});
|
|
|
|
|
revisions = revisions.slice(0, 64);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-24 21:16:08 +00:00
|
|
|
const command = `zoekt-git-index -allow_missing_branches -index ${ctx.indexPath} -file_limit ${DEFAULT_SETTINGS.maxFileSize} -branches ${revisions.join(',')} -tenant_id ${repo.orgId} -shard_prefix ${shardPrefix} ${repoPath}`;
|
2024-11-07 02:28:10 +00:00
|
|
|
|
2024-11-01 17:51:14 +00:00
|
|
|
return new Promise<{ stdout: string, stderr: string }>((resolve, reject) => {
|
2024-11-07 02:28:10 +00:00
|
|
|
exec(command, (error, stdout, stderr) => {
|
2024-11-01 17:51:14 +00:00
|
|
|
if (error) {
|
|
|
|
|
reject(error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
resolve({
|
|
|
|
|
stdout,
|
|
|
|
|
stderr
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
}
|