@@ -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