@antora/content-aggregator 3.2.0-alpha.9 → 3.2.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/aggregate-content.js +201 -101
- package/lib/compute-origin.js +1 -1
- package/lib/filter-refs.js +6 -1
- package/lib/resolve-path-globs.js +1 -1
- package/package.json +6 -6
package/lib/aggregate-content.js
CHANGED
|
@@ -87,35 +87,41 @@ const URL_PORT_CLEANER_RX = /^([^/]+):[0-9]+(?=\/)/
|
|
|
87
87
|
*/
|
|
88
88
|
function aggregateContent (playbook) {
|
|
89
89
|
const startDir = playbook.dir || '.'
|
|
90
|
-
const { branches, editUrl, tags, sources } = playbook.content
|
|
91
|
-
const sourceDefaults = { branches, editUrl, tags }
|
|
90
|
+
const { branches, editUrl, tags, sources, worktrees } = playbook.content
|
|
91
|
+
const sourceDefaults = { branches, editUrl, tags, worktrees }
|
|
92
92
|
const { cacheDir: requestedCacheDir, fetch, quiet } = playbook.runtime
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
93
|
+
const READABLE_STREAM_DISABLED = process.env.READABLE_STREAM === 'disable'
|
|
94
|
+
if (!READABLE_STREAM_DISABLED) process.env.READABLE_STREAM = 'disable' // force use of Node.js stream APIs
|
|
95
|
+
return ensureCacheDir(requestedCacheDir, startDir)
|
|
96
|
+
.then((cacheDir) => {
|
|
97
|
+
const gitConfig = Object.assign({ ensureGitSuffix: true }, playbook.git)
|
|
98
|
+
const gitPlugins = loadGitPlugins(gitConfig, playbook.network || {}, startDir)
|
|
99
|
+
const concurrency = {
|
|
100
|
+
fetch: Math.max(gitConfig.fetchConcurrency || Infinity, 1),
|
|
101
|
+
read: Math.max(gitConfig.readConcurrency || Infinity, 1),
|
|
102
|
+
}
|
|
103
|
+
const sourcesByUrl = sources.reduce((accum, source) => {
|
|
104
|
+
return accum.set(source.url, [...(accum.get(source.url) || []), Object.assign({}, sourceDefaults, source)])
|
|
105
|
+
}, new Map())
|
|
106
|
+
const progress = quiet ? undefined : createProgress(sourcesByUrl.keys(), process.stdout)
|
|
107
|
+
const refPatternCache = Object.assign(new Map(), { braces: new Map() })
|
|
108
|
+
const fetchConfig = { always: fetch, depth: Math.max(0, gitConfig.fetchDepth ?? 1) }
|
|
109
|
+
const loadOpts = { cacheDir, fetch: fetchConfig, gitPlugins, progress, startDir, refPatternCache }
|
|
110
|
+
return collectFiles(sourcesByUrl, loadOpts, concurrency).then(buildAggregate, (err) => {
|
|
111
|
+
progress?.terminate()
|
|
112
|
+
throw err
|
|
113
|
+
})
|
|
110
114
|
})
|
|
111
|
-
|
|
115
|
+
.finally(() => READABLE_STREAM_DISABLED || delete process.env.READABLE_STREAM)
|
|
112
116
|
}
|
|
113
117
|
|
|
114
118
|
async function collectFiles (sourcesByUrl, loadOpts, concurrency, fetchedUrls = []) {
|
|
115
119
|
const loadTasks = [...sourcesByUrl.entries()].map(([url, sources]) => {
|
|
116
120
|
const loadOptsForUrl = Object.assign({}, loadOpts)
|
|
117
|
-
if (loadOpts.fetch.always && fetchedUrls.length && fetchedUrls.
|
|
121
|
+
if (loadOpts.fetch.always && fetchedUrls.length && ~fetchedUrls.indexOf(url)) loadOptsForUrl.fetch.always = false
|
|
118
122
|
if (tagsSpecified(sources)) loadOptsForUrl.fetch.tags = true
|
|
123
|
+
const commits = commitsRequested(sources)
|
|
124
|
+
if (commits) loadOptsForUrl.fetch.commits = commits
|
|
119
125
|
return loadRepository.bind(null, url, loadOptsForUrl, { url, sources })
|
|
120
126
|
})
|
|
121
127
|
return gracefulPromiseAllWithLimit(loadTasks, concurrency.fetch).then(([results, rejections]) => {
|
|
@@ -140,9 +146,10 @@ async function collectFiles (sourcesByUrl, loadOpts, concurrency, fetchedUrls =
|
|
|
140
146
|
})
|
|
141
147
|
}
|
|
142
148
|
|
|
143
|
-
function buildAggregate (
|
|
144
|
-
const
|
|
145
|
-
|
|
149
|
+
function buildAggregate (componentVersionBatches) {
|
|
150
|
+
const contentAggregate = []
|
|
151
|
+
const entries = new Map()
|
|
152
|
+
for (const batchesForOrigin of componentVersionBatches) {
|
|
146
153
|
for (const batch of batchesForOrigin) {
|
|
147
154
|
let key, entry
|
|
148
155
|
if ((entry = entries.get((key = batch.version + '@' + batch.name)))) {
|
|
@@ -151,11 +158,12 @@ function buildAggregate (componentVersionBuckets) {
|
|
|
151
158
|
;(batch.origins = entry.origins).push(origins[0])
|
|
152
159
|
Object.assign(entry, batch)
|
|
153
160
|
} else {
|
|
154
|
-
entries.set(key, batch)
|
|
161
|
+
entries.set(key, batch)
|
|
162
|
+
contentAggregate.push(batch)
|
|
155
163
|
}
|
|
156
164
|
}
|
|
157
165
|
}
|
|
158
|
-
return
|
|
166
|
+
return contentAggregate
|
|
159
167
|
}
|
|
160
168
|
|
|
161
169
|
async function loadRepository (url, opts, result = {}) {
|
|
@@ -177,6 +185,7 @@ async function loadRepository (url, opts, result = {}) {
|
|
|
177
185
|
const fetchOpts = buildFetchOptions(repo, progress, displayUrl, credentials, gitPlugins, fetch, 'fetch')
|
|
178
186
|
await git
|
|
179
187
|
.fetch(fetchOpts)
|
|
188
|
+
.then(() => ensureOids(fetchOpts))
|
|
180
189
|
.then(() => {
|
|
181
190
|
authStatus = identifyAuthStatus(credentialManager, credentials, url)
|
|
182
191
|
return git.setConfig(Object.assign({ path: 'remote.origin.private', value: authStatus }, repo))
|
|
@@ -192,12 +201,13 @@ async function loadRepository (url, opts, result = {}) {
|
|
|
192
201
|
authStatus = await git.getConfig(Object.assign({ path: 'remote.origin.private' }, repo))
|
|
193
202
|
}
|
|
194
203
|
} catch (gitErr) {
|
|
195
|
-
await fsp
|
|
204
|
+
await fsp.rm(dir, { recursive: true, force: true })
|
|
196
205
|
if (gitErr.rethrow) throw transformGitCloneError(gitErr, displayUrl)
|
|
197
206
|
const fetchOpts = buildFetchOptions(repo, progress, displayUrl, credentials, gitPlugins, fetch, 'clone')
|
|
198
207
|
await git
|
|
199
208
|
.clone(fetchOpts)
|
|
200
209
|
.then(() => git.resolveRef(Object.assign({ ref: 'HEAD', depth: 1 }, repo)))
|
|
210
|
+
.then(() => ensureOids(fetchOpts))
|
|
201
211
|
.then(() => {
|
|
202
212
|
authStatus = identifyAuthStatus(credentialManager, credentials, url)
|
|
203
213
|
return git.setConfig(Object.assign({ path: 'remote.origin.private', value: authStatus }, repo))
|
|
@@ -216,6 +226,7 @@ async function loadRepository (url, opts, result = {}) {
|
|
|
216
226
|
if (dotgitStat.isDirectory()) {
|
|
217
227
|
repo = { cache, dir, fs, gitdir: dotgit }
|
|
218
228
|
} else if (dotgitStat.isFile()) {
|
|
229
|
+
// NOTE isomorphic-git will discover the gitdir, but we must do it eagerly to process worktree patterns correctly
|
|
219
230
|
repo = await resolveRepositoryFromWorktree({ cache, dir, fs, gitdir: dotgit })
|
|
220
231
|
} else {
|
|
221
232
|
repo = { cache, dir, fs, gitdir: dir, noCheckout: true }
|
|
@@ -245,7 +256,7 @@ function extractCredentials (url) {
|
|
|
245
256
|
const credentials = username ? { username, password: password || '' } : {}
|
|
246
257
|
return { displayUrl, url, credentials }
|
|
247
258
|
}
|
|
248
|
-
if (url.startsWith('git@')) return { displayUrl: url, url: 'https://' + url.
|
|
259
|
+
if (url.startsWith('git@')) return { displayUrl: url, url: 'https://' + url.substring(4).replace(':', '/') }
|
|
249
260
|
return { displayUrl: url, url }
|
|
250
261
|
}
|
|
251
262
|
|
|
@@ -279,12 +290,12 @@ async function selectStartPathsForRepository (repo, sources) {
|
|
|
279
290
|
}
|
|
280
291
|
}
|
|
281
292
|
} else {
|
|
282
|
-
const { url, branches, tags } = source
|
|
293
|
+
const { url, branches, tags, commits } = source
|
|
283
294
|
const startPathInfo =
|
|
284
295
|
'startPaths' in source
|
|
285
296
|
? { 'start paths': source.startPaths || undefined }
|
|
286
297
|
: { 'start path': source.startPath || undefined }
|
|
287
|
-
const sourceInfo = yaml.dump({ url, branches, tags, ...startPathInfo }, { flowLevel: 1 }).trimRight()
|
|
298
|
+
const sourceInfo = yaml.dump({ url, branches, tags, commits, ...startPathInfo }, { flowLevel: 1 }).trimRight()
|
|
288
299
|
logger.info(`No matching references found for content source entry (${sourceInfo.replace(NEWLINE_RX, ' | ')})`)
|
|
289
300
|
}
|
|
290
301
|
}
|
|
@@ -293,11 +304,12 @@ async function selectStartPathsForRepository (repo, sources) {
|
|
|
293
304
|
|
|
294
305
|
// QUESTION should we resolve HEAD to a ref eagerly to avoid having to do a match on it?
|
|
295
306
|
async function selectReferences (source, repo, remote) {
|
|
296
|
-
let { branches: branchPatterns, tags: tagPatterns, worktrees: worktreePatterns } = source
|
|
307
|
+
let { branches: branchPatterns, tags: tagPatterns, commits, worktrees: worktreePatterns } = source
|
|
297
308
|
const managed = 'url' in repo
|
|
298
309
|
const isBare = managed || repo.noCheckout
|
|
299
310
|
const patternCache = repo.cache[REF_PATTERN_CACHE_KEY]
|
|
300
311
|
const noWorktree = managed ? undefined : false
|
|
312
|
+
const isLinkedWorktree = repo.worktree?.name
|
|
301
313
|
const refs = new Map()
|
|
302
314
|
if (
|
|
303
315
|
tagPatterns &&
|
|
@@ -308,11 +320,20 @@ async function selectReferences (source, repo, remote) {
|
|
|
308
320
|
const tags = await git.listTags(repo)
|
|
309
321
|
if (tags.length) {
|
|
310
322
|
for (const shortname of filterRefs(tags, tagPatterns, patternCache)) {
|
|
311
|
-
// NOTE tags are stored using
|
|
312
|
-
refs.set(
|
|
323
|
+
// NOTE tags are stored using Buffer keys to distinguish them from commits and branches
|
|
324
|
+
refs.set(Buffer.from(shortname), { shortname, fullname: 'tags/' + shortname, type: 'tag', head: noWorktree })
|
|
313
325
|
}
|
|
314
326
|
}
|
|
315
327
|
}
|
|
328
|
+
if (
|
|
329
|
+
commits &&
|
|
330
|
+
(commits = Array.isArray(commits) ? commits.map((commit) => String(commit)) : commits.split(CSV_RX)).length
|
|
331
|
+
) {
|
|
332
|
+
for (const oid of commits) {
|
|
333
|
+
// NOTE commits are stored using Symbol keys to distinguish them from tags and branches
|
|
334
|
+
refs.set(Symbol(oid), { oid, shortname: oid, fullname: 'commits/' + oid, type: 'commit' })
|
|
335
|
+
}
|
|
336
|
+
}
|
|
316
337
|
if (
|
|
317
338
|
!branchPatterns ||
|
|
318
339
|
!(branchPatterns = Array.isArray(branchPatterns)
|
|
@@ -321,38 +342,54 @@ async function selectReferences (source, repo, remote) {
|
|
|
321
342
|
) {
|
|
322
343
|
return [...refs.values()]
|
|
323
344
|
}
|
|
324
|
-
|
|
325
|
-
if (
|
|
326
|
-
if (worktreePatterns) {
|
|
345
|
+
let useWorktree = false
|
|
346
|
+
if (!managed && (useWorktree = {})) {
|
|
327
347
|
if (worktreePatterns === '.') {
|
|
328
|
-
|
|
348
|
+
isLinkedWorktree ? (useWorktree.linked = isLinkedWorktree) : isBare || (useWorktree.main = true)
|
|
349
|
+
worktreePatterns = []
|
|
350
|
+
} else if (!worktreePatterns) {
|
|
351
|
+
worktreePatterns = []
|
|
329
352
|
} else if (worktreePatterns === true) {
|
|
330
|
-
|
|
353
|
+
if (!isBare) useWorktree.main = true
|
|
354
|
+
// NOTE if we don't start at a linked worktree, linked worktree cannot be current worktree
|
|
355
|
+
if (isLinkedWorktree) useWorktree.linked = isLinkedWorktree
|
|
356
|
+
worktreePatterns = ['*']
|
|
357
|
+
} else if (worktreePatterns === '/.') {
|
|
358
|
+
if (!isBare) useWorktree.main = true
|
|
359
|
+
worktreePatterns = []
|
|
331
360
|
} else {
|
|
332
|
-
worktreePatterns =
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
361
|
+
worktreePatterns = (
|
|
362
|
+
Array.isArray(worktreePatterns)
|
|
363
|
+
? worktreePatterns.map((pattern) => String(pattern))
|
|
364
|
+
: splitRefPatterns(String(worktreePatterns))
|
|
365
|
+
).reduce((accum, it) => {
|
|
366
|
+
if (it === '/.') return (isBare || (useWorktree.main = true)) && accum
|
|
367
|
+
if (it === '.') {
|
|
368
|
+
isLinkedWorktree ? (useWorktree.linked = isLinkedWorktree) : isBare || (useWorktree.main = true)
|
|
369
|
+
} else {
|
|
370
|
+
accum.push(it)
|
|
371
|
+
}
|
|
372
|
+
return accum
|
|
373
|
+
}, [])
|
|
336
374
|
}
|
|
337
|
-
|
|
338
|
-
worktreePatterns = worktreePatterns === undefined ? [worktreeName || '.'] : []
|
|
375
|
+
if (!(useWorktree.main || useWorktree.linked)) useWorktree = false
|
|
339
376
|
}
|
|
340
377
|
let currentBranch
|
|
341
|
-
if (
|
|
342
|
-
if ((currentBranch = await getCurrentBranchName(repo, remote).then((branch) => branch ?? false))) {
|
|
343
|
-
branchPatterns = [currentBranch]
|
|
344
|
-
} else if (isBare) {
|
|
345
|
-
return [...refs.values()]
|
|
346
|
-
} else {
|
|
347
|
-
// NOTE current branch is undefined when HEAD is detached
|
|
348
|
-
const head = worktreePatterns[0] === '.' ? repo.dir : noWorktree
|
|
349
|
-
refs.set('HEAD', { shortname: 'HEAD', fullname: 'HEAD', type: 'branch', detached: true, head })
|
|
350
|
-
return [...refs.values()]
|
|
351
|
-
}
|
|
352
|
-
} else {
|
|
378
|
+
if (!isLinkedWorktree) {
|
|
353
379
|
let headBranchIdx
|
|
354
|
-
|
|
355
|
-
|
|
380
|
+
if (branchPatterns.length === 1 && (branchPatterns[0] === 'HEAD' || branchPatterns[0] === '.')) {
|
|
381
|
+
if ((currentBranch = await getCurrentBranchName(repo, remote).then((branch) => branch ?? false))) {
|
|
382
|
+
branchPatterns = [currentBranch]
|
|
383
|
+
} else if (isBare) {
|
|
384
|
+
return [...refs.values()]
|
|
385
|
+
} else {
|
|
386
|
+
// NOTE current branch is undefined when HEAD is detached
|
|
387
|
+
const head = useWorktree.main ? repo.dir : noWorktree
|
|
388
|
+
refs.set('HEAD', { shortname: 'HEAD', fullname: 'HEAD', type: 'branch', detached: true, head })
|
|
389
|
+
return [...refs.values()]
|
|
390
|
+
}
|
|
391
|
+
} else if (~(headBranchIdx = branchPatterns.indexOf('HEAD')) || ~(headBranchIdx = branchPatterns.indexOf('.'))) {
|
|
392
|
+
// NOTE we can assume at least two entries if HEAD or . are present
|
|
356
393
|
if ((currentBranch = await getCurrentBranchName(repo, remote).then((branch) => branch ?? false))) {
|
|
357
394
|
if (~branchPatterns.indexOf(currentBranch)) {
|
|
358
395
|
branchPatterns.splice(headBranchIdx, 1)
|
|
@@ -362,11 +399,7 @@ async function selectReferences (source, repo, remote) {
|
|
|
362
399
|
} else if (isBare) {
|
|
363
400
|
branchPatterns.splice(headBranchIdx, 1)
|
|
364
401
|
} else {
|
|
365
|
-
|
|
366
|
-
if (worktreePatterns[0] === '.') {
|
|
367
|
-
worktreePatterns = worktreePatterns.slice(1)
|
|
368
|
-
head = repo.dir
|
|
369
|
-
}
|
|
402
|
+
const head = useWorktree.main ? repo.dir : noWorktree
|
|
370
403
|
// NOTE current branch is undefined when HEAD is detached
|
|
371
404
|
refs.set('HEAD', { shortname: 'HEAD', fullname: 'HEAD', type: 'branch', detached: true, head })
|
|
372
405
|
branchPatterns.splice(headBranchIdx, 1)
|
|
@@ -389,23 +422,37 @@ async function selectReferences (source, repo, remote) {
|
|
|
389
422
|
if (currentBranch != null) return [currentBranch]
|
|
390
423
|
return getCurrentBranchName(repo).then((branch) => (branch ? [branch] : []))
|
|
391
424
|
})
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
425
|
+
let onMatch, worktrees
|
|
426
|
+
if (
|
|
427
|
+
(useWorktree || worktreePatterns.length) &&
|
|
428
|
+
(worktrees = await findWorktrees(repo, worktreePatterns, useWorktree)).size
|
|
429
|
+
) {
|
|
430
|
+
const headNames = new Map()
|
|
431
|
+
worktrees.forEach(({ name, symbolicNames }, shortname) => {
|
|
432
|
+
if (name) {
|
|
433
|
+
const headName = 'HEAD@' + name
|
|
434
|
+
localBranches.push(headName)
|
|
435
|
+
headNames.set(headName, shortname)
|
|
436
|
+
}
|
|
437
|
+
if (symbolicNames) {
|
|
438
|
+
for (const symbolicName of symbolicNames) {
|
|
439
|
+
const symbolicHeadName = symbolicName === 'HEAD' ? symbolicName : 'HEAD@' + symbolicName
|
|
440
|
+
localBranches.push(symbolicHeadName)
|
|
441
|
+
headNames.set(symbolicHeadName, shortname)
|
|
442
|
+
}
|
|
443
|
+
}
|
|
399
444
|
})
|
|
400
445
|
onMatch = (candidate, { pattern }) => {
|
|
401
|
-
const shortname =
|
|
402
|
-
|
|
446
|
+
const shortname = headNames.get(candidate)
|
|
447
|
+
if (!shortname) return candidate
|
|
448
|
+
if (pattern === 'HEAD' || pattern.startsWith('HEAD@')) return shortname
|
|
403
449
|
}
|
|
404
450
|
}
|
|
405
451
|
if (localBranches.length) {
|
|
406
452
|
const preferRemote = isBare && remoteBranches.length > 0
|
|
407
453
|
for (const shortname of filterRefs(localBranches, branchPatterns, patternCache, onMatch)) {
|
|
408
454
|
if (preferRemote && refs.has(shortname)) continue
|
|
455
|
+
worktrees ??= await findWorktrees(repo, worktreePatterns, useWorktree)
|
|
409
456
|
const head = (worktrees.get(shortname) || { head: false }).head
|
|
410
457
|
refs.set(shortname, { shortname, fullname: 'heads/' + shortname, type: 'branch', head })
|
|
411
458
|
}
|
|
@@ -432,9 +479,11 @@ async function selectStartPaths (source, repo, ref) {
|
|
|
432
479
|
const displayUrl = url || repo.dir
|
|
433
480
|
const worktreePath = ref.head
|
|
434
481
|
if (!worktreePath) {
|
|
435
|
-
ref.oid =
|
|
436
|
-
Object.assign(
|
|
437
|
-
|
|
482
|
+
ref.oid = ref.oid
|
|
483
|
+
? await git.expandOid(Object.assign({ oid: ref.oid }, repo)).catch(() => ref.oid)
|
|
484
|
+
: await git.resolveRef(
|
|
485
|
+
Object.assign(ref.detached ? { ref: 'HEAD', depth: 1 } : { ref: 'refs/' + ref.fullname }, repo)
|
|
486
|
+
)
|
|
438
487
|
}
|
|
439
488
|
if ('startPaths' in source) {
|
|
440
489
|
let startPaths
|
|
@@ -469,7 +518,9 @@ function collectFilesFromStartPath (startPath, repo, authStatus, ref, originUrl,
|
|
|
469
518
|
return (worktreePath ? readFilesFromWorktree(origin) : readFilesFromGitTree(repo, ref.oid, startPath))
|
|
470
519
|
.then((files) => {
|
|
471
520
|
const batch = deepClone((origin.descriptor = loadComponentDescriptor(files, ref, version)))
|
|
472
|
-
if ('nav' in batch && Array.isArray(batch.nav))
|
|
521
|
+
if ('nav' in batch && Array.isArray(batch.nav)) {
|
|
522
|
+
Object.defineProperty(batch.nav, 'origin', { configurable: true, value: origin, writable: true })
|
|
523
|
+
}
|
|
473
524
|
batch.files = files.map((file) => assignFileProperties(file, origin))
|
|
474
525
|
batch.origins = [origin]
|
|
475
526
|
return batch
|
|
@@ -656,10 +707,10 @@ function readGitSymlink (repo, root, parent, { oid, path: name }, following) {
|
|
|
656
707
|
let target
|
|
657
708
|
let targetParent = root
|
|
658
709
|
if (dirname) {
|
|
659
|
-
if (!(target = path.join('/', dirname, symlink).
|
|
710
|
+
if (!(target = path.join('/', dirname, symlink).substring(1)) || target === dirname) {
|
|
660
711
|
target = '.'
|
|
661
712
|
} else if (target.startsWith(dirname + '/')) {
|
|
662
|
-
target = target.
|
|
713
|
+
target = target.substring(dirname.length + 1) // join doesn't remove trailing separator
|
|
663
714
|
targetParent = parent
|
|
664
715
|
}
|
|
665
716
|
} else {
|
|
@@ -754,7 +805,7 @@ function loadComponentDescriptor (files, ref, version) {
|
|
|
754
805
|
!Object.entries(version).some(([pattern, replacement]) => {
|
|
755
806
|
const result = refname.replace(makeMatcherRx(pattern, VERSION_MATCHER_OPTS), '\0' + (replacement ?? ''))
|
|
756
807
|
if (result === refname) return false // no match
|
|
757
|
-
matched = result.
|
|
808
|
+
matched = result.substring(1)
|
|
758
809
|
return true
|
|
759
810
|
})
|
|
760
811
|
) {
|
|
@@ -801,6 +852,7 @@ function buildFetchOptions (repo, progress, displayUrl, credentialsFromUrl, gitP
|
|
|
801
852
|
} else if (!fetch.tags) {
|
|
802
853
|
opts.noTags = true
|
|
803
854
|
}
|
|
855
|
+
if (fetch.commits) opts.oids = fetch.commits
|
|
804
856
|
return opts
|
|
805
857
|
}
|
|
806
858
|
|
|
@@ -835,14 +887,17 @@ function createProgressListener (progress, progressLabel, operation) {
|
|
|
835
887
|
// NOTE leave room for indeterminate progress at end of bar; this isn't strictly needed for a bare clone
|
|
836
888
|
progressBar.scaleFactor = Math.max(0, (ticks - 1) / ticks)
|
|
837
889
|
progressBar.tick(0)
|
|
838
|
-
return Object.assign(onGitProgress.bind(progressBar), {
|
|
890
|
+
return Object.assign(onGitProgress.bind(progressBar), {
|
|
891
|
+
finish: onGitComplete.bind(progressBar),
|
|
892
|
+
reset: () => progressBar.update(0),
|
|
893
|
+
})
|
|
839
894
|
}
|
|
840
895
|
|
|
841
896
|
function formatProgressBar (label, maxLabelWidth, operation) {
|
|
842
897
|
const paddingSize = maxLabelWidth - label.length
|
|
843
898
|
let padding = ''
|
|
844
899
|
if (paddingSize < 0) {
|
|
845
|
-
label = '...' + label.
|
|
900
|
+
label = '...' + label.substring(-paddingSize + 3)
|
|
846
901
|
} else if (paddingSize) {
|
|
847
902
|
padding = ' '.repeat(paddingSize)
|
|
848
903
|
}
|
|
@@ -930,9 +985,9 @@ function resolveRemoteUrl (repo, remoteName) {
|
|
|
930
985
|
if (url.startsWith('https://') || url.startsWith('http://')) {
|
|
931
986
|
return ~url.indexOf('@') ? url.replace(URL_AUTH_CLEANER_RX, '$1') : url
|
|
932
987
|
}
|
|
933
|
-
if (url.startsWith('git@')) return 'https://' + url.
|
|
988
|
+
if (url.startsWith('git@')) return 'https://' + url.substring(4).replace(':', '/')
|
|
934
989
|
if (url.startsWith('ssh://')) {
|
|
935
|
-
return 'https://' + url.
|
|
990
|
+
return 'https://' + url.substring(url.indexOf('@') + 1 || 6).replace(URL_PORT_CLEANER_RX, '$1')
|
|
936
991
|
}
|
|
937
992
|
})
|
|
938
993
|
}
|
|
@@ -951,6 +1006,16 @@ function tagsSpecified (sources) {
|
|
|
951
1006
|
return sources.some(({ tags }) => tags && (Array.isArray(tags) ? tags.length : true))
|
|
952
1007
|
}
|
|
953
1008
|
|
|
1009
|
+
function commitsRequested (sources) {
|
|
1010
|
+
if (!sources.some(({ commits }) => commits && (Array.isArray(commits) ? commits.length : true))) return
|
|
1011
|
+
const result = new Set()
|
|
1012
|
+
for (const { commits } of sources) {
|
|
1013
|
+
if (!commits) continue
|
|
1014
|
+
for (const commit of Array.isArray(commits) ? commits : commits.split(CSV_RX)) result.add(String(commit))
|
|
1015
|
+
}
|
|
1016
|
+
return [...result]
|
|
1017
|
+
}
|
|
1018
|
+
|
|
954
1019
|
function loadGitPlugins (gitConfig, networkConfig, startDir) {
|
|
955
1020
|
const plugins = new Map((git.cores || git.default.cores || new Map()).get(GIT_CORE))
|
|
956
1021
|
for (const [name, request] of Object.entries(gitConfig.plugins || {})) {
|
|
@@ -1028,7 +1093,7 @@ function transformGitCloneError (err, displayUrl, authRequested) {
|
|
|
1028
1093
|
}
|
|
1029
1094
|
|
|
1030
1095
|
function splitRefPatterns (str) {
|
|
1031
|
-
return ~str.indexOf('{') ?
|
|
1096
|
+
return str.split(~str.indexOf('{') ? VENTILATED_CSV_RX : CSV_RX)
|
|
1032
1097
|
}
|
|
1033
1098
|
|
|
1034
1099
|
function camelCaseKeys (o, stopPaths = [], p = '') {
|
|
@@ -1054,45 +1119,57 @@ function coerceToString (value) {
|
|
|
1054
1119
|
function resolveRepositoryFromWorktree (repo) {
|
|
1055
1120
|
return fsp
|
|
1056
1121
|
.readFile(repo.gitdir, 'utf8')
|
|
1057
|
-
.then((contents) => contents.
|
|
1122
|
+
.then((contents) => contents.substring(8).trimEnd())
|
|
1058
1123
|
.then((worktreeGitdir) =>
|
|
1059
1124
|
fsp.readFile(ospath.join(worktreeGitdir, 'commondir'), 'utf8').then(
|
|
1060
1125
|
(contents) => {
|
|
1061
1126
|
const gitdir = ospath.join(worktreeGitdir, contents.trimEnd())
|
|
1062
1127
|
const dir = ospath.basename(gitdir) === '.git' ? ospath.dirname(gitdir) : gitdir
|
|
1063
|
-
|
|
1128
|
+
const name = ospath.basename(worktreeGitdir)
|
|
1129
|
+
return Object.assign(repo, { dir, gitdir, worktree: { gitdir: worktreeGitdir, name } })
|
|
1064
1130
|
},
|
|
1065
1131
|
() => repo
|
|
1066
1132
|
)
|
|
1067
1133
|
)
|
|
1068
1134
|
}
|
|
1069
1135
|
|
|
1070
|
-
function findWorktrees (repo, patterns) {
|
|
1071
|
-
|
|
1072
|
-
const mainWorktree =
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1136
|
+
function findWorktrees (repo, patterns, useWorktree) {
|
|
1137
|
+
const useLinkedWorktree = !!useWorktree.linked
|
|
1138
|
+
const mainWorktree = useWorktree.main
|
|
1139
|
+
? getCurrentBranchName(repo).then((branch) => {
|
|
1140
|
+
if (!branch) return
|
|
1141
|
+
return [branch, { head: repo.dir, name: undefined, symbolicNames: useLinkedWorktree ? ['/.'] : ['/.', '.'] }]
|
|
1142
|
+
})
|
|
1143
|
+
: Promise.resolve()
|
|
1144
|
+
if (!(useLinkedWorktree || patterns.length)) return mainWorktree.then((entry) => new Map(entry && [entry]))
|
|
1077
1145
|
const worktreesDir = ospath.join(repo.dir, repo.dir === repo.gitdir ? '' : '.git', 'worktrees')
|
|
1078
1146
|
const patternCache = repo.cache[REF_PATTERN_CACHE_KEY]
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1147
|
+
const scanWorktrees = patterns.length
|
|
1148
|
+
? fsp
|
|
1149
|
+
.readdir(worktreesDir)
|
|
1150
|
+
.then((worktreeNames) => filterRefs(worktreeNames, patterns, patternCache), invariably.emptyArray)
|
|
1151
|
+
.then((worktreeNames) => {
|
|
1152
|
+
if (useLinkedWorktree && !~worktreeNames.indexOf(useWorktree.linked)) worktreeNames.push(useWorktree.linked)
|
|
1153
|
+
return worktreeNames
|
|
1154
|
+
})
|
|
1155
|
+
: Promise.resolve(useLinkedWorktree ? [useWorktree.linked] : [])
|
|
1156
|
+
return scanWorktrees
|
|
1082
1157
|
.then((worktreeNames) =>
|
|
1083
1158
|
Promise.all(
|
|
1084
|
-
worktreeNames.map((
|
|
1085
|
-
const
|
|
1159
|
+
worktreeNames.map((name) => {
|
|
1160
|
+
const symbolicNames = useLinkedWorktree && name === useWorktree.linked ? ['.', 'HEAD'] : undefined
|
|
1161
|
+
const gitdir = ospath.resolve(worktreesDir, name)
|
|
1086
1162
|
// NOTE branch name defaults to worktree name if HEAD is detached
|
|
1087
|
-
return getCurrentBranchName(Object.assign({}, repo, { gitdir })).then((branch =
|
|
1163
|
+
return getCurrentBranchName(Object.assign({}, repo, { gitdir })).then((branch = name) =>
|
|
1088
1164
|
fsp
|
|
1089
1165
|
.readFile(ospath.join(gitdir, 'gitdir'), 'utf8')
|
|
1090
|
-
.then((contents) => [branch, { head: ospath.dirname(contents.trimEnd()), name
|
|
1166
|
+
.then((contents) => [branch, { head: ospath.dirname(contents.trimEnd()), name, symbolicNames }])
|
|
1091
1167
|
)
|
|
1092
1168
|
})
|
|
1093
1169
|
)
|
|
1094
1170
|
)
|
|
1095
|
-
.then((entries) =>
|
|
1171
|
+
.then((entries) => new Map(entries))
|
|
1172
|
+
.then((worktrees) => mainWorktree.then((result) => (result ? worktrees.set(result[0], result[1]) : worktrees)))
|
|
1096
1173
|
}
|
|
1097
1174
|
|
|
1098
1175
|
async function gracefulPromiseAllWithLimit (tasks, limit = Infinity) {
|
|
@@ -1128,4 +1205,27 @@ async function promiseAllWithLimit (tasks, limit = Infinity) {
|
|
|
1128
1205
|
return Promise.all(started)
|
|
1129
1206
|
}
|
|
1130
1207
|
|
|
1208
|
+
async function ensureOids (opts) {
|
|
1209
|
+
if (!opts.oids) return
|
|
1210
|
+
let prevShallowCommits = await getShallowCommits(opts)
|
|
1211
|
+
if (prevShallowCommits == null) return
|
|
1212
|
+
let oids = opts.oids.slice()
|
|
1213
|
+
const deepenOpts = Object.assign({}, opts, { relative: true })
|
|
1214
|
+
const format = 'deflated'
|
|
1215
|
+
while (oids.length) {
|
|
1216
|
+
deepenOpts.onProgress?.reset()
|
|
1217
|
+
await git.fetch(deepenOpts)
|
|
1218
|
+
const shallowCommits = await getShallowCommits(opts)
|
|
1219
|
+
if (shallowCommits == null || shallowCommits === prevShallowCommits) break
|
|
1220
|
+
prevShallowCommits = shallowCommits
|
|
1221
|
+
oids = await Promise.all(
|
|
1222
|
+
oids.map((oid) => git.readObject(Object.assign({ oid, format }, opts)).then(invariably.void, () => oid))
|
|
1223
|
+
).then((results) => results.filter((it) => it))
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
function getShallowCommits ({ gitdir }) {
|
|
1228
|
+
return fsp.readFile(ospath.join(gitdir, 'shallow'), 'utf8').catch(invariably.void)
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1131
1231
|
module.exports = aggregateContent
|
package/lib/compute-origin.js
CHANGED
|
@@ -42,7 +42,7 @@ function computeOrigin (url, authStatus, gitdir, ref, startPath, worktreePath =
|
|
|
42
42
|
} else if (editUrl) {
|
|
43
43
|
const vars = {
|
|
44
44
|
path: () => (startPath ? path.join(startPath, '%s') : '%s'),
|
|
45
|
-
ref: () => 'refs/' + (reftype === 'branch' ? '
|
|
45
|
+
ref: () => 'refs/' + (reftype === 'branch' ? 'head' : reftype) + 's/' + refname,
|
|
46
46
|
refhash: () => refhash,
|
|
47
47
|
reftype: () => reftype,
|
|
48
48
|
refname: () => refname,
|
package/lib/filter-refs.js
CHANGED
|
@@ -6,7 +6,7 @@ function compileRx (pattern, opts) {
|
|
|
6
6
|
if (pattern === '*' || pattern === '**') return MATCH_ALL_RX
|
|
7
7
|
const rx =
|
|
8
8
|
pattern.charAt() === '!' // we handle negate ourselves
|
|
9
|
-
? Object.defineProperty(makeMatcherRx((pattern = pattern.
|
|
9
|
+
? Object.defineProperty(makeMatcherRx((pattern = pattern.substring(1)), opts), 'negated', { value: true })
|
|
10
10
|
: makeMatcherRx(pattern, opts)
|
|
11
11
|
return Object.defineProperty(rx, 'pattern', { value: pattern })
|
|
12
12
|
}
|
|
@@ -39,6 +39,7 @@ function createMatcher (patterns, cache = Object.assign(new Map(), { braces: new
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
function filterRefs (candidates, patterns, cache, onMatch) {
|
|
42
|
+
if (!(patterns = patterns.filter(compact)).length) return []
|
|
42
43
|
const match = createMatcher(patterns, cache)
|
|
43
44
|
return candidates.reduce((accum, candidate) => {
|
|
44
45
|
if ((candidate = match(candidate, onMatch))) accum.push(candidate)
|
|
@@ -46,4 +47,8 @@ function filterRefs (candidates, patterns, cache, onMatch) {
|
|
|
46
47
|
}, [])
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
function compact (str) {
|
|
51
|
+
return str !== ''
|
|
52
|
+
}
|
|
53
|
+
|
|
49
54
|
module.exports = filterRefs
|
|
@@ -14,7 +14,7 @@ function resolvePathGlobs (base, patterns, listDirents, retrievePath, tree = { p
|
|
|
14
14
|
if (pattern.charAt() === '!') {
|
|
15
15
|
return paths.then((resolvedPaths) => {
|
|
16
16
|
if (resolvedPaths.length) {
|
|
17
|
-
const rx = makeMatcherRx(pattern.
|
|
17
|
+
const rx = makeMatcherRx(pattern.substring(1), MATCHER_OPTS)
|
|
18
18
|
return resolvedPaths.filter((it) => !rx.test(it))
|
|
19
19
|
}
|
|
20
20
|
return resolvedPaths
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antora/content-aggregator",
|
|
3
|
-
"version": "3.2.0-
|
|
3
|
+
"version": "3.2.0-rc.1",
|
|
4
4
|
"description": "Fetches and aggregates content from distributed sources for use in an Antora documentation pipeline.",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"author": "OpenDevise Inc. (https://opendevise.com)",
|
|
@@ -33,14 +33,14 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@antora/expand-path-helper": "~3.0",
|
|
36
|
-
"@antora/logger": "3.2.0-
|
|
36
|
+
"@antora/logger": "3.2.0-rc.1",
|
|
37
37
|
"@antora/user-require-helper": "~3.0",
|
|
38
38
|
"braces": "~3.0",
|
|
39
39
|
"cache-directory": "~2.0",
|
|
40
40
|
"fast-glob": "~3.3",
|
|
41
41
|
"hpagent": "~1.2",
|
|
42
|
-
"isomorphic-git": "~1.
|
|
43
|
-
"js-yaml": "~4.
|
|
42
|
+
"isomorphic-git": "~1.38",
|
|
43
|
+
"js-yaml": "~4.2",
|
|
44
44
|
"multi-progress": "~4.0",
|
|
45
45
|
"picomatch": "~4.0",
|
|
46
46
|
"progress": "~2.0",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"vinyl": "~3.0"
|
|
50
50
|
},
|
|
51
51
|
"engines": {
|
|
52
|
-
"node": ">=
|
|
52
|
+
"node": ">=20.0.0"
|
|
53
53
|
},
|
|
54
54
|
"files": [
|
|
55
55
|
"lib/"
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"web publishing"
|
|
66
66
|
],
|
|
67
67
|
"scripts": {
|
|
68
|
-
"test": "
|
|
68
|
+
"test": "node --test",
|
|
69
69
|
"prepublishOnly": "npx -y downdoc@latest --prepublish",
|
|
70
70
|
"postpublish": "npx -y downdoc@latest --postpublish"
|
|
71
71
|
}
|