@antora/content-aggregator 3.1.5 → 3.1.7
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 +151 -110
- package/lib/git-plugin-http.js +5 -4
- package/package.json +3 -3
package/lib/aggregate-content.js
CHANGED
|
@@ -5,7 +5,6 @@ const { createHash } = require('crypto')
|
|
|
5
5
|
const createGitHttpPlugin = require('./git-plugin-http')
|
|
6
6
|
const decodeUint8Array = require('./decode-uint8-array')
|
|
7
7
|
const deepClone = require('./deep-clone')
|
|
8
|
-
const deepFlatten = require('./deep-flatten')
|
|
9
8
|
const EventEmitter = require('events')
|
|
10
9
|
const expandPath = require('@antora/expand-path-helper')
|
|
11
10
|
const File = require('./file')
|
|
@@ -17,6 +16,7 @@ const GitCredentialManagerStore = require('./git-credential-manager-store')
|
|
|
17
16
|
const git = require('./git')
|
|
18
17
|
const { NotFoundError, ObjectTypeError, UnknownTransportError, UrlParseError } = git.Errors
|
|
19
18
|
const globStream = require('glob-stream')
|
|
19
|
+
const { inspect } = require('util')
|
|
20
20
|
const invariably = require('./invariably')
|
|
21
21
|
const logger = require('./logger')
|
|
22
22
|
const { makeMatcherRx, versionMatcherOpts: VERSION_MATCHER_OPTS } = require('./matcher')
|
|
@@ -93,83 +93,71 @@ function aggregateContent (playbook) {
|
|
|
93
93
|
return ensureCacheDir(requestedCacheDir, startDir).then((cacheDir) => {
|
|
94
94
|
const gitConfig = Object.assign({ ensureGitSuffix: true }, playbook.git)
|
|
95
95
|
const gitPlugins = loadGitPlugins(gitConfig, playbook.network || {}, startDir)
|
|
96
|
-
const
|
|
96
|
+
const concurrency = {
|
|
97
|
+
fetch: Math.max(gitConfig.fetchConcurrency || Infinity, 1),
|
|
98
|
+
read: Math.max(gitConfig.readConcurrency || Infinity, 1),
|
|
99
|
+
}
|
|
97
100
|
const sourcesByUrl = sources.reduce((accum, source) => {
|
|
98
101
|
return accum.set(source.url, [...(accum.get(source.url) || []), Object.assign({}, sourceDefaults, source)])
|
|
99
102
|
}, new Map())
|
|
100
103
|
const progress = !quiet && createProgress(sourcesByUrl.keys(), process.stdout)
|
|
101
104
|
const refPatternCache = Object.assign(new Map(), { braces: new Map() })
|
|
102
105
|
const loadOpts = { cacheDir, fetch, gitPlugins, progress, startDir, refPatternCache }
|
|
103
|
-
return collectFiles(sourcesByUrl, loadOpts,
|
|
106
|
+
return collectFiles(sourcesByUrl, loadOpts, concurrency).then(buildAggregate, (err) => {
|
|
104
107
|
progress && progress.terminate()
|
|
105
108
|
throw err
|
|
106
109
|
})
|
|
107
110
|
})
|
|
108
111
|
}
|
|
109
112
|
|
|
110
|
-
async function collectFiles (sourcesByUrl, loadOpts, concurrency) {
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const runTask = (primary, continuation, idx) =>
|
|
129
|
-
primary().then((value) => {
|
|
130
|
-
if (!rejection) startedContinuations[idx] = continuation(value).catch(recordRejection)
|
|
131
|
-
}, recordRejection)
|
|
132
|
-
if (tasks.length > concurrency) {
|
|
133
|
-
started = []
|
|
134
|
-
const pending = []
|
|
135
|
-
for (const [primary, continuation] of tasks) {
|
|
136
|
-
const current = runTask(primary, continuation, started.length).finally(() =>
|
|
137
|
-
pending.splice(pending.indexOf(current), 1)
|
|
138
|
-
)
|
|
139
|
-
started.push(current)
|
|
140
|
-
if (pending.push(current) < concurrency) continue
|
|
141
|
-
await Promise.race(pending)
|
|
142
|
-
if (rejection) break
|
|
113
|
+
async function collectFiles (sourcesByUrl, loadOpts, concurrency, fetchedUrls) {
|
|
114
|
+
const loadTasks = [...sourcesByUrl.entries()].map(([url, sources]) => {
|
|
115
|
+
const loadOptsForUrl = Object.assign({}, loadOpts)
|
|
116
|
+
if (loadOpts.fetch && fetchedUrls && fetchedUrls.length && fetchedUrls.includes(url)) loadOptsForUrl.fetch = false
|
|
117
|
+
if (tagsSpecified(sources)) loadOptsForUrl.fetchTags = true
|
|
118
|
+
return loadRepository.bind(null, url, loadOptsForUrl, { url, sources })
|
|
119
|
+
})
|
|
120
|
+
return gracefulPromiseAllWithLimit(loadTasks, concurrency.fetch).then(([results, rejections]) => {
|
|
121
|
+
if (rejections.length) {
|
|
122
|
+
if (concurrency.fetch > 1 && results.length > 1 && rejections.every(({ recoverable }) => recoverable)) {
|
|
123
|
+
if (loadOpts.progress) loadOpts.progress.terminate() // reset cursor position and allow it be reused
|
|
124
|
+
const msg0 = 'An unexpected error occurred while fetching content sources concurrently.'
|
|
125
|
+
const msg1 = 'Retrying with git.fetch_concurrency value of 1.'
|
|
126
|
+
logger.warn(rejections[0], msg0 + ' ' + msg1)
|
|
127
|
+
const fulfilledUrls = results.map((it) => it && it.repo.url && it.url).filter((it) => it)
|
|
128
|
+
return collectFiles(sourcesByUrl, loadOpts, Object.assign(concurrency, { fetch: 1 }), fulfilledUrls)
|
|
129
|
+
}
|
|
130
|
+
throw rejections[0]
|
|
143
131
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
)
|
|
132
|
+
return Promise.all(
|
|
133
|
+
results.map(({ repo, authStatus, sources }) =>
|
|
134
|
+
selectStartPathsForRepository(repo, authStatus, sources).then((startPaths) =>
|
|
135
|
+
collectFilesFromStartPaths.bind(null, startPaths, repo, authStatus)
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
).then((collectTasks) => promiseAllWithLimit(collectTasks, concurrency.read))
|
|
139
|
+
})
|
|
153
140
|
}
|
|
154
141
|
|
|
155
142
|
function buildAggregate (componentVersionBuckets) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (!entry) return accum.set(key, batch)
|
|
143
|
+
const entries = Object.assign(new Map(), { accum: [] })
|
|
144
|
+
for (const batchesForOrigin of componentVersionBuckets) {
|
|
145
|
+
for (const batch of batchesForOrigin) {
|
|
146
|
+
let key, entry
|
|
147
|
+
if ((entry = entries.get((key = batch.version + '@' + batch.name)))) {
|
|
162
148
|
const { files, origins } = batch
|
|
163
149
|
;(batch.files = entry.files).push(...files)
|
|
164
150
|
;(batch.origins = entry.origins).push(origins[0])
|
|
165
151
|
Object.assign(entry, batch)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
152
|
+
} else {
|
|
153
|
+
entries.set(key, batch).accum.push(batch)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return entries.accum
|
|
170
158
|
}
|
|
171
159
|
|
|
172
|
-
async function loadRepository (url, opts) {
|
|
160
|
+
async function loadRepository (url, opts, result = {}) {
|
|
173
161
|
let authStatus, dir, repo
|
|
174
162
|
const cache = { [REF_PATTERN_CACHE_KEY]: opts.refPatternCache }
|
|
175
163
|
if (~url.indexOf(':') && GIT_URI_DETECTOR_RX.test(url)) {
|
|
@@ -179,6 +167,7 @@ async function loadRepository (url, opts) {
|
|
|
179
167
|
dir = ospath.join(cacheDir, generateCloneFolderName(displayUrl))
|
|
180
168
|
// NOTE the presence of the url property on the repo object implies the repository is remote
|
|
181
169
|
repo = { cache, dir, fs, gitdir: dir, noCheckout: true, url }
|
|
170
|
+
const { credentialManager } = gitPlugins
|
|
182
171
|
const validStateFile = ospath.join(dir, VALID_STATE_FILENAME)
|
|
183
172
|
try {
|
|
184
173
|
await fsp.access(validStateFile)
|
|
@@ -188,8 +177,7 @@ async function loadRepository (url, opts) {
|
|
|
188
177
|
await git
|
|
189
178
|
.fetch(fetchOpts)
|
|
190
179
|
.then(() => {
|
|
191
|
-
|
|
192
|
-
authStatus = credentials ? 'auth-embedded' : credentialManager.status({ url }) ? 'auth-required' : undefined
|
|
180
|
+
authStatus = identifyAuthStatus(credentialManager, credentials, url)
|
|
193
181
|
return git.setConfig(Object.assign({ path: 'remote.origin.private', value: authStatus }, repo))
|
|
194
182
|
})
|
|
195
183
|
.catch((fetchErr) => {
|
|
@@ -210,14 +198,13 @@ async function loadRepository (url, opts) {
|
|
|
210
198
|
.clone(fetchOpts)
|
|
211
199
|
.then(() => git.resolveRef(Object.assign({ ref: 'HEAD', depth: 1 }, repo)))
|
|
212
200
|
.then(() => {
|
|
213
|
-
|
|
214
|
-
authStatus = credentials ? 'auth-embedded' : credentialManager.status({ url }) ? 'auth-required' : undefined
|
|
201
|
+
authStatus = identifyAuthStatus(credentialManager, credentials, url)
|
|
215
202
|
return git.setConfig(Object.assign({ path: 'remote.origin.private', value: authStatus }, repo))
|
|
216
203
|
})
|
|
217
204
|
.catch((cloneErr) => {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
throw transformGitCloneError(cloneErr, displayUrl)
|
|
205
|
+
if (fetchOpts.onProgress) fetchOpts.onProgress.finish(cloneErr)
|
|
206
|
+
const authRequested = credentialManager.status({ url }) === 'requested'
|
|
207
|
+
throw transformGitCloneError(cloneErr, displayUrl, authRequested)
|
|
221
208
|
})
|
|
222
209
|
.then(() => fsp.writeFile(validStateFile, '').catch(invariably.void))
|
|
223
210
|
.then(() => fetchOpts.onProgress && fetchOpts.onProgress.finish())
|
|
@@ -234,7 +221,7 @@ async function loadRepository (url, opts) {
|
|
|
234
221
|
} else {
|
|
235
222
|
throw new Error(`Local content source does not exist: ${dir}${url !== dir ? ' (url: ' + url + ')' : ''}`)
|
|
236
223
|
}
|
|
237
|
-
return { repo, authStatus }
|
|
224
|
+
return Object.assign(result, { repo, authStatus })
|
|
238
225
|
}
|
|
239
226
|
|
|
240
227
|
function extractCredentials (url) {
|
|
@@ -256,19 +243,33 @@ function extractCredentials (url) {
|
|
|
256
243
|
}
|
|
257
244
|
}
|
|
258
245
|
|
|
259
|
-
async function
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
246
|
+
async function selectStartPathsForRepository (repo, authStatus, sources) {
|
|
247
|
+
const startPaths = []
|
|
248
|
+
const originUrls = {}
|
|
249
|
+
for (const source of sources) {
|
|
250
|
+
const { version, editUrl } = source
|
|
251
|
+
// NOTE if repository is managed (has a url property), we can assume the remote name is origin
|
|
252
|
+
// TODO if the repo has no remotes, then remoteName should be undefined
|
|
253
|
+
const remoteName = repo.url ? 'origin' : source.remote || 'origin'
|
|
254
|
+
const originUrl = repo.url || (originUrls[remoteName] ||= await resolveRemoteUrl(repo, remoteName))
|
|
255
|
+
const refs = await selectReferences(source, repo, remoteName)
|
|
256
|
+
if (refs.length) {
|
|
257
|
+
for (const ref of refs) {
|
|
258
|
+
for (const startPath of await selectStartPaths(source, repo, remoteName, ref)) {
|
|
259
|
+
startPaths.push({ startPath, ref, originUrl, editUrl, version })
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
const { url, branches, tags } = source
|
|
264
264
|
const startPathInfo =
|
|
265
|
-
'startPaths' in source
|
|
265
|
+
'startPaths' in source
|
|
266
|
+
? { 'start paths': source.startPaths || undefined }
|
|
267
|
+
: { 'start path': source.startPath || undefined }
|
|
266
268
|
const sourceInfo = yaml.dump({ url, branches, tags, ...startPathInfo }, { flowLevel: 1 }).trimRight()
|
|
267
269
|
logger.info(`No matching references found for content source entry (${sourceInfo.replace(NEWLINE_RX, ' | ')})`)
|
|
268
|
-
return []
|
|
269
270
|
}
|
|
270
|
-
|
|
271
|
-
|
|
271
|
+
}
|
|
272
|
+
return startPaths
|
|
272
273
|
}
|
|
273
274
|
|
|
274
275
|
// QUESTION should we resolve HEAD to a ref eagerly to avoid having to do a match on it?
|
|
@@ -397,10 +398,9 @@ function getCurrentBranchName (repo, remote) {
|
|
|
397
398
|
return refPromise.then((ref) => (ref.startsWith('refs/') ? ref.replace(SHORTEN_REF_RX, '') : undefined))
|
|
398
399
|
}
|
|
399
400
|
|
|
400
|
-
async function
|
|
401
|
+
async function selectStartPaths (source, repo, remoteName, ref) {
|
|
401
402
|
const url = repo.url
|
|
402
403
|
const displayUrl = url || repo.dir
|
|
403
|
-
const { version, editUrl } = source
|
|
404
404
|
const worktreePath = ref.head
|
|
405
405
|
if (!worktreePath) {
|
|
406
406
|
ref.oid = await git.resolveRef(
|
|
@@ -420,17 +420,22 @@ async function collectFilesFromReference (source, repo, remoteName, authStatus,
|
|
|
420
420
|
const flag = worktreePath ? ' <worktree>' : ref.remote && worktreePath === false ? ` <remotes/${ref.remote}>` : ''
|
|
421
421
|
throw new Error(`no start paths found in ${where} (${ref.type}: ${ref.shortname}${flag})`)
|
|
422
422
|
}
|
|
423
|
-
return
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
423
|
+
return startPaths
|
|
424
|
+
}
|
|
425
|
+
return [cleanStartPath(coerceToString(source.startPath))]
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
async function collectFilesFromStartPaths (startPaths, repo, authStatus) {
|
|
429
|
+
const buckets = []
|
|
430
|
+
for (const { startPath, ref, originUrl, editUrl, version } of startPaths) {
|
|
431
|
+
buckets.push(await collectFilesFromStartPath(startPath, repo, authStatus, ref, originUrl, editUrl, version))
|
|
428
432
|
}
|
|
429
|
-
|
|
430
|
-
return
|
|
433
|
+
repo.cache = undefined
|
|
434
|
+
return buckets
|
|
431
435
|
}
|
|
432
436
|
|
|
433
|
-
function collectFilesFromStartPath (startPath, repo, authStatus, ref,
|
|
437
|
+
function collectFilesFromStartPath (startPath, repo, authStatus, ref, originUrl, editUrl, version) {
|
|
438
|
+
const worktreePath = ref.head
|
|
434
439
|
const origin = computeOrigin(originUrl, authStatus, repo.gitdir, ref, startPath, worktreePath, editUrl)
|
|
435
440
|
return (worktreePath ? readFilesFromWorktree(origin) : readFilesFromGitTree(repo, ref.oid, startPath))
|
|
436
441
|
.then((files) =>
|
|
@@ -510,26 +515,25 @@ function srcFs (cwd, origin) {
|
|
|
510
515
|
}
|
|
511
516
|
|
|
512
517
|
function readFilesFromGitTree (repo, oid, startPath) {
|
|
513
|
-
return git
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
getGitTreeAtStartPath(repo, oid, startPath).then((start) =>
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
518
|
+
return git.readTree(Object.assign({ oid }, repo)).then((root) => {
|
|
519
|
+
Object.assign(root, { dirname: '' })
|
|
520
|
+
return startPath
|
|
521
|
+
? getGitTreeAtStartPath(repo, oid, startPath).then((start) => {
|
|
522
|
+
Object.assign(start, { dirname: startPath })
|
|
523
|
+
return srcGitTree(repo, root, start)
|
|
524
|
+
})
|
|
525
|
+
: srcGitTree(repo, root)
|
|
526
|
+
})
|
|
520
527
|
}
|
|
521
528
|
|
|
522
529
|
function getGitTreeAtStartPath (repo, oid, startPath) {
|
|
523
|
-
return git.readTree(Object.assign({ oid, filepath: startPath }, repo)).
|
|
524
|
-
|
|
525
|
-
(
|
|
526
|
-
|
|
527
|
-
throw new Error(`the start path '${startPath}' ${m}`)
|
|
528
|
-
}
|
|
529
|
-
)
|
|
530
|
+
return git.readTree(Object.assign({ oid, filepath: startPath }, repo)).catch((err) => {
|
|
531
|
+
const m = err instanceof ObjectTypeError && err.data.expected === 'tree' ? 'is not a directory' : 'does not exist'
|
|
532
|
+
throw new Error(`the start path '${startPath}' ${m}`)
|
|
533
|
+
})
|
|
530
534
|
}
|
|
531
535
|
|
|
532
|
-
function srcGitTree (repo, root, start) {
|
|
536
|
+
function srcGitTree (repo, root, start = root) {
|
|
533
537
|
return new Promise((resolve, reject) => {
|
|
534
538
|
const files = []
|
|
535
539
|
createGitTreeWalker(repo, root, filterGitEntry, gitEntryToFile)
|
|
@@ -816,7 +820,6 @@ function onGitProgress ({ phase, loaded, total }) {
|
|
|
816
820
|
|
|
817
821
|
function onGitComplete (err) {
|
|
818
822
|
if (err) {
|
|
819
|
-
// TODO could use progressBar.interrupt() to replace bar with message instead
|
|
820
823
|
this.chars.incomplete = '?'
|
|
821
824
|
this.update(0)
|
|
822
825
|
// NOTE force progress bar to update regardless of throttle setting
|
|
@@ -846,6 +849,10 @@ function resolveCredentials (credentialsFromUrlHolder, url, auth) {
|
|
|
846
849
|
)
|
|
847
850
|
}
|
|
848
851
|
|
|
852
|
+
function identifyAuthStatus (credentialManager, credentials, url) {
|
|
853
|
+
return credentials ? 'auth-embedded' : credentialManager.status({ url }) ? 'auth-required' : undefined
|
|
854
|
+
}
|
|
855
|
+
|
|
849
856
|
/**
|
|
850
857
|
* Generates a safe, unique folder name for a git URL.
|
|
851
858
|
*
|
|
@@ -957,8 +964,8 @@ function ensureCacheDir (preferredCacheDir, startDir) {
|
|
|
957
964
|
)
|
|
958
965
|
}
|
|
959
966
|
|
|
960
|
-
function transformGitCloneError (err, displayUrl) {
|
|
961
|
-
let wrappedMsg, trimMessage
|
|
967
|
+
function transformGitCloneError (err, displayUrl, authRequested) {
|
|
968
|
+
let wrappedMsg, recoverable, trimMessage
|
|
962
969
|
if (HTTP_ERROR_CODE_RX.test(err.code)) {
|
|
963
970
|
switch (err.data.statusCode) {
|
|
964
971
|
case 401:
|
|
@@ -967,25 +974,26 @@ function transformGitCloneError (err, displayUrl) {
|
|
|
967
974
|
: 'Content repository not found or requires credentials'
|
|
968
975
|
break
|
|
969
976
|
case 404:
|
|
970
|
-
wrappedMsg =
|
|
977
|
+
wrappedMsg = authRequested
|
|
978
|
+
? 'Content repository not found or credentials were rejected'
|
|
979
|
+
: 'Content repository not found'
|
|
971
980
|
break
|
|
972
981
|
default:
|
|
973
982
|
wrappedMsg = err.message
|
|
974
|
-
trimMessage = true
|
|
983
|
+
recoverable = trimMessage = true
|
|
975
984
|
}
|
|
976
985
|
} else if (err instanceof UrlParseError || err instanceof UnknownTransportError) {
|
|
977
986
|
wrappedMsg = 'Content source uses an unsupported transport protocol'
|
|
978
987
|
} else if (err.code === 'ENOTFOUND') {
|
|
979
988
|
wrappedMsg = `Content repository host could not be resolved: ${err.hostname}`
|
|
980
989
|
} else {
|
|
981
|
-
wrappedMsg =
|
|
982
|
-
trimMessage = true
|
|
983
|
-
}
|
|
984
|
-
if (trimMessage) {
|
|
985
|
-
wrappedMsg = ~(wrappedMsg = wrappedMsg.trimRight()).indexOf('. ') ? wrappedMsg : wrappedMsg.replace(/\.$/, '')
|
|
990
|
+
wrappedMsg = err.message || String(err)
|
|
991
|
+
recoverable = trimMessage = true
|
|
986
992
|
}
|
|
993
|
+
if (trimMessage && !~(wrappedMsg = wrappedMsg.trimEnd()).indexOf('. ')) wrappedMsg = wrappedMsg.replace(/\.$/, '')
|
|
987
994
|
const errWrapper = new Error(`${wrappedMsg} (url: ${displayUrl})`)
|
|
988
|
-
errWrapper.stack += `\nCaused by: ${err.stack
|
|
995
|
+
errWrapper.stack += `\nCaused by: ${err.stack ? inspect(err).replace(/^Error \[(.+?)\](?=: )/, '$1') : err}`
|
|
996
|
+
if (recoverable) Object.defineProperty(errWrapper, 'recoverable', { value: true })
|
|
989
997
|
return errWrapper
|
|
990
998
|
}
|
|
991
999
|
|
|
@@ -1034,7 +1042,7 @@ function findWorktrees (repo, patterns) {
|
|
|
1034
1042
|
.then((branch = worktreeName) =>
|
|
1035
1043
|
fsp
|
|
1036
1044
|
.readFile(ospath.join(gitdir, 'gitdir'), 'utf8')
|
|
1037
|
-
.then((contents) => ({ branch, dir: ospath.dirname(contents.
|
|
1045
|
+
.then((contents) => ({ branch, dir: ospath.dirname(contents.trimEnd()) }))
|
|
1038
1046
|
)
|
|
1039
1047
|
})
|
|
1040
1048
|
).then((entries) => entries.reduce((accum, it) => accum.set(it.branch, it.dir), new Map()))
|
|
@@ -1048,4 +1056,37 @@ function findWorktrees (repo, patterns) {
|
|
|
1048
1056
|
)
|
|
1049
1057
|
}
|
|
1050
1058
|
|
|
1059
|
+
async function gracefulPromiseAllWithLimit (tasks, limit = Infinity) {
|
|
1060
|
+
const rejections = []
|
|
1061
|
+
const recordRejection = (err) => rejections.push(err) && undefined
|
|
1062
|
+
const started = []
|
|
1063
|
+
if (tasks.length <= limit) {
|
|
1064
|
+
for (const task of tasks) started.push(task().catch(recordRejection))
|
|
1065
|
+
} else {
|
|
1066
|
+
const pending = []
|
|
1067
|
+
for (const task of tasks) {
|
|
1068
|
+
const current = task()
|
|
1069
|
+
.catch(recordRejection)
|
|
1070
|
+
.finally(() => pending.splice(pending.indexOf(current), 1))
|
|
1071
|
+
started.push(current)
|
|
1072
|
+
if (pending.push(current) < limit) continue
|
|
1073
|
+
await Promise.race(pending)
|
|
1074
|
+
if (rejections.length) break
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
return Promise.all(started).then((results) => [results, rejections])
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
async function promiseAllWithLimit (tasks, limit = Infinity) {
|
|
1081
|
+
if (tasks.length <= limit) return Promise.all(tasks.map((task) => task()))
|
|
1082
|
+
const started = []
|
|
1083
|
+
const pending = []
|
|
1084
|
+
for (const task of tasks) {
|
|
1085
|
+
const current = task().finally(() => pending.splice(pending.indexOf(current), 1))
|
|
1086
|
+
started.push(current)
|
|
1087
|
+
if (pending.push(current) >= limit) await Promise.race(pending)
|
|
1088
|
+
}
|
|
1089
|
+
return Promise.all(started)
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1051
1092
|
module.exports = aggregateContent
|
package/lib/git-plugin-http.js
CHANGED
|
@@ -49,11 +49,12 @@ module.exports = ({ headers: extraHeaders, httpProxy, httpsProxy, noProxy } = {}
|
|
|
49
49
|
}
|
|
50
50
|
return {
|
|
51
51
|
async request ({ url, method, headers, body }) {
|
|
52
|
-
headers = mergeHeaders(headers, extraHeaders)
|
|
52
|
+
headers = Object.assign(mergeHeaders(headers, extraHeaders), { connection: 'close' })
|
|
53
53
|
body = await mergeBuffers(body)
|
|
54
|
-
return new Promise((resolve, reject) =>
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
const opts = { url, method, headers, body, timeout: 0, keepAlive: false }
|
|
56
|
+
return get(opts, (err, res) => (err ? reject(err) : resolve(distillResponse(res))))
|
|
57
|
+
})
|
|
57
58
|
},
|
|
58
59
|
}
|
|
59
60
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antora/content-aggregator",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.7",
|
|
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)",
|
|
@@ -29,13 +29,13 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@antora/expand-path-helper": "~2.0",
|
|
32
|
-
"@antora/logger": "3.1.
|
|
32
|
+
"@antora/logger": "3.1.7",
|
|
33
33
|
"@antora/user-require-helper": "~2.0",
|
|
34
34
|
"braces": "~3.0",
|
|
35
35
|
"cache-directory": "~2.0",
|
|
36
36
|
"glob-stream": "~7.0",
|
|
37
37
|
"hpagent": "~1.2",
|
|
38
|
-
"isomorphic-git": "~1.
|
|
38
|
+
"isomorphic-git": "~1.25",
|
|
39
39
|
"js-yaml": "~4.1",
|
|
40
40
|
"multi-progress": "~4.0",
|
|
41
41
|
"picomatch": "~2.3",
|