import type Backend from '../backend' import Limits from '../limits' import Argv from './argv' import { FAILED_RUN } from './failed-run' import { fetchDiff } from './fetch-diff.js' import { fetchFileHunks } from './fetch-file-hunks.js' import { GIT_BASE_MODES } from './git-base-modes' import { GIT_WORDS } from './git-words' import Probes from './probes' import type Types from './types' /** * The git backend over the session's directory: the repository read with * one `rev-parse` in that directory, then every child pinned to it * (`--git-dir`, `--work-tree`, cwd the top) under the C locale and the * fetch's timeout (gitDiff.ts execPinnedGit). * * @param host the bound host's runner and probes * @returns the backend, or null outside a git working tree */ export async function gitBackendOf( host: Backend.BackendHost, ): Promise { const runOf = (pinned: Types.Repository | null): Types.GitRun => async argv => { try { return await host.run( ['git', ...(pinned ? Argv.pinnedLeadOf(pinned) : []), ...argv], { timeoutMs: Limits.GIT_TIMEOUT_MS, env: Argv.GIT_CHILD_ENV, ...(pinned && { cwd: pinned.toplevel }), }, ) } catch { return FAILED_RUN } } const repository = await Probes.repositoryOf(runOf(null)) if (!repository) { return null } const run = runOf(repository) const depsOf = (): Types.GitDeps => ({ run, repository, mtimeOf: host.mtimeOf, entryKindsOf: host.entryKindsOf, sessionStartMs: host.sessionStartMsOf(), onBranchBase: host.onBranchBase, }) return { repository, baseModes: GIT_BASE_MODES, words: GIT_WORDS, fetchDiff: mode => fetchDiff(depsOf(), mode), fetchFileHunks: (data, file) => fetchFileHunks(run, data, file), headKeyOf: () => Probes.headKeyOf({ ...depsOf(), readFile: host.readFile }, repository), } }