Revert "debug: pass environment via terminal API instead of command (#206376)" (#210097)

This reverts commit 6b6da7928d.

For #209693
This commit is contained in:
Connor Peet
2024-04-10 12:53:24 -07:00
committed by GitHub
parent 23915afd3b
commit d748e6abca
2 changed files with 46 additions and 15 deletions
@@ -27,7 +27,6 @@ import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/c
import type * as vscode from 'vscode';
import { ExtHostConfigProvider, IExtHostConfiguration } from '../common/extHostConfiguration';
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { createHash } from 'crypto';
export class ExtHostDebugService extends ExtHostDebugServiceBase {
@@ -90,8 +89,8 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
const terminalName = args.title || nls.localize('debug.terminal.title', "Debug Process");
const termKey = createKeyForShell(shell, shellArgs, args);
let terminal = await this._integratedTerminalInstances.checkout(termKey, terminalName, true);
const shellConfig = JSON.stringify({ shell, shellArgs });
let terminal = await this._integratedTerminalInstances.checkout(shellConfig, terminalName);
let cwdForPrepareCommand: string | undefined;
let giveShellTimeToInitialize = false;
@@ -103,7 +102,6 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
cwd: args.cwd,
name: terminalName,
iconPath: new ThemeIcon('debug'),
env: args.env,
};
giveShellTimeToInitialize = true;
terminal = this._terminalService.createTerminalFromOptions(options, {
@@ -113,7 +111,7 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
forceShellIntegration: true,
useShellEnvironment: true
});
this._integratedTerminalInstances.insert(terminal, termKey);
this._integratedTerminalInstances.insert(terminal, shellConfig);
} else {
cwdForPrepareCommand = args.cwd;
@@ -145,7 +143,7 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
}
}
const command = prepareCommand(shell, args.args, !!args.argsCanBeInterpretedByShell, cwdForPrepareCommand);
const command = prepareCommand(shell, args.args, !!args.argsCanBeInterpretedByShell, cwdForPrepareCommand, args.env);
terminal.sendText(command);
// Mark terminal as unused when its session ends, see #112055
@@ -165,14 +163,6 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
}
}
/** Creates a key that determines how terminals get reused */
function createKeyForShell(shell: string, shellArgs: string | string[], args: DebugProtocol.RunInTerminalRequestArguments) {
const hash = createHash('sha256');
hash.update(JSON.stringify({ shell, shellArgs }));
hash.update(JSON.stringify(Object.entries(args.env || {}).sort(([k1], [k2]) => k1.localeCompare(k2))));
return hash.digest('base64');
}
let externalTerminalService: IExternalTerminalService | undefined = undefined;
function runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestArguments, configProvider: ExtHostConfigProvider): Promise<number | undefined> {
@@ -56,7 +56,7 @@ export async function hasChildProcesses(processId: number | undefined): Promise<
const enum ShellType { cmd, powershell, bash }
export function prepareCommand(shell: string, args: string[], argsCanBeInterpretedByShell: boolean, cwd?: string): string {
export function prepareCommand(shell: string, args: string[], argsCanBeInterpretedByShell: boolean, cwd?: string, env?: { [key: string]: string | null }): string {
shell = shell.trim().toLowerCase();
@@ -97,6 +97,16 @@ export function prepareCommand(shell: string, args: string[], argsCanBeInterpret
}
command += `cd ${quote(cwd)}; `;
}
if (env) {
for (const key in env) {
const value = env[key];
if (value === null) {
command += `Remove-Item env:${key}; `;
} else {
command += `\${env:${key}}='${value}'; `;
}
}
}
if (args.length > 0) {
const arg = args.shift()!;
const cmd = argsCanBeInterpretedByShell ? arg : quote(arg);
@@ -127,10 +137,25 @@ export function prepareCommand(shell: string, args: string[], argsCanBeInterpret
}
command += `cd ${quote(cwd)} && `;
}
if (env) {
command += 'cmd /C "';
for (const key in env) {
let value = env[key];
if (value === null) {
command += `set "${key}=" && `;
} else {
value = value.replace(/[&^|<>]/g, s => `^${s}`);
command += `set "${key}=${value}" && `;
}
}
}
for (const a of args) {
command += (a === '<' || a === '>' || argsCanBeInterpretedByShell) ? a : quote(a);
command += ' ';
}
if (env) {
command += '"';
}
break;
case ShellType.bash: {
@@ -140,9 +165,25 @@ export function prepareCommand(shell: string, args: string[], argsCanBeInterpret
return s.length === 0 ? `""` : s;
};
const hardQuote = (s: string) => {
return /[^\w@%\/+=,.:^-]/.test(s) ? `'${s.replace(/'/g, '\'\\\'\'')}'` : s;
};
if (cwd) {
command += `cd ${quote(cwd)} ; `;
}
if (env) {
command += '/usr/bin/env';
for (const key in env) {
const value = env[key];
if (value === null) {
command += ` -u ${hardQuote(key)}`;
} else {
command += ` ${hardQuote(`${key}=${value}`)}`;
}
}
command += ' ';
}
for (const a of args) {
command += (a === '<' || a === '>' || argsCanBeInterpretedByShell) ? a : quote(a);
command += ' ';