@@ -362,6 +362,8 @@ export class CodeQLCliServer implements Disposable {
362362 silent ?: boolean ,
363363 ) : Promise < string > {
364364 const stderrBuffers : Buffer [ ] = [ ] ;
365+ // The current buffer of stderr of a single line. To be used for logging.
366+ let currentLineStderrBuffer : Buffer = Buffer . alloc ( 0 ) ;
365367 if ( this . commandInProcess ) {
366368 throw new Error ( "runCodeQlCliInternal called while cli was running" ) ;
367369 }
@@ -419,6 +421,38 @@ export class CodeQLCliServer implements Disposable {
419421 // Listen to stderr
420422 process . stderr . addListener ( "data" , ( newData : Buffer ) => {
421423 stderrBuffers . push ( newData ) ;
424+
425+ if ( ! silent ) {
426+ currentLineStderrBuffer = Buffer . concat ( [
427+ currentLineStderrBuffer ,
428+ newData ,
429+ ] ) ;
430+
431+ // Print the stderr to the logger as it comes in. We need to ensure that
432+ // we don't split messages on the same line, so we buffer the stderr and
433+ // split it on EOLs.
434+ const eolBuffer = Buffer . from ( EOL ) ;
435+
436+ let hasCreatedSubarray = false ;
437+
438+ let eolIndex ;
439+ while (
440+ ( eolIndex = currentLineStderrBuffer . indexOf ( eolBuffer ) ) !== - 1
441+ ) {
442+ const line = currentLineStderrBuffer . subarray ( 0 , eolIndex ) ;
443+ void this . logger . log ( line . toString ( "utf-8" ) ) ;
444+ currentLineStderrBuffer = currentLineStderrBuffer . subarray (
445+ eolIndex + eolBuffer . length ,
446+ ) ;
447+ hasCreatedSubarray = true ;
448+ }
449+
450+ // We have created a subarray, which means that the complete original buffer is now referenced
451+ // by the subarray. We need to create a new buffer to avoid memory leaks.
452+ if ( hasCreatedSubarray ) {
453+ currentLineStderrBuffer = Buffer . from ( currentLineStderrBuffer ) ;
454+ }
455+ }
422456 } ) ;
423457 // Listen for process exit.
424458 process . addListener ( "close" , ( code ) =>
@@ -433,6 +467,8 @@ export class CodeQLCliServer implements Disposable {
433467 // Make sure we remove the terminator;
434468 const data = fullBuffer . toString ( "utf8" , 0 , fullBuffer . length - 1 ) ;
435469 if ( ! silent ) {
470+ void this . logger . log ( currentLineStderrBuffer . toString ( "utf8" ) ) ;
471+ currentLineStderrBuffer = Buffer . alloc ( 0 ) ;
436472 void this . logger . log ( "CLI command succeeded." ) ;
437473 }
438474 return data ;
@@ -452,8 +488,8 @@ export class CodeQLCliServer implements Disposable {
452488 cliError . stack += getErrorStack ( err ) ;
453489 throw cliError ;
454490 } finally {
455- if ( ! silent ) {
456- void this . logger . log ( Buffer . concat ( stderrBuffers ) . toString ( "utf8" ) ) ;
491+ if ( ! silent && currentLineStderrBuffer . length > 0 ) {
492+ void this . logger . log ( currentLineStderrBuffer . toString ( "utf8" ) ) ;
457493 }
458494 // Remove the listeners we set up.
459495 process . stdout . removeAllListeners ( "data" ) ;
0 commit comments