Skip to content

Commit 7cd43cd

Browse files
authored
Merge pull request github#3369 from github/koesie10/stream-cli-output
Stream CLI server command stderr instead of buffering
2 parents 58b26d2 + 1b66767 commit 7cd43cd

File tree

1 file changed

+38
-2
lines changed
  • extensions/ql-vscode/src/codeql-cli

1 file changed

+38
-2
lines changed

extensions/ql-vscode/src/codeql-cli/cli.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)