UNPKG

@opendevise/antora-git-lfs-extension

Version:

An Antora extension that uses the native git command to clone content source repositories in the playbook marked as lfs enabled and records the oid of all lfs files.

124 lines (112 loc) 4.71 kB
'use strict' const { createHash } = require('node:crypto') const expandPath = require('@antora/expand-path-helper') const fsp = require('node:fs/promises') const os = require('node:os') const ospath = require('node:path') const runCommand = require('@antora/run-command-helper') const invariably = { false: () => false, newObject: () => ({}) } module.exports.register = function ({ config }) { this.once('playbookBuilt', ({ playbook }) => { const defaultBranches = playbook.content.branches const lfsContentSources = playbook.content.sources.filter((it) => { if (!it.lfs) return false it.branches = [branchesToArray(it.branches ?? defaultBranches)[0] || 'HEAD'] return true }) if (!lfsContentSources.length) return let workspaceDir = resolveWorkspaceDir(config.workspaceDir, playbook.runtime.cacheDir, playbook.dir) workspaceDir = '.' + ospath.sep + ospath.relative(playbook.dir, workspaceDir) for (const contentSource of lfsContentSources) { contentSource.remoteUrl = contentSource.url contentSource.url = workspaceDir + ospath.sep + generateWorktreeName(contentSource.url, contentSource.branches[0]) } this.updateVariables({ playbook }) }) this.once('beforeProcess', async ({ playbook }) => { const lfsContentSources = playbook.content.sources.filter((it) => it.lfs) if (!lfsContentSources.length) return const processed = [] for (const contentSource of lfsContentSources) { const cloneDir = ospath.join(playbook.dir, contentSource.url) if (processed.includes(cloneDir)) continue processed.push(cloneDir) const cached = await fsp.stat(cloneDir).then((stat) => stat.isDirectory(), invariably.false) let gitCmd const gitArgs = [] let gitCwd if (cached) { if (playbook.runtime.fetch) gitCmd = 'pull' gitCwd = cloneDir } else { gitCmd = 'clone' const branch = contentSource.branches[0] if (!isDefaultBranch(branch)) gitArgs.push('-b', branch) gitArgs.push('-q', contentSource.remoteUrl, cloneDir) } if (gitCmd) { if (!playbook.runtime.quiet) console.log(`[${gitCmd}] ${contentSource.remoteUrl}`) await git(gitCmd, gitArgs, gitCwd) } } }) this.once('contentClassified', async ({ contentCatalog }) => { const gitLfsFilesByWorktree = {} for (const file of contentCatalog.getFiles()) { const worktree = file.src.origin?.worktree if (!worktree) continue if (!(worktree in gitLfsFilesByWorktree)) { gitLfsFilesByWorktree[worktree] = await git('lfs', ['ls-files', '-l'], worktree).then( (data) => data .trimEnd() .split('\n') .reduce((accum, line) => { const [oid, filepath] = line.split(/ [*-] /, 2) return Object.assign(accum, { [filepath]: oid }) }, {}), invariably.newObject ) } file.src.oid = gitLfsFilesByWorktree[worktree][file.src.path] } }) } function branchesToArray (branches) { if (!branches) return [] if (Array.isArray(branches)) return branches.map((it) => String(it)) return String(branches).split(/\s*,\s*/) } function generateWorktreeName (url, branch) { const normalizedUrl = url.toLowerCase().replace(/\.git/, '') const basename = normalizedUrl.split('/').pop() const branchQualifier = isDefaultBranch(branch) ? '' : '-' + branch return basename + branchQualifier + '-' + createHash('sha1').update(normalizedUrl).digest('hex') } function getCacheDir (userCacheDir) { if (userCacheDir) return userCacheDir let basedir switch (process.platform) { case 'win32': if ((basedir = process.env.APPDATA)) return ospath.join(basedir, 'antora', 'Caches') break case 'darwin': if ((basedir = os.homedir())) return path.join(basedir, 'Library/Caches', 'antora') break case 'linux': if ((basedir = process.env.XDG_CACHE_HOME)) return ospath.join(basedir, 'antora') if ((basedir = os.homedir())) return ospath.join(basedir, '.cache', 'antora') } return ospath.join(process.cwd(), '.cache', 'antora') } function isDefaultBranch (name) { return name === 'HEAD' || name === '.' || name === 'main' } function git (command, args, cwd) { const baseCall = process.env.GIT_COMMAND || 'git' return runCommand(baseCall, [command].concat(args), { cwd }).then((stdout) => stdout.toString().trimEnd()) } function resolveWorkspaceDir (requestedDir, userCacheDir, startDir) { const workspaceDir = requestedDir || getCacheDir(userCacheDir) + ospath.sep + 'content-with-lfs' return expandPath(workspaceDir, { dot: startDir }) }