diff --git a/src/populateCache.ts b/src/populateCache.ts index 69c17de..e6b1be7 100644 --- a/src/populateCache.ts +++ b/src/populateCache.ts @@ -1,7 +1,7 @@ import fs from 'fs'; import git from 'isomorphic-git'; -import http from 'isomorphic-git/http/node'; +import http, { GitProgressEvent } from 'isomorphic-git/http/node'; import { isVacantAndWriteable, pointsToLFS } from './util'; import downloadBlobFromPointer from './download'; @@ -11,6 +11,9 @@ import { readPointer } from "./pointers"; const SYMLINK_MODE = 40960; +type ProgressHandler = (progress: GitProgressEvent) => void + + /** * Populates LFS cache for each repository object that is an LFS pointer. * @@ -18,55 +21,60 @@ const SYMLINK_MODE = 40960; * * NOTE: If LFS cache path, as extracted from the pointer, * is not writeable at the time of download start, - * the object will be silently skipped; - * if LFS cache path is not writeable at the time download completes, - * an error will be thrown. + * 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. */ -export default async function populateCache(workDir: string, ref: string = 'HEAD') { - const remoteURL = await git.getConfig({ +export default async function populateCache( + workDir: string, + remoteURL: string, + ref: string = 'HEAD', + onProgress?: ProgressHandler, +) { + await git.walk({ fs, dir: workDir, - path: 'remote.origin.url', - }); - if (remoteURL) { - await git.walk({ - fs, - dir: workDir, - trees: [git.TREE({ ref })], - map: async function lfsDownloadingWalker(filepath, entries) { - if (entries === null || entries[0] === null) { - return null; - } + trees: [git.TREE({ ref })], + map: async function lfsDownloadingWalker(filepath, entries) { - const [entry] = entries; - const entryType = await entry.type(); + if (entries === null || entries[0] === null) { + return null; + } - if (entryType === 'tree') { - // Walk children - return true; + onProgress?.({ phase: `skimming: ${filepath}`, loaded: 5, total: 10 }); - } else if (entryType === 'blob' && (await entry.mode()) !== SYMLINK_MODE) { - const content = await entry.content(); + const [entry] = entries; + const entryType = await entry.type(); - if (content) { - const buff = Buffer.from(content.buffer); + if (entryType === 'tree') { + // Walk children + return true; - if (pointsToLFS(buff)) { - const pointer = readPointer({ dir: workDir, content: buff }); + } else if (entryType === 'blob' && (await entry.mode()) !== SYMLINK_MODE) { + const content = await entry.content(); - // 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; + if (content) { + const buff = Buffer.from(content.buffer); + if (pointsToLFS(buff)) { - await downloadBlobFromPointer({ http, url: remoteURL }, pointer); + 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); - } } } - return; } - }); - } + return; + } + }); }