From f8ae10c8d05cf92f55c19b4937f0a5c5c0498778 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 3 Aug 2022 09:41:12 +0200 Subject: [PATCH] Piping into Code fails if data writes delayed (fix #155341) (#156973) --- src/vs/code/node/cli.ts | 2 +- src/vs/platform/environment/node/stdin.ts | 15 +++++++++++---- src/vs/server/node/server.cli.ts | 9 +++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index 3a006e635a3..0c2429c97e0 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -179,7 +179,7 @@ export async function main(argv: string[]): Promise { // returns a file path where stdin input is written into (write in progress). try { - readFromStdin(stdinFilePath, !!verbose); // throws error if file can not be written + await readFromStdin(stdinFilePath, !!verbose); // throws error if file can not be written // Make sure to open tmp file addArg(argv, stdinFilePath); diff --git a/src/vs/platform/environment/node/stdin.ts b/src/vs/platform/environment/node/stdin.ts index 27c30eb1e20..9bceca5ec47 100644 --- a/src/vs/platform/environment/node/stdin.ts +++ b/src/vs/platform/environment/node/stdin.ts @@ -39,26 +39,33 @@ export function getStdinFilePath(): string { } export async function readFromStdin(targetPath: string, verbose: boolean): Promise { - let encoding = await resolveTerminalEncoding(verbose); - const iconv = await import('@vscode/iconv-lite-umd'); + let [encoding, iconv] = await Promise.all([ + resolveTerminalEncoding(verbose), // respect terminal encoding when piping into file + import('@vscode/iconv-lite-umd'), // lazy load encoding module for usage + Promises.appendFile(targetPath, '') // make sure file exists right away (https://github.com/microsoft/vscode/issues/155341) + ]); + if (!iconv.encodingExists(encoding)) { console.log(`Unsupported terminal encoding: ${encoding}, falling back to UTF-8.`); encoding = 'utf8'; } - // Pipe into tmp file using terminals encoding // Use a `Queue` to be able to use `appendFile` // which helps file watchers to be aware of the // changes because each append closes the underlying // file descriptor. // (https://github.com/microsoft/vscode/issues/148952) - const decoder = iconv.getDecoder(encoding); + const appendFileQueue = new Queue(); + + const decoder = iconv.getDecoder(encoding); + process.stdin.on('data', chunk => { const chunkStr = decoder.write(chunk); appendFileQueue.queue(() => Promises.appendFile(targetPath, chunkStr)); }); + process.stdin.on('end', () => { const end = decoder.end(); if (typeof end === 'string') { diff --git a/src/vs/server/node/server.cli.ts b/src/vs/server/node/server.cli.ts index 837b0b500d4..650552d798d 100644 --- a/src/vs/server/node/server.cli.ts +++ b/src/vs/server/node/server.cli.ts @@ -87,7 +87,7 @@ const cliRemoteAuthority = process.env['VSCODE_CLI_AUTHORITY'] as string; const cliStdInFilePath = process.env['VSCODE_STDIN_FILE_PATH'] as string; -export function main(desc: ProductDescription, args: string[]): void { +export async function main(desc: ProductDescription, args: string[]): Promise { if (!cliPipe && !cliCommand) { console.log('Command is only available in WSL or inside a Visual Studio Code terminal.'); return; @@ -184,7 +184,7 @@ export function main(desc: ProductDescription, args: string[]): void { let stdinFilePath = cliStdInFilePath; if (!stdinFilePath) { stdinFilePath = getStdinFilePath(); - readFromStdin(stdinFilePath, verbose); // throws error if file can not be written + await readFromStdin(stdinFilePath, verbose); // throws error if file can not be written } // Make sure to open tmp file @@ -460,5 +460,6 @@ function mapFileToRemoteUri(uri: string): string { } const [, , productName, version, commit, executableName, ...remainingArgs] = process.argv; -main({ productName, version, commit, executableName }, remainingArgs); - +main({ productName, version, commit, executableName }, remainingArgs).then(null, err => { + console.error(err.message || err.stack || err); +});