@antora/content-aggregator 3.0.0-beta.1 → 3.0.0-beta.5
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 +159 -165
- 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 +4 -4
- package/lib/promise-all-settled-polyfill.js +0 -11
package/lib/aggregate-content.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
if (!Promise.allSettled) require('./promise-all-settled-polyfill')
|
|
4
|
-
|
|
5
3
|
const camelCaseKeys = require('camelcase-keys')
|
|
6
4
|
const { createHash } = require('crypto')
|
|
7
5
|
const createHttpPlugin = require('./git-plugin-http')
|
|
@@ -17,17 +15,17 @@ const getCacheDir = require('cache-directory')
|
|
|
17
15
|
const GitCredentialManagerStore = require('./git-credential-manager-store')
|
|
18
16
|
const git = require('./git')
|
|
19
17
|
const { NotFoundError, ObjectTypeError, UnknownTransportError, UrlParseError } = git.Errors
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
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
|
|
23
22
|
const ospath = require('path')
|
|
24
23
|
const { posix: path } = ospath
|
|
25
24
|
const posixify = ospath.sep === '\\' ? (p) => p.replace(/\\/g, '/') : undefined
|
|
26
25
|
const { fs: resolvePathGlobsFs, git: resolvePathGlobsGit } = require('./resolve-path-globs')
|
|
27
|
-
const {
|
|
28
|
-
const
|
|
26
|
+
const { pipeline, Writable } = require('stream')
|
|
27
|
+
const forEach = (write) => new Writable({ objectMode: true, write })
|
|
29
28
|
const userRequire = require('@antora/user-require-helper')
|
|
30
|
-
const vfs = require('vinyl-fs')
|
|
31
29
|
const yaml = require('js-yaml')
|
|
32
30
|
|
|
33
31
|
const {
|
|
@@ -39,12 +37,10 @@ const {
|
|
|
39
37
|
GIT_CORE,
|
|
40
38
|
GIT_OPERATION_LABEL_LENGTH,
|
|
41
39
|
GIT_PROGRESS_PHASES,
|
|
42
|
-
PICOMATCH_VERSION_OPTS,
|
|
43
40
|
REF_PATTERN_CACHE_KEY,
|
|
44
41
|
SYMLINK_FILE_MODE,
|
|
45
42
|
VALID_STATE_FILENAME,
|
|
46
43
|
} = require('./constants')
|
|
47
|
-
|
|
48
44
|
const ANY_SEPARATOR_RX = /[:/]/
|
|
49
45
|
const CSV_RX = /\s*,\s*/
|
|
50
46
|
const VENTILATED_CSV_RX = /\s*,\s+/
|
|
@@ -124,14 +120,14 @@ async function collectFiles (sourcesByUrl, loadOpts, concurrency) {
|
|
|
124
120
|
})
|
|
125
121
|
),
|
|
126
122
|
])
|
|
127
|
-
let
|
|
123
|
+
let rejection, started
|
|
128
124
|
const startedContinuations = []
|
|
129
125
|
const recordRejection = (err) => {
|
|
130
|
-
|
|
126
|
+
rejection = err
|
|
131
127
|
}
|
|
132
128
|
const runTask = (primary, continuation, idx) =>
|
|
133
129
|
primary().then((value) => {
|
|
134
|
-
if (!
|
|
130
|
+
if (!rejection) startedContinuations[idx] = continuation(value).catch(recordRejection)
|
|
135
131
|
}, recordRejection)
|
|
136
132
|
if (tasks.length > concurrency) {
|
|
137
133
|
started = []
|
|
@@ -142,17 +138,16 @@ async function collectFiles (sourcesByUrl, loadOpts, concurrency) {
|
|
|
142
138
|
)
|
|
143
139
|
started.push(current)
|
|
144
140
|
if (pending.push(current) < concurrency) continue
|
|
145
|
-
|
|
146
|
-
break
|
|
141
|
+
await Promise.race(pending)
|
|
142
|
+
if (rejection) break
|
|
147
143
|
}
|
|
148
144
|
} else {
|
|
149
145
|
started = tasks.map(([primary, continuation], idx) => runTask(primary, continuation, idx))
|
|
150
146
|
}
|
|
151
|
-
return Promise.
|
|
152
|
-
Promise.
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return continuationOutcomes.map(({ value }) => value)
|
|
147
|
+
return Promise.all(started).then(() =>
|
|
148
|
+
Promise.all(startedContinuations).then((result) => {
|
|
149
|
+
if (rejection) throw rejection
|
|
150
|
+
return result
|
|
156
151
|
})
|
|
157
152
|
)
|
|
158
153
|
}
|
|
@@ -232,9 +227,8 @@ async function loadRepository (url, opts) {
|
|
|
232
227
|
try {
|
|
233
228
|
await git.resolveRef(Object.assign({ ref: 'HEAD', depth: 1 }, repo))
|
|
234
229
|
} catch {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
)
|
|
230
|
+
const msg = `Local content source must be a git repository: ${dir}${url !== dir ? ' (url: ' + url + ')' : ''}`
|
|
231
|
+
throw new Error(msg)
|
|
238
232
|
}
|
|
239
233
|
} else {
|
|
240
234
|
throw new Error(`Local content source does not exist: ${dir}${url !== dir ? ' (url: ' + url + ')' : ''}`)
|
|
@@ -275,99 +269,100 @@ async function selectReferences (source, repo, remote) {
|
|
|
275
269
|
const patternCache = repo.cache[REF_PATTERN_CACHE_KEY]
|
|
276
270
|
const noWorktree = repo.url ? undefined : null
|
|
277
271
|
const refs = new Map()
|
|
278
|
-
if (
|
|
279
|
-
tagPatterns
|
|
272
|
+
if (
|
|
273
|
+
tagPatterns &&
|
|
274
|
+
(tagPatterns = Array.isArray(tagPatterns)
|
|
280
275
|
? tagPatterns.map((pattern) => String(pattern))
|
|
281
|
-
: splitRefPatterns(String(tagPatterns))
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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)) {
|
|
285
281
|
// NOTE tags are stored using symbol keys to distinguish them from branches
|
|
286
282
|
refs.set(Symbol(shortname), { shortname, fullname: 'tags/' + shortname, type: 'tag', head: noWorktree })
|
|
287
283
|
}
|
|
288
284
|
}
|
|
289
285
|
}
|
|
290
|
-
if (branchPatterns)
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
}
|
|
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))
|
|
301
296
|
}
|
|
302
|
-
|
|
303
|
-
|
|
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('.'))) {
|
|
304
319
|
const currentBranch = await getCurrentBranchName(repo, remote)
|
|
305
320
|
if (currentBranch) {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
if (!isBare) {
|
|
309
|
-
// NOTE current branch is undefined when HEAD is detached
|
|
310
|
-
const head = worktreePatterns[0] === '.' ? repo.dir : noWorktree
|
|
311
|
-
refs.set('HEAD', { shortname: 'HEAD', fullname: 'HEAD', type: 'branch', detached: true, head })
|
|
312
|
-
}
|
|
313
|
-
return [...refs.values()]
|
|
314
|
-
}
|
|
315
|
-
} else if (
|
|
316
|
-
(branchPatterns = Array.isArray(branchPatterns)
|
|
317
|
-
? branchPatterns.map((pattern) => String(pattern))
|
|
318
|
-
: splitRefPatterns(branchPatternsString)).length
|
|
319
|
-
) {
|
|
320
|
-
let headBranchIdx
|
|
321
|
-
// NOTE we can assume at least two entries if HEAD or . are present
|
|
322
|
-
if (~(headBranchIdx = branchPatterns.indexOf('HEAD')) || ~(headBranchIdx = branchPatterns.indexOf('.'))) {
|
|
323
|
-
const currentBranch = await getCurrentBranchName(repo, remote)
|
|
324
|
-
if (currentBranch) {
|
|
325
|
-
// NOTE ignore if current branch is already in list
|
|
326
|
-
if (~branchPatterns.indexOf(currentBranch)) {
|
|
327
|
-
branchPatterns.splice(headBranchIdx, 1)
|
|
328
|
-
} else {
|
|
329
|
-
branchPatterns[headBranchIdx] = currentBranch
|
|
330
|
-
}
|
|
331
|
-
} else {
|
|
332
|
-
if (!isBare) {
|
|
333
|
-
let head = noWorktree
|
|
334
|
-
if (worktreePatterns[0] === '.') {
|
|
335
|
-
worktreePatterns = worktreePatterns.slice(1)
|
|
336
|
-
head = repo.dir
|
|
337
|
-
}
|
|
338
|
-
// NOTE current branch is undefined when HEAD is detached
|
|
339
|
-
refs.set('HEAD', { shortname: 'HEAD', fullname: 'HEAD', type: 'branch', detached: true, head })
|
|
340
|
-
}
|
|
321
|
+
// NOTE ignore if current branch is already in list
|
|
322
|
+
if (~branchPatterns.indexOf(currentBranch)) {
|
|
341
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
|
|
342
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)
|
|
343
338
|
}
|
|
344
|
-
} else {
|
|
345
|
-
return [...refs.values()]
|
|
346
339
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
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 })
|
|
354
349
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
}
|
|
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 })
|
|
364
359
|
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
}
|
|
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 })
|
|
371
366
|
}
|
|
372
367
|
}
|
|
373
368
|
}
|
|
@@ -433,35 +428,19 @@ function collectFilesFromStartPath (startPath, repo, authStatus, ref, worktreePa
|
|
|
433
428
|
return componentVersionBucket
|
|
434
429
|
})
|
|
435
430
|
.catch((err) => {
|
|
431
|
+
const msg = err.message
|
|
436
432
|
const refInfo = `ref: ${ref.fullname.replace(HEADS_DIR_RX, '')}${worktreePath ? ' <worktree>' : ''}`
|
|
437
|
-
const pathInfo = !startPath ||
|
|
438
|
-
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})`) })
|
|
439
435
|
})
|
|
440
436
|
}
|
|
441
437
|
|
|
442
438
|
function readFilesFromWorktree (worktreePath, startPath) {
|
|
443
|
-
const cwd = ospath.join(worktreePath, startPath)
|
|
439
|
+
const cwd = ospath.join(worktreePath, startPath, '.') // . shaves off trailing slash
|
|
444
440
|
return fsp.stat(cwd).then(
|
|
445
|
-
(
|
|
446
|
-
if (!
|
|
447
|
-
return
|
|
448
|
-
vfs
|
|
449
|
-
.src(CONTENT_SRC_GLOB, Object.assign({ cwd }, CONTENT_SRC_OPTS))
|
|
450
|
-
.on('error', (err) => {
|
|
451
|
-
if (err.code === 'ENOENT' && err.syscall === 'stat') {
|
|
452
|
-
try {
|
|
453
|
-
if (fs.lstatSync(err.path).isSymbolicLink()) {
|
|
454
|
-
err.message = `Broken symbolic link detected at ${ospath.relative(cwd, err.path)}`
|
|
455
|
-
}
|
|
456
|
-
} catch {}
|
|
457
|
-
} else if (err.code === 'ELOOP') {
|
|
458
|
-
err.message = `Symbolic link cycle detected at ${ospath.relative(cwd, err.path)}`
|
|
459
|
-
}
|
|
460
|
-
reject(err)
|
|
461
|
-
})
|
|
462
|
-
.pipe(relativizeFiles())
|
|
463
|
-
.pipe(collectDataFromStream(resolve))
|
|
464
|
-
)
|
|
441
|
+
(startPathStat) => {
|
|
442
|
+
if (!startPathStat.isDirectory()) throw new Error(`the start path '${startPath}' is not a directory`)
|
|
443
|
+
return srcFs(cwd)
|
|
465
444
|
},
|
|
466
445
|
() => {
|
|
467
446
|
throw new Error(`the start path '${startPath}' does not exist`)
|
|
@@ -469,40 +448,43 @@ function readFilesFromWorktree (worktreePath, startPath) {
|
|
|
469
448
|
)
|
|
470
449
|
}
|
|
471
450
|
|
|
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
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
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
|
+
)
|
|
506
488
|
)
|
|
507
489
|
}
|
|
508
490
|
|
|
@@ -671,7 +653,7 @@ function loadComponentDescriptor (files, ref, version) {
|
|
|
671
653
|
files.splice(descriptorFileIdx, 1)
|
|
672
654
|
let data
|
|
673
655
|
try {
|
|
674
|
-
data = yaml.load(descriptorFile.contents.toString())
|
|
656
|
+
data = yaml.load(descriptorFile.contents.toString(), { schema: yaml.CORE_SCHEMA })
|
|
675
657
|
} catch (err) {
|
|
676
658
|
throw Object.assign(err, { message: `${COMPONENT_DESC_FILENAME} has invalid syntax; ${err.message}` })
|
|
677
659
|
}
|
|
@@ -683,7 +665,8 @@ function loadComponentDescriptor (files, ref, version) {
|
|
|
683
665
|
if ('version' in data) version = data.version
|
|
684
666
|
if (!version) {
|
|
685
667
|
if (version === undefined) throw new Error(`${COMPONENT_DESC_FILENAME} is missing a version`)
|
|
686
|
-
version
|
|
668
|
+
if (version === false) throw new Error(`${COMPONENT_DESC_FILENAME} has an invalid version`)
|
|
669
|
+
version = '' + (typeof version === 'number' ? version : '')
|
|
687
670
|
} else if (version === true) {
|
|
688
671
|
version = ref.shortname.replace(PATH_SEPARATOR_RX, '-')
|
|
689
672
|
} else if (version.constructor === Object) {
|
|
@@ -693,7 +676,7 @@ function loadComponentDescriptor (files, ref, version) {
|
|
|
693
676
|
matched = version[refname]
|
|
694
677
|
} else if (
|
|
695
678
|
!Object.entries(version).some(([pattern, replacement]) => {
|
|
696
|
-
const result = refname.replace(
|
|
679
|
+
const result = refname.replace(makeMatcherRx(pattern, VERSION_MATCHER_OPTS), '\0' + replacement)
|
|
697
680
|
if (result === refname) return false
|
|
698
681
|
matched = result.substr(1)
|
|
699
682
|
return true
|
|
@@ -705,7 +688,7 @@ function loadComponentDescriptor (files, ref, version) {
|
|
|
705
688
|
throw new Error(`version in ${COMPONENT_DESC_FILENAME} cannot have path segments: ${matched}`)
|
|
706
689
|
}
|
|
707
690
|
version = matched.replace(PATH_SEPARATOR_RX, '-')
|
|
708
|
-
} else if ((version =
|
|
691
|
+
} else if ((version = '' + version) === '.' || version === '..' || ~version.indexOf('/')) {
|
|
709
692
|
throw new Error(`version in ${COMPONENT_DESC_FILENAME} cannot have path segments: ${version}`)
|
|
710
693
|
}
|
|
711
694
|
data.version = version
|
|
@@ -721,7 +704,8 @@ function computeOrigin (url, authStatus, gitdir, ref, startPath, worktreePath =
|
|
|
721
704
|
} else {
|
|
722
705
|
if (worktreePath) {
|
|
723
706
|
origin.fileUriPattern =
|
|
724
|
-
(posixify ? 'file:///' + posixify(worktreePath) : 'file://' + worktreePath) +
|
|
707
|
+
(posixify ? 'file:///' + posixify(worktreePath) : 'file://' + worktreePath) +
|
|
708
|
+
(startPath ? '/' + startPath + '/%s' : '/%s')
|
|
725
709
|
} else {
|
|
726
710
|
origin.refhash = refhash
|
|
727
711
|
}
|
|
@@ -909,7 +893,8 @@ function resolveRemoteUrl (repo, remoteName) {
|
|
|
909
893
|
return 'https://' + url.substr(url.indexOf('@') + 1 || 6).replace(URL_PORT_CLEANER_RX, '$1')
|
|
910
894
|
}
|
|
911
895
|
}
|
|
912
|
-
|
|
896
|
+
url = posixify ? 'file:///' + posixify(repo.dir) : 'file://' + repo.dir
|
|
897
|
+
return ~url.indexOf(' ') ? url.replace(SPACE_RX, '%20') : url
|
|
913
898
|
})
|
|
914
899
|
}
|
|
915
900
|
|
|
@@ -923,6 +908,15 @@ function isDirectory (url) {
|
|
|
923
908
|
return fsp.stat(url).then((stat) => stat.isDirectory(), invariably.false)
|
|
924
909
|
}
|
|
925
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
|
+
|
|
926
920
|
function tagsSpecified (sources) {
|
|
927
921
|
return sources.some(({ tags }) => tags && (Array.isArray(tags) ? tags.length : true))
|
|
928
922
|
}
|
|
@@ -1022,7 +1016,7 @@ function findWorktrees (repo, patterns) {
|
|
|
1022
1016
|
return (patterns.length
|
|
1023
1017
|
? fsp
|
|
1024
1018
|
.readdir((worktreesDir = ospath.join(repo.dir, '.git', 'worktrees')))
|
|
1025
|
-
.then((worktreeNames) => filterRefs(worktreeNames,
|
|
1019
|
+
.then((worktreeNames) => filterRefs(worktreeNames, patterns, patternCache), invariably.emptyArray)
|
|
1026
1020
|
.then((worktreeNames) =>
|
|
1027
1021
|
worktreeNames.length
|
|
1028
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.5",
|
|
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)",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"braces": "~3.0",
|
|
23
23
|
"cache-directory": "~2.0",
|
|
24
24
|
"camelcase-keys": "~7.0",
|
|
25
|
+
"glob-stream": "~7.0",
|
|
25
26
|
"hpagent": "~0.1.0",
|
|
26
27
|
"isomorphic-git": "~1.10",
|
|
27
28
|
"js-yaml": "~4.1",
|
|
@@ -30,8 +31,7 @@
|
|
|
30
31
|
"progress": "~2.0",
|
|
31
32
|
"should-proxy": "~1.0",
|
|
32
33
|
"simple-get": "~4.0",
|
|
33
|
-
"vinyl": "~2.2"
|
|
34
|
-
"vinyl-fs": "~3.0"
|
|
34
|
+
"vinyl": "~2.2"
|
|
35
35
|
},
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": ">=12.21.0"
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"static site",
|
|
50
50
|
"web publishing"
|
|
51
51
|
],
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "a13d03df41654d4deb78211a5a54953ce2a35fb8"
|
|
53
53
|
}
|