Skip to content

Commit ce414a8

Browse files
committed
Implement terminal inheritEnv on remote
Fixes microsoft/vscode-remote-release#823
1 parent cefbf36 commit ce414a8

3 files changed

Lines changed: 86 additions & 75 deletions

File tree

src/vs/workbench/api/node/extHostTerminalService.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
2121
import { ExtHostVariableResolverService } from 'vs/workbench/api/node/extHostDebugService';
2222
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
2323
import { getSystemShell, detectAvailableShells } from 'vs/workbench/contrib/terminal/node/terminal';
24+
import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment';
2425

2526
const RENDERER_NO_PROCESS_ID = -1;
2627

@@ -522,6 +523,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
522523
const envFromConfig = this._apiInspectConfigToPlain(configProvider.getConfiguration('terminal.integrated').inspect<ITerminalEnvironment>(`env.${platformKey}`));
523524
const workspaceFolders = await this._extHostWorkspace.getWorkspaceFolders2();
524525
const variableResolver = workspaceFolders ? new ExtHostVariableResolverService(workspaceFolders, this._extHostDocumentsAndEditors, configProvider) : undefined;
526+
const baseEnv = terminalConfig.get<boolean>('inheritEnv', true) ? process.env as platform.IProcessEnvironment : await getMainProcessParentEnv();
525527
const env = terminalEnvironment.createTerminalEnvironment(
526528
shellLaunchConfig,
527529
lastActiveWorkspace,
@@ -530,9 +532,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
530532
isWorkspaceShellAllowed,
531533
pkg.version,
532534
terminalConfig.get<boolean>('setLocaleVariables', false),
533-
// Always inherit the environment as we need to be running in a login shell, this may
534-
// change when macOS servers are supported
535-
process.env as platform.IProcessEnvironment
535+
baseEnv
536536
);
537537

538538
// Fork the process and listen for messages

src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts

Lines changed: 4 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,16 @@ import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/
77
import { ITerminalInstance, IWindowsShellHelper, IShellLaunchConfig, ITerminalChildProcess, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY } from 'vs/workbench/contrib/terminal/common/terminal';
88
import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/node/windowsShellHelper';
99
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
10-
import { IProcessEnvironment, isLinux, isMacintosh, isWindows, platform, Platform } from 'vs/base/common/platform';
10+
import { IProcessEnvironment, platform, Platform } from 'vs/base/common/platform';
1111
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
1212
import { getSystemShell } from 'vs/workbench/contrib/terminal/node/terminal';
1313
import { Terminal as XTermTerminal } from 'xterm';
1414
import { WebLinksAddon as XTermWebLinksAddon } from 'xterm-addon-web-links';
1515
import { SearchAddon as XTermSearchAddon } from 'xterm-addon-search';
16-
import { readFile } from 'vs/base/node/pfs';
17-
import { basename } from 'vs/base/common/path';
1816
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
1917
import { getDefaultShell, getDefaultShellArgs } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
2018
import { StorageScope, IStorageService } from 'vs/platform/storage/common/storage';
19+
import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment';
2120

2221
let Terminal: typeof XTermTerminal;
2322
let WebLinksAddon: typeof XTermWebLinksAddon;
@@ -26,8 +25,6 @@ let SearchAddon: typeof XTermSearchAddon;
2625
export class TerminalInstanceService implements ITerminalInstanceService {
2726
public _serviceBrand: any;
2827

29-
private _mainProcessParentEnv: IProcessEnvironment | undefined;
30-
3128
constructor(
3229
@IInstantiationService private readonly _instantiationService: IInstantiationService,
3330
@IConfigurationService private readonly _configurationService: IConfigurationService,
@@ -86,72 +83,7 @@ export class TerminalInstanceService implements ITerminalInstanceService {
8683
return Promise.resolve({ shell, args });
8784
}
8885

89-
public async getMainProcessParentEnv(): Promise<IProcessEnvironment> {
90-
if (this._mainProcessParentEnv) {
91-
return this._mainProcessParentEnv;
92-
}
93-
94-
// For Linux use /proc/<pid>/status to get the parent of the main process and then fetch its
95-
// env using /proc/<pid>/environ.
96-
if (isLinux) {
97-
const mainProcessId = process.ppid;
98-
const codeProcessName = basename(process.argv[0]);
99-
let pid: number = 0;
100-
let ppid: number = mainProcessId;
101-
let name: string = codeProcessName;
102-
do {
103-
pid = ppid;
104-
const status = await readFile(`/proc/${pid}/status`, 'utf8');
105-
const splitByLine = status.split('\n');
106-
splitByLine.forEach(line => {
107-
if (line.indexOf('Name:') === 0) {
108-
name = line.replace(/^Name:\s+/, '');
109-
}
110-
if (line.indexOf('PPid:') === 0) {
111-
ppid = parseInt(line.replace(/^PPid:\s+/, ''));
112-
}
113-
});
114-
} while (name === codeProcessName);
115-
const rawEnv = await readFile(`/proc/${pid}/environ`, 'utf8');
116-
const env = {};
117-
rawEnv.split('\0').forEach(e => {
118-
const i = e.indexOf('=');
119-
env[e.substr(0, i)] = e.substr(i + 1);
120-
});
121-
this._mainProcessParentEnv = env;
122-
}
123-
124-
// For macOS we want the "root" environment as shells by default run as login shells. It
125-
// doesn't appear to be possible to get the "root" environment as `ps eww -o command` for
126-
// PID 1 (the parent of the main process when launched from the dock/finder) returns no
127-
// environment, because of this we will fill in the root environment using a whitelist of
128-
// environment variables that we have.
129-
if (isMacintosh) {
130-
this._mainProcessParentEnv = {};
131-
// This list was generated by diffing launching a terminal with {} and the system
132-
// terminal launched from finder.
133-
const rootEnvVars = [
134-
'SHELL',
135-
'SSH_AUTH_SOCK',
136-
'Apple_PubSub_Socket_Render',
137-
'XPC_FLAGS',
138-
'XPC_SERVICE_NAME',
139-
'HOME',
140-
'LOGNAME',
141-
'TMPDIR'
142-
];
143-
rootEnvVars.forEach(k => {
144-
if (process.env[k]) {
145-
this._mainProcessParentEnv![k] = process.env[k]!;
146-
}
147-
});
148-
}
149-
150-
// TODO: Windows should return a fresh environment block, might need native code?
151-
if (isWindows) {
152-
this._mainProcessParentEnv = process.env as IProcessEnvironment;
153-
}
154-
155-
return this._mainProcessParentEnv!;
86+
public getMainProcessParentEnv(): Promise<IProcessEnvironment> {
87+
return getMainProcessParentEnv();
15688
}
15789
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { IProcessEnvironment, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
7+
import { readFile } from 'vs/base/node/pfs';
8+
import { basename } from 'vs/base/common/path';
9+
10+
let mainProcessParentEnv: IProcessEnvironment | undefined;
11+
12+
export async function getMainProcessParentEnv(): Promise<IProcessEnvironment> {
13+
if (mainProcessParentEnv) {
14+
return mainProcessParentEnv;
15+
}
16+
17+
// For Linux use /proc/<pid>/status to get the parent of the main process and then fetch its
18+
// env using /proc/<pid>/environ.
19+
if (isLinux) {
20+
const mainProcessId = process.ppid;
21+
const codeProcessName = basename(process.argv[0]);
22+
let pid: number = 0;
23+
let ppid: number = mainProcessId;
24+
let name: string = codeProcessName;
25+
do {
26+
pid = ppid;
27+
const status = await readFile(`/proc/${pid}/status`, 'utf8');
28+
const splitByLine = status.split('\n');
29+
splitByLine.forEach(line => {
30+
if (line.indexOf('Name:') === 0) {
31+
name = line.replace(/^Name:\s+/, '');
32+
}
33+
if (line.indexOf('PPid:') === 0) {
34+
ppid = parseInt(line.replace(/^PPid:\s+/, ''));
35+
}
36+
});
37+
} while (name === codeProcessName);
38+
const rawEnv = await readFile(`/proc/${pid}/environ`, 'utf8');
39+
const env = {};
40+
rawEnv.split('\0').forEach(e => {
41+
const i = e.indexOf('=');
42+
env[e.substr(0, i)] = e.substr(i + 1);
43+
});
44+
mainProcessParentEnv = env;
45+
}
46+
47+
// For macOS we want the "root" environment as shells by default run as login shells. It
48+
// doesn't appear to be possible to get the "root" environment as `ps eww -o command` for
49+
// PID 1 (the parent of the main process when launched from the dock/finder) returns no
50+
// environment, because of this we will fill in the root environment using a whitelist of
51+
// environment variables that we have.
52+
if (isMacintosh) {
53+
mainProcessParentEnv = {};
54+
// This list was generated by diffing launching a terminal with {} and the system
55+
// terminal launched from finder.
56+
const rootEnvVars = [
57+
'SHELL',
58+
'SSH_AUTH_SOCK',
59+
'Apple_PubSub_Socket_Render',
60+
'XPC_FLAGS',
61+
'XPC_SERVICE_NAME',
62+
'HOME',
63+
'LOGNAME',
64+
'TMPDIR'
65+
];
66+
rootEnvVars.forEach(k => {
67+
if (process.env[k]) {
68+
mainProcessParentEnv![k] = process.env[k]!;
69+
}
70+
});
71+
}
72+
73+
// TODO: Windows should return a fresh environment block, might need native code?
74+
if (isWindows) {
75+
mainProcessParentEnv = process.env as IProcessEnvironment;
76+
}
77+
78+
return mainProcessParentEnv!;
79+
}

0 commit comments

Comments
 (0)