Skip to content

Commit 5539141

Browse files
gnodetclaude
andcommitted
Fix docs gulp race condition with parallel builds
Replace the deep `**` glob pattern for DSL docs with explicit depth patterns using `!(target)` extglob to structurally prevent entering target/ directories during directory scanning. Add a resilientSrc() wrapper around gulp.src() that gracefully handles ENOENT errors from ephemeral directories (e.g. .camel-jbang/work created/deleted by parallel JBang tests). The wrapper continues processing remaining files instead of aborting the entire stream, and uses a close event handler as fallback to prevent task hangs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2f4e7f4 commit 5539141

1 file changed

Lines changed: 40 additions & 3 deletions

File tree

docs/gulpfile.js

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,8 @@ const sources = {
206206
'../core/camel-base/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc',
207207
'../core/camel-main/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc',
208208
'../components/{*,*/*}/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc',
209-
'../dsl/**/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc',
209+
'../dsl/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc',
210+
'../dsl/{*,*/!(target)}/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc',
210211
],
211212
destination: 'components/modules/others/pages',
212213
keep: [
@@ -314,6 +315,37 @@ const tasks = Array.from(sourcesMap).flatMap(([type, definition]) => {
314315
})
315316
}
316317

318+
// Wraps gulp.src to gracefully handle ENOENT from ephemeral directories
319+
// (e.g. .camel-jbang/work created/deleted by tests running in parallel).
320+
// We pipe through a passthrough transform so that on ENOENT we can
321+
// cleanly end() the passthrough, which properly signals downstream
322+
// pipes to finish. Direct error handling on gulp.src() doesn't work
323+
// because Node.js .pipe() does not propagate errors or end signals.
324+
const ignorePatterns = ['**/target/**', '**/.camel-jbang/**']
325+
const resilientSrc = (source, options) => {
326+
const src = gulp.src(source, options)
327+
const passthrough = through2.obj(function (file, enc, done) {
328+
done(null, file)
329+
})
330+
src.on('error', function (err) {
331+
if (err.code === 'ENOENT') {
332+
// Don't end passthrough — the source may continue with remaining files.
333+
// If it stops, the 'close' handler below will clean up.
334+
console.error(`⚠️ ENOENT (skipped): ${err.path || err.message}`)
335+
} else {
336+
passthrough.destroy(err)
337+
}
338+
})
339+
// If the source closes without emitting 'end' (e.g. after an error),
340+
// ensure the passthrough ends so downstream tasks don't hang.
341+
src.on('close', function () {
342+
if (!passthrough.writableEnded) {
343+
passthrough.end()
344+
}
345+
})
346+
return src.pipe(passthrough)
347+
}
348+
317349
// creates symlinks from source to destination that satisfy the
318350
// given filter removing the basedir from a path, i.e. symlinking
319351
// from a flat hiearchy
@@ -326,10 +358,12 @@ const tasks = Array.from(sourcesMap).flatMap(([type, definition]) => {
326358
}
327359
})
328360

329-
return gulp.src(source, { ignore: ['**/target/**'] })
361+
let fileCount = 0
362+
return resilientSrc(source, { ignore: ignorePatterns, allowEmpty: true })
330363
.pipe(filterFn)
331364
.pipe(
332365
map((file, done) => {
366+
fileCount++
333367
// this flattens the output to just .../pages/.../file.ext
334368
// instead of .../pages/camel-.../src/main/docs/.../file.ext
335369
file.base = path.dirname(file.path)
@@ -339,6 +373,9 @@ const tasks = Array.from(sourcesMap).flatMap(([type, definition]) => {
339373
.pipe(gulp.symlink(destination, {
340374
relativeSymlinks: true,
341375
}))
376+
.on('end', () => {
377+
console.log(` → symlinked ${fileCount} files to ${destination}`)
378+
})
342379
}
343380

344381
// generates sorted & grouped nav.adoc file from a set of .adoc
@@ -409,7 +446,7 @@ const tasks = Array.from(sourcesMap).flatMap(([type, definition]) => {
409446
return done()
410447
}
411448

412-
return gulp.src(source, { ignore: ['**/target/**'] }) // asciidoc files
449+
return resilientSrc(source, { ignore: ignorePatterns, allowEmpty: true }) // asciidoc files
413450
.pipe(through2.obj(extractExamples)) // extracted example files
414451
// symlink links from a fixed directory, i.e. we could link to
415452
// the example files from `destination`, that would not work for

0 commit comments

Comments
 (0)