chore(vscode): update to 1.56.0

This commit is contained in:
Akash Satheesan
2021-04-30 20:25:17 +05:30
1749 changed files with 88014 additions and 43316 deletions

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import * as path from 'vs/base/common/path';
import * as platform from 'vs/base/common/platform';
import type * as pty from 'node-pty';
import * as fs from 'fs';
import * as os from 'os';
@@ -17,6 +16,8 @@ import { findExecutable, getWindowsBuildNumber } from 'vs/platform/terminal/node
import { URI } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { WindowsShellHelper } from 'vs/platform/terminal/node/windowsShellHelper';
import { IProcessEnvironment, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
import { timeout } from 'vs/base/common/async';
// Writing large amounts of data can be corrupted for some reason, after looking into this is
// appears to be a race condition around writing to the FD which may be based on how powerful the
@@ -44,9 +45,33 @@ const enum ShutdownConstants {
MaximumShutdownTime = 5000
}
const enum Constants {
/**
* The minimum duration between kill and spawn calls on Windows/conpty as a mitigation for a
* hang issue. See:
* - https://github.com/microsoft/vscode/issues/71966
* - https://github.com/microsoft/vscode/issues/117956
* - https://github.com/microsoft/vscode/issues/121336
*/
KillSpawnThrottleInterval = 250,
/**
* The amount of time to wait when a call is throttles beyond the exact amount, this is used to
* try prevent early timeouts causing a kill/spawn call to happen at double the regular
* interval.
*/
KillSpawnSpacingDuration = 50,
}
interface IWriteObject {
data: string,
isBinary: boolean
}
export class TerminalProcess extends Disposable implements ITerminalChildProcess {
readonly shouldPersist = false;
private static _lastKillOrStart = 0;
private _exitCode: number | undefined;
private _exitMessage: string | undefined;
private _closeTimeout: any;
@@ -62,7 +87,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
private _isDisposed: boolean = false;
private _windowsShellHelper: WindowsShellHelper | undefined;
private _titleInterval: NodeJS.Timer | null = null;
private _writeQueue: string[] = [];
private _writeQueue: IWriteObject[] = [];
private _writeTimeout: NodeJS.Timeout | undefined;
private _delayedResizer: DelayedResizer | undefined;
private readonly _initialCwd: string;
@@ -93,17 +118,17 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
cwd: string,
cols: number,
rows: number,
env: platform.IProcessEnvironment,
env: IProcessEnvironment,
/**
* environment used for `findExecutable`
*/
private readonly _executableEnv: platform.IProcessEnvironment,
private readonly _executableEnv: IProcessEnvironment,
windowsEnableConpty: boolean,
@ILogService private readonly _logService: ILogService
) {
super();
let name: string;
if (platform.isWindows) {
if (isWindows) {
name = path.basename(this._shellLaunchConfig.executable || '');
} else {
// Using 'xterm-256color' here helps ensure that the majority of Linux distributions will use a
@@ -115,7 +140,8 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
this._ptyOptions = {
name,
cwd,
env,
// TODO: When node-pty is updated this cast can be removed
env: env as { [key: string]: string; },
cols,
rows,
useConpty,
@@ -123,7 +149,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
conptyInheritCursor: useConpty && !!_shellLaunchConfig.initialText
};
// Delay resizes to avoid conpty not respecting very early resize calls
if (platform.isWindows) {
if (isWindows) {
if (useConpty && cols === 0 && rows === 0 && this._shellLaunchConfig.executable?.endsWith('Git\\bin\\bash.exe')) {
this._delayedResizer = new DelayedResizer();
this._register(this._delayedResizer.onTrigger(dimensions => {
@@ -194,6 +220,9 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
if (!executable) {
return { message: localize('launchFail.executableDoesNotExist', "Path to shell executable \"{0}\" does not exist", slc.executable) };
}
// Set the executable explicitly here so that node-pty doesn't need to search the
// $PATH too.
slc.executable = executable;
}
}
return undefined;
@@ -201,6 +230,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
private async setupPtyProcess(shellLaunchConfig: IShellLaunchConfig, options: pty.IPtyForkOptions): Promise<void> {
const args = shellLaunchConfig.args || [];
await this._throttleKillSpawn();
this._logService.trace('IPty#spawn', shellLaunchConfig.executable, args, options);
const ptyProcess = (await import('node-pty')).spawn(shellLaunchConfig.executable!, args, options);
this._ptyProcess = ptyProcess;
@@ -220,7 +250,6 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
// Refire the data event
this._onProcessData.fire(data);
if (this._closeTimeout) {
clearTimeout(this._closeTimeout);
this._queueProcessExit();
}
this._windowsShellHelper?.checkShell();
@@ -233,7 +262,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
this._sendProcessId(ptyProcess.pid);
}
public dispose(): void {
public override dispose(): void {
this._isDisposed = true;
if (this._titleInterval) {
clearInterval(this._titleInterval);
@@ -246,7 +275,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
// Send initial timeout async to give event listeners a chance to init
setTimeout(() => this._sendProcessTitle(ptyProcess), 0);
// Setup polling for non-Windows, for Windows `process` doesn't change
if (!platform.isWindows) {
if (!isWindows) {
this._titleInterval = setInterval(() => {
if (this._currentTitle !== ptyProcess.process) {
this._sendProcessTitle(ptyProcess);
@@ -278,6 +307,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
// point but we want to make sure
try {
if (this._ptyProcess) {
await this._throttleKillSpawn();
this._logService.trace('IPty#kill');
this._ptyProcess.kill();
}
@@ -288,6 +318,19 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
this.dispose();
}
private async _throttleKillSpawn(): Promise<void> {
// Only throttle on Windows/conpty
if (!isWindows || !('useConpty' in this._ptyOptions) || !this._ptyOptions.useConpty) {
return;
}
// Use a loop to ensure multiple calls in a single interval space out
while (Date.now() - TerminalProcess._lastKillOrStart < Constants.KillSpawnThrottleInterval) {
this._logService.trace('Throttling kill/spawn call');
await timeout(Constants.KillSpawnThrottleInterval - (Date.now() - TerminalProcess._lastKillOrStart) + Constants.KillSpawnSpacingDuration);
}
TerminalProcess._lastKillOrStart = Date.now();
}
private _sendProcessId(pid: number) {
this._onProcessReady.fire({ pid, cwd: this._initialCwd });
}
@@ -301,7 +344,10 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
}
public shutdown(immediate: boolean): void {
if (immediate) {
// don't force immediate disposal of the terminal processes on Windows as an additional
// mitigation for https://github.com/microsoft/vscode/issues/71966 which causes the pty host
// to become unresponsive, disconnecting all terminals across all windows.
if (immediate && !isWindows) {
this._kill();
} else {
if (!this._closeTimeout && !this._isDisposed) {
@@ -317,16 +363,24 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
}
}
public input(data: string): void {
public input(data: string, isBinary?: boolean): void {
if (this._isDisposed || !this._ptyProcess) {
return;
}
for (let i = 0; i <= Math.floor(data.length / WRITE_MAX_CHUNK_SIZE); i++) {
this._writeQueue.push(data.substr(i * WRITE_MAX_CHUNK_SIZE, WRITE_MAX_CHUNK_SIZE));
const obj = {
isBinary: isBinary || false,
data: data.substr(i * WRITE_MAX_CHUNK_SIZE, WRITE_MAX_CHUNK_SIZE)
};
this._writeQueue.push(obj);
}
this._startWrite();
}
public async processBinary(data: string): Promise<void> {
this.input(data, true);
}
private _startWrite(): void {
// Don't write if it's already queued of is there is nothing to write
if (this._writeTimeout !== undefined || this._writeQueue.length === 0) {
@@ -349,9 +403,12 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
}
private _doWrite(): void {
const data = this._writeQueue.shift()!;
this._logService.trace('IPty#write', `${data.length} characters`);
this._ptyProcess!.write(data);
const object = this._writeQueue.shift()!;
if (object.isBinary) {
this._ptyProcess!.write(Buffer.from(object.data, 'binary') as any);
} else {
this._ptyProcess!.write(object.data);
}
}
public resize(cols: number, rows: number): void {
@@ -412,7 +469,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
}
public getCwd(): Promise<string> {
if (platform.isMacintosh) {
if (isMacintosh) {
// Disable cwd lookup on macOS Big Sur due to spawn blocking thread (darwin v20 is macOS
// Big Sur) https://github.com/Microsoft/vscode/issues/105446
const osRelease = os.release().split('.');
@@ -435,7 +492,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
}
}
if (platform.isLinux) {
if (isLinux) {
return new Promise<string>(resolve => {
if (!this._ptyProcess) {
resolve(this._initialCwd);
@@ -484,7 +541,7 @@ class DelayedResizer extends Disposable {
});
}
dispose(): void {
override dispose(): void {
super.dispose();
clearTimeout(this._timeout);
}