@antora/content-aggregator 3.0.0-beta.2 → 3.0.0-beta.6
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 +150 -153
- package/lib/constants.js +1 -12
- package/lib/filter-refs.js +13 -31
- package/lib/git-credential-manager-store.js +7 -9
- package/lib/invariably.js +3 -0
- package/lib/matcher.js +32 -0
- package/lib/resolve-path-globs.js +7 -19
- package/package.json +7 -4
package/lib/aggregate-content.js
CHANGED
|
@@ -15,17 +15,17 @@ const getCacheDir = require('cache-directory')
|
|
|
15
15
|
const GitCredentialManagerStore = require('./git-credential-manager-store')
|
|
16
16
|
const git = require('./git')
|
|
17
17
|
const { NotFoundError, ObjectTypeError, UnknownTransportError, UrlParseError } = git.Errors
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
18
|
+
const globStream = require('glob-stream')
|
|
19
|
+
const invariably = require('./invariably')
|
|
20
|
+
const { makeMatcherRx, versionMatcherOpts: VERSION_MATCHER_OPTS } = require('./matcher')
|
|
21
|
+
const MultiProgress = require('multi-progress') // calls require('progress') as a peer dependencies
|
|
21
22
|
const ospath = require('path')
|
|
22
23
|
const { posix: path } = ospath
|
|
23
24
|
const posixify = ospath.sep === '\\' ? (p) => p.replace(/\\/g, '/') : undefined
|
|
24
25
|
const { fs: resolvePathGlobsFs, git: resolvePathGlobsGit } = require('./resolve-path-globs')
|
|
25
|
-
const {
|
|
26
|
-
const
|
|
26
|
+
const { pipeline, Writable } = require('stream')
|
|
27
|
+
const forEach = (write) => new Writable({ objectMode: true, write })
|
|
27
28
|
const userRequire = require('@antora/user-require-helper')
|
|
28
|
-
const vfs = require('vinyl-fs')
|
|
29
29
|
const yaml = require('js-yaml')
|
|
30
30
|
|
|
31
31
|
const {
|
|
@@ -37,12 +37,10 @@ const {
|
|
|
37
37
|
GIT_CORE,
|
|
38
38
|
GIT_OPERATION_LABEL_LENGTH,
|
|
39
39
|
GIT_PROGRESS_PHASES,
|
|
40
|
-
PICOMATCH_VERSION_OPTS,
|
|
41
40
|
REF_PATTERN_CACHE_KEY,
|
|
42
41
|
SYMLINK_FILE_MODE,
|
|
43
42
|
VALID_STATE_FILENAME,
|
|
44
43
|
} = require('./constants')
|
|
45
|
-
|
|
46
44
|
const ANY_SEPARATOR_RX = /[:/]/
|
|
47
45
|
const CSV_RX = /\s*,\s*/
|
|
48
46
|
const VENTILATED_CSV_RX = /\s*,\s+/
|
|
@@ -229,9 +227,8 @@ async function loadRepository (url, opts) {
|
|
|
229
227
|
try {
|
|
230
228
|
await git.resolveRef(Object.assign({ ref: 'HEAD', depth: 1 }, repo))
|
|
231
229
|
} catch {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
)
|
|
230
|
+
const msg = `Local content source must be a git repository: ${dir}${url !== dir ? ' (url: ' + url + ')' : ''}`
|
|
231
|
+
throw new Error(msg)
|
|
235
232
|
}
|
|
236
233
|
} else {
|
|
237
234
|
throw new Error(`Local content source does not exist: ${dir}${url !== dir ? ' (url: ' + url + ')' : ''}`)
|
|
@@ -272,99 +269,100 @@ async function selectReferences (source, repo, remote) {
|
|
|
272
269
|
const patternCache = repo.cache[REF_PATTERN_CACHE_KEY]
|
|
273
270
|
const noWorktree = repo.url ? undefined : null
|
|
274
271
|
const refs = new Map()
|
|
275
|
-
if (
|
|
276
|
-
tagPatterns
|
|
272
|
+
if (
|
|
273
|
+
tagPatterns &&
|
|
274
|
+
(tagPatterns = Array.isArray(tagPatterns)
|
|
277
275
|
? tagPatterns.map((pattern) => String(pattern))
|
|
278
|
-
: splitRefPatterns(String(tagPatterns))
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
276
|
+
: splitRefPatterns(String(tagPatterns))).length
|
|
277
|
+
) {
|
|
278
|
+
const tags = await git.listTags(repo)
|
|
279
|
+
if (tags.length) {
|
|
280
|
+
for (const shortname of filterRefs(tags, tagPatterns, patternCache)) {
|
|
282
281
|
// NOTE tags are stored using symbol keys to distinguish them from branches
|
|
283
282
|
refs.set(Symbol(shortname), { shortname, fullname: 'tags/' + shortname, type: 'tag', head: noWorktree })
|
|
284
283
|
}
|
|
285
284
|
}
|
|
286
285
|
}
|
|
287
|
-
if (branchPatterns)
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
286
|
+
if (!branchPatterns) return [...refs.values()]
|
|
287
|
+
if (worktreePatterns) {
|
|
288
|
+
if (worktreePatterns === '.') {
|
|
289
|
+
worktreePatterns = ['.']
|
|
290
|
+
} else if (worktreePatterns === true) {
|
|
291
|
+
worktreePatterns = ['.', '*']
|
|
292
|
+
} else {
|
|
293
|
+
worktreePatterns = Array.isArray(worktreePatterns)
|
|
294
|
+
? worktreePatterns.map((pattern) => String(pattern))
|
|
295
|
+
: splitRefPatterns(String(worktreePatterns))
|
|
298
296
|
}
|
|
299
|
-
|
|
300
|
-
|
|
297
|
+
}
|
|
298
|
+
const branchPatternsString = String(branchPatterns)
|
|
299
|
+
if (branchPatternsString === 'HEAD' || branchPatternsString === '.') {
|
|
300
|
+
const currentBranch = await getCurrentBranchName(repo, remote)
|
|
301
|
+
if (currentBranch) {
|
|
302
|
+
branchPatterns = [currentBranch]
|
|
303
|
+
} else if (isBare) {
|
|
304
|
+
return [...refs.values()]
|
|
305
|
+
} else {
|
|
306
|
+
// NOTE current branch is undefined when HEAD is detached
|
|
307
|
+
const head = worktreePatterns[0] === '.' ? repo.dir : noWorktree
|
|
308
|
+
refs.set('HEAD', { shortname: 'HEAD', fullname: 'HEAD', type: 'branch', detached: true, head })
|
|
309
|
+
return [...refs.values()]
|
|
310
|
+
}
|
|
311
|
+
} else if (
|
|
312
|
+
(branchPatterns = Array.isArray(branchPatterns)
|
|
313
|
+
? branchPatterns.map((pattern) => String(pattern))
|
|
314
|
+
: splitRefPatterns(branchPatternsString)).length
|
|
315
|
+
) {
|
|
316
|
+
let headBranchIdx
|
|
317
|
+
// NOTE we can assume at least two entries if HEAD or . are present
|
|
318
|
+
if (~(headBranchIdx = branchPatterns.indexOf('HEAD')) || ~(headBranchIdx = branchPatterns.indexOf('.'))) {
|
|
301
319
|
const currentBranch = await getCurrentBranchName(repo, remote)
|
|
302
320
|
if (currentBranch) {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if (!isBare) {
|
|
306
|
-
// NOTE current branch is undefined when HEAD is detached
|
|
307
|
-
const head = worktreePatterns[0] === '.' ? repo.dir : noWorktree
|
|
308
|
-
refs.set('HEAD', { shortname: 'HEAD', fullname: 'HEAD', type: 'branch', detached: true, head })
|
|
309
|
-
}
|
|
310
|
-
return [...refs.values()]
|
|
311
|
-
}
|
|
312
|
-
} else if (
|
|
313
|
-
(branchPatterns = Array.isArray(branchPatterns)
|
|
314
|
-
? branchPatterns.map((pattern) => String(pattern))
|
|
315
|
-
: splitRefPatterns(branchPatternsString)).length
|
|
316
|
-
) {
|
|
317
|
-
let headBranchIdx
|
|
318
|
-
// NOTE we can assume at least two entries if HEAD or . are present
|
|
319
|
-
if (~(headBranchIdx = branchPatterns.indexOf('HEAD')) || ~(headBranchIdx = branchPatterns.indexOf('.'))) {
|
|
320
|
-
const currentBranch = await getCurrentBranchName(repo, remote)
|
|
321
|
-
if (currentBranch) {
|
|
322
|
-
// NOTE ignore if current branch is already in list
|
|
323
|
-
if (~branchPatterns.indexOf(currentBranch)) {
|
|
324
|
-
branchPatterns.splice(headBranchIdx, 1)
|
|
325
|
-
} else {
|
|
326
|
-
branchPatterns[headBranchIdx] = currentBranch
|
|
327
|
-
}
|
|
328
|
-
} else {
|
|
329
|
-
if (!isBare) {
|
|
330
|
-
let head = noWorktree
|
|
331
|
-
if (worktreePatterns[0] === '.') {
|
|
332
|
-
worktreePatterns = worktreePatterns.slice(1)
|
|
333
|
-
head = repo.dir
|
|
334
|
-
}
|
|
335
|
-
// NOTE current branch is undefined when HEAD is detached
|
|
336
|
-
refs.set('HEAD', { shortname: 'HEAD', fullname: 'HEAD', type: 'branch', detached: true, head })
|
|
337
|
-
}
|
|
321
|
+
// NOTE ignore if current branch is already in list
|
|
322
|
+
if (~branchPatterns.indexOf(currentBranch)) {
|
|
338
323
|
branchPatterns.splice(headBranchIdx, 1)
|
|
324
|
+
} else {
|
|
325
|
+
branchPatterns[headBranchIdx] = currentBranch
|
|
326
|
+
}
|
|
327
|
+
} else if (isBare) {
|
|
328
|
+
branchPatterns.splice(headBranchIdx, 1)
|
|
329
|
+
} else {
|
|
330
|
+
let head = noWorktree
|
|
331
|
+
if (worktreePatterns[0] === '.') {
|
|
332
|
+
worktreePatterns = worktreePatterns.slice(1)
|
|
333
|
+
head = repo.dir
|
|
339
334
|
}
|
|
335
|
+
// NOTE current branch is undefined when HEAD is detached
|
|
336
|
+
refs.set('HEAD', { shortname: 'HEAD', fullname: 'HEAD', type: 'branch', detached: true, head })
|
|
337
|
+
branchPatterns.splice(headBranchIdx, 1)
|
|
340
338
|
}
|
|
341
|
-
} else {
|
|
342
|
-
return [...refs.values()]
|
|
343
339
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
340
|
+
} else {
|
|
341
|
+
return [...refs.values()]
|
|
342
|
+
}
|
|
343
|
+
// NOTE isomorphic-git includes HEAD in list of remote branches (see https://isomorphic-git.org/docs/listBranches)
|
|
344
|
+
const remoteBranches = (await git.listBranches(Object.assign({ remote }, repo))).filter((it) => it !== 'HEAD')
|
|
345
|
+
if (remoteBranches.length) {
|
|
346
|
+
for (const shortname of filterRefs(remoteBranches, branchPatterns, patternCache)) {
|
|
347
|
+
const fullname = 'remotes/' + remote + '/' + shortname
|
|
348
|
+
refs.set(shortname, { shortname, fullname, type: 'branch', remote, head: noWorktree })
|
|
351
349
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}
|
|
350
|
+
}
|
|
351
|
+
// NOTE only consider local branches if repo has a worktree or there are no remote tracking branches
|
|
352
|
+
if (!isBare) {
|
|
353
|
+
const localBranches = await git.listBranches(repo)
|
|
354
|
+
if (localBranches.length) {
|
|
355
|
+
const worktrees = await findWorktrees(repo, worktreePatterns)
|
|
356
|
+
for (const shortname of filterRefs(localBranches, branchPatterns, patternCache)) {
|
|
357
|
+
const head = worktrees.get(shortname) || noWorktree
|
|
358
|
+
refs.set(shortname, { shortname, fullname: 'heads/' + shortname, type: 'branch', head })
|
|
361
359
|
}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
}
|
|
360
|
+
}
|
|
361
|
+
} else if (!remoteBranches.length) {
|
|
362
|
+
const localBranches = await git.listBranches(repo)
|
|
363
|
+
if (localBranches.length) {
|
|
364
|
+
for (const shortname of filterRefs(localBranches, branchPatterns, patternCache)) {
|
|
365
|
+
refs.set(shortname, { shortname, fullname: 'heads/' + shortname, type: 'branch', head: noWorktree })
|
|
368
366
|
}
|
|
369
367
|
}
|
|
370
368
|
}
|
|
@@ -430,35 +428,19 @@ function collectFilesFromStartPath (startPath, repo, authStatus, ref, worktreePa
|
|
|
430
428
|
return componentVersionBucket
|
|
431
429
|
})
|
|
432
430
|
.catch((err) => {
|
|
431
|
+
const msg = err.message
|
|
433
432
|
const refInfo = `ref: ${ref.fullname.replace(HEADS_DIR_RX, '')}${worktreePath ? ' <worktree>' : ''}`
|
|
434
|
-
const pathInfo = !startPath ||
|
|
435
|
-
throw Object.assign(err, { message:
|
|
433
|
+
const pathInfo = !startPath || msg.startsWith('the start path ') ? '' : ' | path: ' + startPath
|
|
434
|
+
throw Object.assign(err, { message: msg.replace(/$/m, ` in ${repo.url || repo.dir} (${refInfo}${pathInfo})`) })
|
|
436
435
|
})
|
|
437
436
|
}
|
|
438
437
|
|
|
439
438
|
function readFilesFromWorktree (worktreePath, startPath) {
|
|
440
|
-
const cwd = ospath.join(worktreePath, startPath)
|
|
439
|
+
const cwd = ospath.join(worktreePath, startPath, '.') // . shaves off trailing slash
|
|
441
440
|
return fsp.stat(cwd).then(
|
|
442
|
-
(
|
|
443
|
-
if (!
|
|
444
|
-
return
|
|
445
|
-
vfs
|
|
446
|
-
.src(CONTENT_SRC_GLOB, Object.assign({ cwd }, CONTENT_SRC_OPTS))
|
|
447
|
-
.on('error', (err) => {
|
|
448
|
-
if (err.code === 'ENOENT' && err.syscall === 'stat') {
|
|
449
|
-
try {
|
|
450
|
-
if (fs.lstatSync(err.path).isSymbolicLink()) {
|
|
451
|
-
err.message = `Broken symbolic link detected at ${ospath.relative(cwd, err.path)}`
|
|
452
|
-
}
|
|
453
|
-
} catch {}
|
|
454
|
-
} else if (err.code === 'ELOOP') {
|
|
455
|
-
err.message = `Symbolic link cycle detected at ${ospath.relative(cwd, err.path)}`
|
|
456
|
-
}
|
|
457
|
-
reject(err)
|
|
458
|
-
})
|
|
459
|
-
.pipe(relativizeFiles())
|
|
460
|
-
.pipe(collectDataFromStream(resolve))
|
|
461
|
-
)
|
|
441
|
+
(startPathStat) => {
|
|
442
|
+
if (!startPathStat.isDirectory()) throw new Error(`the start path '${startPath}' is not a directory`)
|
|
443
|
+
return srcFs(cwd)
|
|
462
444
|
},
|
|
463
445
|
() => {
|
|
464
446
|
throw new Error(`the start path '${startPath}' does not exist`)
|
|
@@ -466,40 +448,43 @@ function readFilesFromWorktree (worktreePath, startPath) {
|
|
|
466
448
|
)
|
|
467
449
|
}
|
|
468
450
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
451
|
+
function srcFs (cwd) {
|
|
452
|
+
const relpathStart = cwd.length + 1
|
|
453
|
+
return new Promise((resolve, reject, cache = Object.create(null), files = []) =>
|
|
454
|
+
pipeline(
|
|
455
|
+
globStream(CONTENT_SRC_GLOB, Object.assign({ cache, cwd }, CONTENT_SRC_OPTS)),
|
|
456
|
+
forEach(({ path: abspathPosix }, _, done) => {
|
|
457
|
+
if (Array.isArray(cache[abspathPosix])) return done() // detects some directories, but not all
|
|
458
|
+
const abspath = posixify ? ospath.normalize(abspathPosix) : abspathPosix
|
|
459
|
+
const relpath = abspath.substr(relpathStart)
|
|
460
|
+
symlinkAwareStat(abspath).then(
|
|
461
|
+
(stat) => {
|
|
462
|
+
if (stat.isDirectory()) return done() // detects remaining directories
|
|
463
|
+
fsp.readFile(abspath).then(
|
|
464
|
+
(contents) => {
|
|
465
|
+
files.push(new File({ path: posixify ? posixify(relpath) : relpath, contents, stat, src: { abspath } }))
|
|
466
|
+
done()
|
|
467
|
+
},
|
|
468
|
+
(readErr) => {
|
|
469
|
+
done(Object.assign(readErr, { message: readErr.message.replace(`'${abspath}'`, relpath) }))
|
|
470
|
+
}
|
|
471
|
+
)
|
|
472
|
+
},
|
|
473
|
+
(statErr) => {
|
|
474
|
+
if (statErr.symlink) {
|
|
475
|
+
statErr.message =
|
|
476
|
+
statErr.code === 'ELOOP'
|
|
477
|
+
? `Symbolic link cycle detected at ${relpath}`
|
|
478
|
+
: `Broken symbolic link detected at ${relpath}`
|
|
479
|
+
} else {
|
|
480
|
+
statErr.message = statErr.message.replace(`'${abspath}'`, relpath)
|
|
481
|
+
}
|
|
482
|
+
done(statErr)
|
|
483
|
+
}
|
|
484
|
+
)
|
|
485
|
+
}),
|
|
486
|
+
(err) => (err ? reject(err) : resolve(files))
|
|
487
|
+
)
|
|
503
488
|
)
|
|
504
489
|
}
|
|
505
490
|
|
|
@@ -668,7 +653,7 @@ function loadComponentDescriptor (files, ref, version) {
|
|
|
668
653
|
files.splice(descriptorFileIdx, 1)
|
|
669
654
|
let data
|
|
670
655
|
try {
|
|
671
|
-
data = yaml.load(descriptorFile.contents.toString())
|
|
656
|
+
data = yaml.load(descriptorFile.contents.toString(), { schema: yaml.CORE_SCHEMA })
|
|
672
657
|
} catch (err) {
|
|
673
658
|
throw Object.assign(err, { message: `${COMPONENT_DESC_FILENAME} has invalid syntax; ${err.message}` })
|
|
674
659
|
}
|
|
@@ -680,7 +665,8 @@ function loadComponentDescriptor (files, ref, version) {
|
|
|
680
665
|
if ('version' in data) version = data.version
|
|
681
666
|
if (!version) {
|
|
682
667
|
if (version === undefined) throw new Error(`${COMPONENT_DESC_FILENAME} is missing a version`)
|
|
683
|
-
version
|
|
668
|
+
if (version === false) throw new Error(`${COMPONENT_DESC_FILENAME} has an invalid version`)
|
|
669
|
+
version = '' + (typeof version === 'number' ? version : '')
|
|
684
670
|
} else if (version === true) {
|
|
685
671
|
version = ref.shortname.replace(PATH_SEPARATOR_RX, '-')
|
|
686
672
|
} else if (version.constructor === Object) {
|
|
@@ -690,7 +676,7 @@ function loadComponentDescriptor (files, ref, version) {
|
|
|
690
676
|
matched = version[refname]
|
|
691
677
|
} else if (
|
|
692
678
|
!Object.entries(version).some(([pattern, replacement]) => {
|
|
693
|
-
const result = refname.replace(
|
|
679
|
+
const result = refname.replace(makeMatcherRx(pattern, VERSION_MATCHER_OPTS), '\0' + replacement)
|
|
694
680
|
if (result === refname) return false
|
|
695
681
|
matched = result.substr(1)
|
|
696
682
|
return true
|
|
@@ -702,7 +688,7 @@ function loadComponentDescriptor (files, ref, version) {
|
|
|
702
688
|
throw new Error(`version in ${COMPONENT_DESC_FILENAME} cannot have path segments: ${matched}`)
|
|
703
689
|
}
|
|
704
690
|
version = matched.replace(PATH_SEPARATOR_RX, '-')
|
|
705
|
-
} else if ((version =
|
|
691
|
+
} else if ((version = '' + version) === '.' || version === '..' || ~version.indexOf('/')) {
|
|
706
692
|
throw new Error(`version in ${COMPONENT_DESC_FILENAME} cannot have path segments: ${version}`)
|
|
707
693
|
}
|
|
708
694
|
data.version = version
|
|
@@ -718,7 +704,8 @@ function computeOrigin (url, authStatus, gitdir, ref, startPath, worktreePath =
|
|
|
718
704
|
} else {
|
|
719
705
|
if (worktreePath) {
|
|
720
706
|
origin.fileUriPattern =
|
|
721
|
-
(posixify ? 'file:///' + posixify(worktreePath) : 'file://' + worktreePath) +
|
|
707
|
+
(posixify ? 'file:///' + posixify(worktreePath) : 'file://' + worktreePath) +
|
|
708
|
+
(startPath ? '/' + startPath + '/%s' : '/%s')
|
|
722
709
|
} else {
|
|
723
710
|
origin.refhash = refhash
|
|
724
711
|
}
|
|
@@ -906,7 +893,8 @@ function resolveRemoteUrl (repo, remoteName) {
|
|
|
906
893
|
return 'https://' + url.substr(url.indexOf('@') + 1 || 6).replace(URL_PORT_CLEANER_RX, '$1')
|
|
907
894
|
}
|
|
908
895
|
}
|
|
909
|
-
|
|
896
|
+
url = posixify ? 'file:///' + posixify(repo.dir) : 'file://' + repo.dir
|
|
897
|
+
return ~url.indexOf(' ') ? url.replace(SPACE_RX, '%20') : url
|
|
910
898
|
})
|
|
911
899
|
}
|
|
912
900
|
|
|
@@ -920,6 +908,15 @@ function isDirectory (url) {
|
|
|
920
908
|
return fsp.stat(url).then((stat) => stat.isDirectory(), invariably.false)
|
|
921
909
|
}
|
|
922
910
|
|
|
911
|
+
function symlinkAwareStat (path_) {
|
|
912
|
+
return fsp.lstat(path_).then((lstat) => {
|
|
913
|
+
if (!lstat.isSymbolicLink()) return lstat
|
|
914
|
+
return fsp.stat(path_).catch((statErr) => {
|
|
915
|
+
throw Object.assign(statErr, { symlink: true })
|
|
916
|
+
})
|
|
917
|
+
})
|
|
918
|
+
}
|
|
919
|
+
|
|
923
920
|
function tagsSpecified (sources) {
|
|
924
921
|
return sources.some(({ tags }) => tags && (Array.isArray(tags) ? tags.length : true))
|
|
925
922
|
}
|
|
@@ -1019,7 +1016,7 @@ function findWorktrees (repo, patterns) {
|
|
|
1019
1016
|
return (patterns.length
|
|
1020
1017
|
? fsp
|
|
1021
1018
|
.readdir((worktreesDir = ospath.join(repo.dir, '.git', 'worktrees')))
|
|
1022
|
-
.then((worktreeNames) => filterRefs(worktreeNames,
|
|
1019
|
+
.then((worktreeNames) => filterRefs(worktreeNames, patterns, patternCache), invariably.emptyArray)
|
|
1023
1020
|
.then((worktreeNames) =>
|
|
1024
1021
|
worktreeNames.length
|
|
1025
1022
|
? Promise.all(
|
package/lib/constants.js
CHANGED
|
@@ -4,22 +4,11 @@ module.exports = Object.freeze({
|
|
|
4
4
|
COMPONENT_DESC_FILENAME: 'antora.yml',
|
|
5
5
|
CONTENT_CACHE_FOLDER: 'content',
|
|
6
6
|
CONTENT_SRC_GLOB: '**/*[!~]',
|
|
7
|
-
CONTENT_SRC_OPTS: { follow: true, nomount: true, nosort: true, nounique: true,
|
|
7
|
+
CONTENT_SRC_OPTS: { follow: true, nomount: true, nosort: true, nounique: true, strict: false, uniqueBy: (m) => m },
|
|
8
8
|
FILE_MODES: { 100644: 0o100666 & ~process.umask(), 100755: 0o100777 & ~process.umask() },
|
|
9
9
|
GIT_CORE: 'antora',
|
|
10
10
|
GIT_OPERATION_LABEL_LENGTH: 8,
|
|
11
11
|
GIT_PROGRESS_PHASES: ['Counting objects', 'Compressing objects', 'Receiving objects', 'Resolving deltas'],
|
|
12
|
-
PICOMATCH_VERSION_OPTS: {
|
|
13
|
-
bash: true,
|
|
14
|
-
dot: true,
|
|
15
|
-
fastpaths: false,
|
|
16
|
-
nobracket: true,
|
|
17
|
-
noglobstar: true,
|
|
18
|
-
nonegate: true,
|
|
19
|
-
noquantifiers: true,
|
|
20
|
-
regex: false,
|
|
21
|
-
strictSlashes: true,
|
|
22
|
-
},
|
|
23
12
|
REF_PATTERN_CACHE_KEY: Symbol('RefPatternCache'),
|
|
24
13
|
SYMLINK_FILE_MODE: '120000',
|
|
25
14
|
VALID_STATE_FILENAME: 'valid',
|
package/lib/filter-refs.js
CHANGED
|
@@ -1,49 +1,31 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const {
|
|
4
|
-
const { makeRe: makePicomatchRx } = require('picomatch')
|
|
5
|
-
|
|
6
|
-
function getPicomatchOpts (cache) {
|
|
7
|
-
return {
|
|
8
|
-
bash: true,
|
|
9
|
-
dot: true,
|
|
10
|
-
expandRange: (begin, end, step, opts) => {
|
|
11
|
-
const pattern = opts ? `{${begin}..${end}..${step}}` : `{${begin}..${end}}`
|
|
12
|
-
return cache.braces.get(pattern) || cache.braces.set(pattern, bracesToGroup(pattern)).get(pattern)
|
|
13
|
-
},
|
|
14
|
-
fastpaths: false,
|
|
15
|
-
nobracket: true,
|
|
16
|
-
noglobstar: true,
|
|
17
|
-
noquantifiers: true,
|
|
18
|
-
regex: false,
|
|
19
|
-
strictSlashes: true,
|
|
20
|
-
}
|
|
21
|
-
}
|
|
3
|
+
const { makeMatcherRx, refMatcherOpts: getMatcherOpts, MATCH_ALL_RX } = require('./matcher')
|
|
22
4
|
|
|
23
5
|
function compileRx (pattern, opts) {
|
|
24
|
-
if (pattern === '*' || pattern === '**') return
|
|
6
|
+
if (pattern === '*' || pattern === '**') return MATCH_ALL_RX
|
|
25
7
|
return pattern.charAt() === '!' // do our own negate
|
|
26
|
-
? Object.defineProperty(
|
|
27
|
-
:
|
|
8
|
+
? Object.defineProperty(makeMatcherRx(pattern.substr(1), opts), 'negated', { value: true })
|
|
9
|
+
: makeMatcherRx(pattern, opts)
|
|
28
10
|
}
|
|
29
11
|
|
|
30
|
-
function createMatcher (patterns, cache) {
|
|
31
|
-
let opts
|
|
12
|
+
function createMatcher (patterns, cache, opts) {
|
|
32
13
|
const rxs = patterns.map(
|
|
33
14
|
(pattern) =>
|
|
34
|
-
cache.get(pattern) ||
|
|
35
|
-
cache.set(pattern, compileRx(pattern, opts || (opts = getPicomatchOpts(cache)))).get(pattern)
|
|
15
|
+
cache.get(pattern) || cache.set(pattern, compileRx(pattern, opts || (opts = getMatcherOpts(cache)))).get(pattern)
|
|
36
16
|
)
|
|
17
|
+
if (rxs[0].negated) rxs.unshift(MATCH_ALL_RX)
|
|
37
18
|
return (candidate) => {
|
|
38
|
-
let first = true
|
|
39
19
|
let matched
|
|
40
20
|
for (const rx of rxs) {
|
|
21
|
+
let voteIfMatched = true
|
|
41
22
|
if (matched) {
|
|
42
|
-
if (rx.negated
|
|
43
|
-
|
|
44
|
-
|
|
23
|
+
if (!rx.negated) continue
|
|
24
|
+
voteIfMatched = false
|
|
25
|
+
} else if (rx.negated) {
|
|
26
|
+
continue
|
|
45
27
|
}
|
|
46
|
-
|
|
28
|
+
if (rx.test(candidate)) matched = voteIfMatched
|
|
47
29
|
}
|
|
48
30
|
return matched
|
|
49
31
|
}
|
|
@@ -2,17 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
const { homedir } = require('os')
|
|
4
4
|
const expandPath = require('@antora/expand-path-helper')
|
|
5
|
-
const invariably = { void: () => undefined }
|
|
6
5
|
const { promises: fsp } = require('fs')
|
|
6
|
+
const invariably = require('./invariably')
|
|
7
7
|
const ospath = require('path')
|
|
8
8
|
|
|
9
9
|
class GitCredentialManagerStore {
|
|
10
10
|
configure ({ config, startDir }) {
|
|
11
11
|
this.entries = undefined
|
|
12
|
+
this.path = undefined
|
|
12
13
|
this.urls = {}
|
|
13
|
-
if ((this.contents = (config = config || {}).contents)
|
|
14
|
-
this.path = undefined
|
|
15
|
-
} else {
|
|
14
|
+
if (!(this.contents = (config = config || {}).contents) && config.path) {
|
|
16
15
|
this.path = expandPath(config.path, { dot: startDir })
|
|
17
16
|
}
|
|
18
17
|
return this
|
|
@@ -35,14 +34,13 @@ class GitCredentialManagerStore {
|
|
|
35
34
|
'git',
|
|
36
35
|
'credentials'
|
|
37
36
|
)
|
|
38
|
-
contentsPromise = fsp
|
|
39
|
-
.
|
|
40
|
-
|
|
41
|
-
.catch(() =>
|
|
37
|
+
contentsPromise = fsp.access(homeGitCredentialsPath).then(
|
|
38
|
+
() => fsp.readFile(homeGitCredentialsPath, 'utf8'),
|
|
39
|
+
() =>
|
|
42
40
|
fsp
|
|
43
41
|
.access(xdgConfigGitCredentialsPath)
|
|
44
42
|
.then(() => fsp.readFile(xdgConfigGitCredentialsPath, 'utf8'), invariably.void)
|
|
45
|
-
|
|
43
|
+
)
|
|
46
44
|
}
|
|
47
45
|
contentsPromise.then((contents) => {
|
|
48
46
|
if (contents) {
|
package/lib/matcher.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { compile: bracesToGroup, expand: expandBraces } = require('braces')
|
|
4
|
+
const { makeRe: makeMatcherRx } = require('picomatch')
|
|
5
|
+
|
|
6
|
+
const BASE_OPTS = {
|
|
7
|
+
bash: true,
|
|
8
|
+
dot: true,
|
|
9
|
+
expandRange: (begin, end, step, opts) => bracesToGroup(opts ? `{${begin}..${end}..${step}}` : `{${begin}..${end}}`),
|
|
10
|
+
fastpaths: false,
|
|
11
|
+
nobracket: true,
|
|
12
|
+
noglobstar: true,
|
|
13
|
+
nonegate: true,
|
|
14
|
+
noquantifiers: true,
|
|
15
|
+
regex: false,
|
|
16
|
+
strictSlashes: true,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
MATCH_ALL_RX: { test: () => true },
|
|
21
|
+
expandBraces,
|
|
22
|
+
makeMatcherRx,
|
|
23
|
+
pathMatcherOpts: Object.assign({}, BASE_OPTS, { dot: false }),
|
|
24
|
+
refMatcherOpts: (cache) =>
|
|
25
|
+
Object.assign({}, BASE_OPTS, {
|
|
26
|
+
expandRange: (begin, end, step, opts) => {
|
|
27
|
+
const pattern = opts ? `{${begin}..${end}..${step}}` : `{${begin}..${end}}`
|
|
28
|
+
return cache.braces.get(pattern) || cache.braces.set(pattern, bracesToGroup(pattern)).get(pattern)
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
versionMatcherOpts: Object.assign({}, BASE_OPTS, { nonegate: false }),
|
|
32
|
+
}
|
|
@@ -1,32 +1,20 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { expand: expandBraces, compile: bracesToGroup } = require('braces')
|
|
4
3
|
const flattenDeep = require('./flatten-deep')
|
|
5
4
|
const { promises: fsp } = require('fs')
|
|
6
5
|
const git = require('./git')
|
|
7
|
-
const invariably =
|
|
8
|
-
const {
|
|
6
|
+
const invariably = require('./invariably')
|
|
7
|
+
const { expandBraces, makeMatcherRx, pathMatcherOpts: MATCHER_OPTS } = require('./matcher')
|
|
9
8
|
|
|
10
9
|
const NON_GLOB_SPECIAL_CHARS_RX = /[.+?^${}()|[\]\\]/g
|
|
11
10
|
const RX_MAGIC_DETECTOR = /[*{(]/
|
|
12
|
-
const PICOMATCH_OPTS = {
|
|
13
|
-
bash: true,
|
|
14
|
-
expandRange: (begin, end, step, opts) => bracesToGroup(opts ? `{${begin}..${end}..${step}}` : `{${begin}..${end}}`),
|
|
15
|
-
fastpaths: false,
|
|
16
|
-
nobracket: true,
|
|
17
|
-
noglobstar: true,
|
|
18
|
-
nonegate: true,
|
|
19
|
-
noquantifiers: true,
|
|
20
|
-
regex: false,
|
|
21
|
-
strictSlashes: true,
|
|
22
|
-
}
|
|
23
11
|
|
|
24
12
|
function resolvePathGlobs (base, patterns, listDirents, retrievePath, tree = { path: '' }) {
|
|
25
13
|
return patterns.reduce((paths, pattern) => {
|
|
26
14
|
if (pattern.charAt() === '!') {
|
|
27
15
|
return paths.then((resolvedPaths) => {
|
|
28
16
|
if (resolvedPaths.length) {
|
|
29
|
-
const rx =
|
|
17
|
+
const rx = makeMatcherRx(pattern.substr(1), MATCHER_OPTS)
|
|
30
18
|
return resolvedPaths.filter((it) => !rx.test(it))
|
|
31
19
|
} else {
|
|
32
20
|
return resolvedPaths
|
|
@@ -49,10 +37,10 @@ async function glob (base, patternSegments, listDirents, retrievePath, { oid, pa
|
|
|
49
37
|
if (patternSegment === '*') {
|
|
50
38
|
isMatch = (it) => it.charAt() !== '.'
|
|
51
39
|
} else if (~patternSegment.indexOf('(')) {
|
|
52
|
-
isMatch = (isMatch =
|
|
40
|
+
isMatch = (isMatch = makeMatcherRx(patternSegment, MATCHER_OPTS)).test.bind(isMatch)
|
|
53
41
|
} else if (~patternSegment.indexOf('{')) {
|
|
54
42
|
if (globbed) {
|
|
55
|
-
isMatch = (isMatch =
|
|
43
|
+
isMatch = (isMatch = makeMatcherRx(patternSegment, MATCHER_OPTS)).test.bind(isMatch)
|
|
56
44
|
} else if (~patternSegment.indexOf('*')) {
|
|
57
45
|
const [wildPatterns, literals] = expandBraces(patternSegment).reduce(
|
|
58
46
|
([wild, literal], it) => (~it.indexOf('*') ? [[...wild, it], literal] : [wild, [...literal, it]]),
|
|
@@ -64,7 +52,7 @@ async function glob (base, patternSegments, listDirents, retrievePath, { oid, pa
|
|
|
64
52
|
return expandBraces(patternSegment).map((it) => joinPath(path, it))
|
|
65
53
|
}
|
|
66
54
|
} else {
|
|
67
|
-
isMatch = (isMatch =
|
|
55
|
+
isMatch = (isMatch = makeSingleMatcherRx(patternSegment)).test.bind(isMatch)
|
|
68
56
|
}
|
|
69
57
|
let dirents = await listDirents(base, oid || path)
|
|
70
58
|
if (explicit) dirents = dirents.filter((dirent) => !explicit.has(dirent.name))
|
|
@@ -134,7 +122,7 @@ function makeAlternationMatcherRx (patterns) {
|
|
|
134
122
|
return new RegExp('^(?:' + patterns.map(patternToRx).join('|') + ')$')
|
|
135
123
|
}
|
|
136
124
|
|
|
137
|
-
function
|
|
125
|
+
function makeSingleMatcherRx (pattern) {
|
|
138
126
|
return new RegExp('^' + patternToRx(pattern) + '$')
|
|
139
127
|
}
|
|
140
128
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antora/content-aggregator",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.6",
|
|
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)",
|
|
@@ -16,12 +16,16 @@
|
|
|
16
16
|
"url": "https://gitlab.com/antora/antora/issues"
|
|
17
17
|
},
|
|
18
18
|
"main": "lib/index.js",
|
|
19
|
+
"scripts": {
|
|
20
|
+
"test": "_mocha"
|
|
21
|
+
},
|
|
19
22
|
"dependencies": {
|
|
20
23
|
"@antora/expand-path-helper": "~2.0",
|
|
21
24
|
"@antora/user-require-helper": "~2.0",
|
|
22
25
|
"braces": "~3.0",
|
|
23
26
|
"cache-directory": "~2.0",
|
|
24
27
|
"camelcase-keys": "~7.0",
|
|
28
|
+
"glob-stream": "~7.0",
|
|
25
29
|
"hpagent": "~0.1.0",
|
|
26
30
|
"isomorphic-git": "~1.10",
|
|
27
31
|
"js-yaml": "~4.1",
|
|
@@ -30,8 +34,7 @@
|
|
|
30
34
|
"progress": "~2.0",
|
|
31
35
|
"should-proxy": "~1.0",
|
|
32
36
|
"simple-get": "~4.0",
|
|
33
|
-
"vinyl": "~2.2"
|
|
34
|
-
"vinyl-fs": "~3.0"
|
|
37
|
+
"vinyl": "~2.2"
|
|
35
38
|
},
|
|
36
39
|
"engines": {
|
|
37
40
|
"node": ">=12.21.0"
|
|
@@ -49,5 +52,5 @@
|
|
|
49
52
|
"static site",
|
|
50
53
|
"web publishing"
|
|
51
54
|
],
|
|
52
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "f9f747965f599442562f59206d870b7e38864806"
|
|
53
56
|
}
|