Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: update electron@19.1.3 #164882

Merged
merged 2 commits into from
Oct 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions src/bootstrap-fork.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,6 @@ if (process.env['VSCODE_PARENT_PID']) {
terminateWhenParentTerminates();
}

// Listen for message ports
if (process.env['VSCODE_WILL_SEND_MESSAGE_PORT']) {
listenForMessagePort();
}

// Load AMD entry point
require('./bootstrap-amd').load(process.env['VSCODE_AMD_ENTRYPOINT']);

Expand Down Expand Up @@ -237,21 +232,4 @@ function terminateWhenParentTerminates() {
}
}

function listenForMessagePort() {
// We need to listen for the 'port' event as soon as possible,
// otherwise we might miss the event. But we should also be
// prepared in case the event arrives late.
// @ts-ignore
if (process.parentPort) {
// @ts-ignore
process.parentPort.on('message', (e) => {
if (global.vscodePortsCallback) {
global.vscodePortsCallback(e.ports);
} else {
global.vscodePorts = e.ports;
}
});
}
}

//#endregion
107 changes: 64 additions & 43 deletions src/vs/platform/extensions/electron-main/extensionHostStarter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,27 @@ import * as electron from 'electron';
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';

declare namespace UtilityProcessProposedApi {
interface UtilityProcessConstructorOptions {
interface ForkOptions {
/**
* Environment key-value pairs. Default is `process.env`.
*/
env?: NodeJS.ProcessEnv;
/**
* List of string arguments passed to the executable. Default is
* `process.execArgv`.
* List of string arguments passed to the executable.
*/
execArgv?: string[];
/**
* Child's stdout and stderr configuration. Default is `pipe`. String value can be
* one of `pipe`, `ignore`, `inherit`, for more details on these values you can
* refer to stdio documentation from Node.js. Currently this option does not allow
* configuring stdin and is always set to `ignore`. For example, the supported
* values will be processed as following:
* Current working directory of the child process.
*/
cwd?: string;
/**
* Allows configuring the mode for `stdout` and `stderr` of the child process.
* Default is `inherit`. String value can be one of `pipe`, `ignore`, `inherit`,
* for more details on these values you can refer to stdio documentation from
* Node.js. Currently this option only supports configuring `stdout` and `stderr`
* to either `pipe`, `inherit` or `ignore`. Configuring `stdin` is not supported;
* `stdin` will always be ignored. For example, the supported values will be
* processed as following:
*/
stdio?: (Array<'pipe' | 'ignore' | 'inherit'>) | (string);
/**
Expand All @@ -61,30 +66,42 @@ declare namespace UtilityProcessProposedApi {

// Docs: https://electronjs.org/docs/api/utility-process

static fork(modulePath: string, args?: string[], options?: ForkOptions): UtilityProcess;
/**
* Emitted after the child process ends. `code` contains the exit code for the
* process obtained from waitpid on posix, or GetExitCodeProcess on windows.
* Emitted after the child process ends.
*/
on(event: 'exit', listener: (event: Electron.Event,
on(event: 'exit', listener: (
/**
* Contains the exit code for the process obtained from waitpid on posix, or
* GetExitCodeProcess on windows.
*/
code: number) => void): this;
once(event: 'exit', listener: (event: Electron.Event,
once(event: 'exit', listener: (
/**
* Contains the exit code for the process obtained from waitpid on posix, or
* GetExitCodeProcess on windows.
*/
code: number) => void): this;
addListener(event: 'exit', listener: (event: Electron.Event,
addListener(event: 'exit', listener: (
/**
* Contains the exit code for the process obtained from waitpid on posix, or
* GetExitCodeProcess on windows.
*/
code: number) => void): this;
removeListener(event: 'exit', listener: (event: Electron.Event,
removeListener(event: 'exit', listener: (
/**
* Contains the exit code for the process obtained from waitpid on posix, or
* GetExitCodeProcess on windows.
*/
code: number) => void): this;
/**
* Emitted when the child process sends a message using
* `process.parentPort.postMessage()`.
*/
on(event: 'message', listener: (event: Electron.Event,
message: any) => void): this;
once(event: 'message', listener: (event: Electron.Event,
message: any) => void): this;
addListener(event: 'message', listener: (event: Electron.Event,
message: any) => void): this;
removeListener(event: 'message', listener: (event: Electron.Event,
message: any) => void): this;
on(event: 'message', listener: (message: any) => void): this;
once(event: 'message', listener: (message: any) => void): this;
addListener(event: 'message', listener: (message: any) => void): this;
removeListener(event: 'message', listener: (message: any) => void): this;
/**
* Emitted once the child process has spawned successfully.
*/
Expand All @@ -93,13 +110,9 @@ declare namespace UtilityProcessProposedApi {
addListener(event: 'spawn', listener: Function): this;
removeListener(event: 'spawn', listener: Function): this;
/**
* UtilityProcess
*/
constructor(modulePath: string, args?: string[], options?: UtilityProcessConstructorOptions);
/**
* Terminates the process gracefully. On POSIX, it uses SIGTERM but will ensure to
* reap the process on exit. This function returns true if kill succeeds, and false
* otherwise.
* Terminates the process gracefully. On POSIX, it uses SIGTERM but will ensure the
* process is reaped on exit. This function returns true if the kill is successful,
* and false otherwise.
*/
kill(): boolean;
/**
Expand All @@ -112,26 +125,27 @@ declare namespace UtilityProcessProposedApi {
/**
* A `Integer | undefined` representing the process identifier (PID) of the child
* process. If the child process fails to spawn due to errors, then the value is
* `undefined`.
* `undefined`. When the child process exits, then the value is `undefined` after
* the `exit` event is emitted.
*/
pid: (number) | (undefined);
/**
* A `NodeJS.ReadableStream | null | undefined` that represents the child process's
* stderr. If the child was spawned with options.stdio[2] set to anything other
* than 'pipe', then this will be `null`. The property will be `undefined` if the
* child process could not be successfully spawned.
* A `NodeJS.ReadableStream | null` that represents the child process's stderr. If
* the child was spawned with options.stdio[2] set to anything other than 'pipe',
* then this will be `null`. When the child process exits, then the value is `null`
* after the `exit` event is emitted.
*/
stderr: (NodeJS.ReadableStream) | (null) | (undefined);
stderr: (NodeJS.ReadableStream) | (null);
/**
* A `NodeJS.ReadableStream | null | undefined` that represents the child process's
* stdout. If the child was spawned with options.stdio[1] set to anything other
* than 'pipe', then this will be `null`. The property will be `undefined` if the
* child process could not be successfully spawned.
* A `NodeJS.ReadableStream | null` that represents the child process's stdout. If
* the child was spawned with options.stdio[1] set to anything other than 'pipe',
* then this will be `null`. When the child process exits, then the value is `null`
* after the `exit` event is emitted.
*/
stdout: (NodeJS.ReadableStream) | (null) | (undefined);
stdout: (NodeJS.ReadableStream) | (null);
}
}
const UtilityProcess = <typeof UtilityProcessProposedApi.UtilityProcess>((electron as any).UtilityProcess);
const UtilityProcess = <typeof UtilityProcessProposedApi.UtilityProcess>((electron as any).utilityProcess);
const canUseUtilityProcess = (typeof UtilityProcess !== 'undefined');

export class ExtensionHostStarter implements IDisposable, IExtensionHostStarter {
Expand Down Expand Up @@ -425,6 +439,7 @@ class UtilityExtensionHostProcess extends Disposable {
const execArgv: string[] = opts.execArgv || [];
const env: { [key: string]: any } = { ...opts.env };
const allowLoadingUnsignedLibraries: boolean = true;
const stdio: (Array<'pipe' | 'ignore' | 'inherit'>) | (string) = 'pipe';

// Make sure all values are strings, otherwise the process will not start
for (const key of Object.keys(env)) {
Expand All @@ -433,7 +448,13 @@ class UtilityExtensionHostProcess extends Disposable {

this._logService.info(`UtilityProcess<${this.id}>: Creating new...`);

this._process = new UtilityProcess(modulePath, args, { serviceName, env, execArgv, allowLoadingUnsignedLibraries });
this._process = UtilityProcess.fork(modulePath, args, {
serviceName,
env,
execArgv,
allowLoadingUnsignedLibraries,
stdio
});

const stdoutDecoder = new StringDecoder('utf-8');
this._process.stdout?.on('data', (chunk) => {
Expand All @@ -454,7 +475,7 @@ class UtilityExtensionHostProcess extends Disposable {
this._register(Event.fromNodeEventEmitter<void>(this._process, 'spawn')(() => {
this._logService.info(`UtilityProcess<${this.id}>: received spawn event.`);
}));
const onExit = Event.fromNodeEventEmitter<number>(this._process, 'exit', (_, code: number) => code);
const onExit = Event.fromNodeEventEmitter<number>(this._process, 'exit', (code: number) => code);
this._register(onExit((code: number) => {
this._logService.info(`UtilityProcess<${this.id}>: received exit event with code ${code}.`);
this._hasExited = true;
Expand Down
28 changes: 20 additions & 8 deletions src/vs/workbench/api/node/extensionHostProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { boolean } from 'vs/editor/common/config/editorOptions';
import { createURITransformer } from 'vs/workbench/api/node/uriTransformer';
import { MessagePortMain } from 'electron';
import { ExtHostConnectionType, readExtHostConnection } from 'vs/workbench/services/extensions/common/extensionHostEnv';
import type { EventEmitter } from 'events';

import 'vs/workbench/api/common/extHost.common.services';
import 'vs/workbench/api/node/extHost.node.services';
Expand All @@ -35,6 +36,24 @@ interface ParsedExtHostArgs {
useHostProxy?: 'true' | 'false'; // use a string, as undefined is also a valid value
}

interface ParentPort extends EventEmitter {

// Docs: https://electronjs.org/docs/api/parent-port

/**
* Emitted when the process receives a message. Messages received on this port will
* be queued up until a handler is registered for this event.
*/
on(event: 'message', listener: (messageEvent: Electron.MessageEvent) => void): this;
once(event: 'message', listener: (messageEvent: Electron.MessageEvent) => void): this;
addListener(event: 'message', listener: (messageEvent: Electron.MessageEvent) => void): this;
removeListener(event: 'message', listener: (messageEvent: Electron.MessageEvent) => void): this;
/**
* Sends a message from the process to its parent.
*/
postMessage(message: any): void;
}

// workaround for https://github.com/microsoft/vscode/issues/85490
// remove --inspect-port=0 after start so that it doesn't trigger LSP debugging
(function removeInspectPort() {
Expand Down Expand Up @@ -132,14 +151,7 @@ function _createExtHostProtocol(): Promise<IMessagePassingProtocol> {
});
};

if ((<any>global).vscodePorts) {
const ports = (<any>global).vscodePorts;
delete (<any>global).vscodePorts;
withPorts(ports);
} else {
(<any>global).vscodePortsCallback = withPorts;
}

(process as NodeJS.Process & { parentPort: ParentPort })?.parentPort.on('message', (e: Electron.MessageEvent) => withPorts(e.ports));
});

} else if (extHostConnection.type === ExtHostConnectionType.Socket) {
Expand Down