2021-11-29 02:03:49 +00:00
|
|
|
|
import fs from 'fs';
|
2021-11-25 12:27:33 +00:00
|
|
|
|
|
|
|
|
|
import git from 'isomorphic-git';
|
2021-11-29 02:06:19 +00:00
|
|
|
|
import http, { GitProgressEvent } from 'isomorphic-git/http/node';
|
2021-11-25 12:27:33 +00:00
|
|
|
|
|
2021-11-29 02:03:28 +00:00
|
|
|
|
import { isVacantAndWriteable, pointsToLFS } from './util';
|
2021-11-25 12:27:33 +00:00
|
|
|
|
import downloadBlobFromPointer from './download';
|
|
|
|
|
import { readPointer } from "./pointers";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const SYMLINK_MODE = 40960;
|
|
|
|
|
|
|
|
|
|
|
2021-11-29 02:06:19 +00:00
|
|
|
|
type ProgressHandler = (progress: GitProgressEvent) => void
|
|
|
|
|
|
|
|
|
|
|
2021-11-25 12:27:33 +00:00
|
|
|
|
/**
|
|
|
|
|
* Populates LFS cache for each repository object that is an LFS pointer.
|
|
|
|
|
*
|
|
|
|
|
* Does not touch working directory.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: If LFS cache path, as extracted from the pointer,
|
|
|
|
|
* is not writeable at the time of download start,
|
2021-11-29 02:06:19 +00:00
|
|
|
|
* the object will be silently skipped.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: This function skips objects silently in case of errors.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: onProgress currently doesn’t report loaded/total values accurately.
|
2021-11-25 12:27:33 +00:00
|
|
|
|
*/
|
2021-11-29 02:06:19 +00:00
|
|
|
|
export default async function populateCache(
|
|
|
|
|
workDir: string,
|
|
|
|
|
remoteURL: string,
|
|
|
|
|
ref: string = 'HEAD',
|
|
|
|
|
onProgress?: ProgressHandler,
|
|
|
|
|
) {
|
|
|
|
|
await git.walk({
|
2021-11-25 12:27:33 +00:00
|
|
|
|
fs,
|
|
|
|
|
dir: workDir,
|
2021-11-29 02:06:19 +00:00
|
|
|
|
trees: [git.TREE({ ref })],
|
|
|
|
|
map: async function lfsDownloadingWalker(filepath, entries) {
|
2021-11-25 12:27:33 +00:00
|
|
|
|
|
2021-11-29 02:06:19 +00:00
|
|
|
|
if (entries === null || entries[0] === null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2021-11-25 12:27:33 +00:00
|
|
|
|
|
2021-11-29 02:06:19 +00:00
|
|
|
|
onProgress?.({ phase: `skimming: ${filepath}`, loaded: 5, total: 10 });
|
2021-11-25 12:27:33 +00:00
|
|
|
|
|
2021-11-29 02:06:19 +00:00
|
|
|
|
const [entry] = entries;
|
|
|
|
|
const entryType = await entry.type();
|
2021-11-25 12:27:33 +00:00
|
|
|
|
|
2021-11-29 02:06:19 +00:00
|
|
|
|
if (entryType === 'tree') {
|
|
|
|
|
// Walk children
|
|
|
|
|
return true;
|
2021-11-25 12:27:33 +00:00
|
|
|
|
|
2021-11-29 02:06:19 +00:00
|
|
|
|
} else if (entryType === 'blob' && (await entry.mode()) !== SYMLINK_MODE) {
|
|
|
|
|
const content = await entry.content();
|
2021-11-25 12:27:33 +00:00
|
|
|
|
|
2021-11-29 02:06:19 +00:00
|
|
|
|
if (content) {
|
|
|
|
|
const buff = Buffer.from(content.buffer);
|
2021-11-25 12:27:33 +00:00
|
|
|
|
|
2021-11-29 02:06:19 +00:00
|
|
|
|
if (pointsToLFS(buff)) {
|
2021-11-25 12:27:33 +00:00
|
|
|
|
|
2021-11-29 02:06:19 +00:00
|
|
|
|
const pointer = readPointer({ dir: workDir, content: buff });
|
|
|
|
|
|
|
|
|
|
// Don’t even start the download if LFS cache path is not accessible,
|
|
|
|
|
// or if it already exists
|
|
|
|
|
if (await isVacantAndWriteable(pointer.objectPath) === false)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
onProgress?.({ phase: `downloading: ${filepath}`, loaded: 5, total: 10 });
|
|
|
|
|
|
|
|
|
|
await downloadBlobFromPointer({ http, url: remoteURL }, pointer);
|
2021-11-25 12:27:33 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-11-29 02:06:19 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
});
|
2021-11-25 12:27:33 +00:00
|
|
|
|
}
|