fix(core): batch calls to git hash-object to avoid E2BIG error

This commit is contained in:
Craigory Coppola 2022-02-14 12:49:22 -05:00 committed by Victor Savkin
parent 471f7be539
commit efedd2eff7

View File

@ -6,18 +6,42 @@ export async function getGitHashForFiles(
potentialFilesToHash: string[],
path: string
): Promise<{ hashes: Map<string, string>; deleted: string[] }> {
const filesToHash = [];
const deleted = [];
for (let f of potentialFilesToHash) {
if (fileExists(joinPathFragments(path, f))) {
filesToHash.push(f);
} else {
deleted.push(f);
}
}
const { filesToHash, deleted } = getActualFilesToHash(
potentialFilesToHash,
path
);
const res: Map<string, string> = new Map<string, string>();
const promises: Promise<Map<string, string>>[] = [];
if (filesToHash.length) {
// On windows the max length is limited by the length of
// the overall comand, rather than the number of individual
// arguments. Since file paths are large and rather variable,
// we use a smaller batchSize.
const batchSize = process.platform === 'win32' ? 500 : 4000;
for (
let startIndex = 0;
startIndex < filesToHash.length;
startIndex += batchSize
) {
promises.push(
getGitHashForBatch(
filesToHash.slice(startIndex, startIndex + batchSize),
path
)
);
}
}
// Merge batch results into final result set
const batchResults = await Promise.all(promises);
for (const batch of batchResults) {
batch.forEach((v, k) => res.set(k, v));
}
return { hashes: res, deleted };
}
async function getGitHashForBatch(filesToHash: string[], path) {
const res: Map<string, string> = new Map<string, string>();
const hashStdout = await spawnProcess(
'git',
['hash-object', ...filesToHash],
@ -34,8 +58,23 @@ export async function getGitHashForFiles(
const filePath: string = filesToHash[i];
res.set(filePath, hash);
}
return res;
}
function getActualFilesToHash(
potentialFilesToHash: string[],
path: string
): { filesToHash: string[]; deleted: string[] } {
const filesToHash = [];
const deleted = [];
for (let f of potentialFilesToHash) {
if (fileExists(joinPathFragments(path, f))) {
filesToHash.push(f);
} else {
deleted.push(f);
}
return { hashes: res, deleted };
}
return { filesToHash, deleted };
}
async function spawnProcess(command: string, args: string[], cwd: string) {