Unnamed repository; edit this file 'description' to name the repository.
fix: Fix runnables extra env not substituting env vars
Lukas Wirth 9 months ago
parent 7a62181 · commit 92d5615
-rw-r--r--editors/code/src/config.ts45
-rw-r--r--editors/code/src/debug.ts24
-rw-r--r--editors/code/src/run.ts14
-rw-r--r--editors/code/src/tasks.ts12
-rw-r--r--editors/code/src/toolchain.ts8
5 files changed, 53 insertions, 50 deletions
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index d2dc740c09..cadab37f51 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -8,10 +8,9 @@ import type { Disposable } from "vscode";
export type RunnableEnvCfgItem = {
mask?: string;
- env: Record<string, string>;
+ env: { [key: string]: { toString(): string } | null };
platform?: string | string[];
};
-export type RunnableEnvCfg = Record<string, string> | RunnableEnvCfgItem[];
type ShowStatusBar = "always" | "never" | { documentSelector: vscode.DocumentSelector };
@@ -261,18 +260,9 @@ export class Config {
return this.get<boolean | undefined>("testExplorer");
}
- runnablesExtraEnv(label: string): Record<string, string> | undefined {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const item = this.get<any>("runnables.extraEnv") ?? this.get<any>("runnableEnv");
- if (!item) return undefined;
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const fixRecord = (r: Record<string, any>) => {
- for (const key in r) {
- if (typeof r[key] !== "string") {
- r[key] = String(r[key]);
- }
- }
- };
+ runnablesExtraEnv(label: string): Env {
+ let extraEnv = this.get<RunnableEnvCfgItem[] | { [key: string]: { toString(): string } | null } | null>("runnables.extraEnv") ?? {};
+ if (!extraEnv) return {};
const platform = process.platform;
const checkPlatform = (it: RunnableEnvCfgItem) => {
@@ -283,19 +273,24 @@ export class Config {
return true;
};
- if (item instanceof Array) {
+ if (extraEnv instanceof Array) {
const env = {};
- for (const it of item) {
+ for (const it of extraEnv) {
const masked = !it.mask || new RegExp(it.mask).test(label);
if (masked && checkPlatform(it)) {
Object.assign(env, it.env);
}
}
- fixRecord(env);
- return env;
+ extraEnv = env;
}
- fixRecord(item);
- return item;
+ return substituteVariablesInEnv(
+ Object.fromEntries(
+ Object.entries(extraEnv).map(([k, v]) => [
+ k,
+ typeof v === "string" ? v : v?.toString(),
+ ]),
+ ),
+ );
}
get restartServerOnConfigChange() {
@@ -490,11 +485,11 @@ function computeVscodeVar(varName: string): string | null {
folder === undefined
? "" // no workspace opened
: // could use currently opened document to detect the correct
- // workspace. However, that would be determined by the document
- // user has opened on Editor startup. Could lead to
- // unpredictable workspace selection in practice.
- // It's better to pick the first one
- normalizeDriveLetter(folder.uri.fsPath);
+ // workspace. However, that would be determined by the document
+ // user has opened on Editor startup. Could lead to
+ // unpredictable workspace selection in practice.
+ // It's better to pick the first one
+ normalizeDriveLetter(folder.uri.fsPath);
return fsPath;
};
// https://code.visualstudio.com/docs/editor/variables-reference
diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts
index adb75c23c7..9559fe16f5 100644
--- a/editors/code/src/debug.ts
+++ b/editors/code/src/debug.ts
@@ -6,7 +6,7 @@ import type * as ra from "./lsp_ext";
import { Cargo } from "./toolchain";
import type { Ctx } from "./ctx";
import { createTaskFromRunnable, prepareEnv } from "./run";
-import { execute, isCargoRunnableArgs, unwrapUndefinable, log, normalizeDriveLetter } from "./util";
+import { execute, isCargoRunnableArgs, unwrapUndefinable, log, normalizeDriveLetter, Env } from "./util";
import type { Config } from "./config";
// Here we want to keep track on everything that's currently running
@@ -108,9 +108,9 @@ async function getDebugConfiguration(
await vscode.window.showErrorMessage(
`Install [CodeLLDB](command:${commandCodeLLDB} "Open CodeLLDB")` +
- `, [lldb-dap](command:${commandLLDBDap} "Open lldb-dap")` +
- `, [C/C++](command:${commandCCpp} "Open C/C++") ` +
- `or [Native Debug](command:${commandNativeDebug} "Open Native Debug") for debugging.`,
+ `, [lldb-dap](command:${commandLLDBDap} "Open lldb-dap")` +
+ `, [C/C++](command:${commandCCpp} "Open C/C++") ` +
+ `or [Native Debug](command:${commandNativeDebug} "Open Native Debug") for debugging.`,
);
return;
}
@@ -124,7 +124,7 @@ async function getDebugConfiguration(
!isMultiFolderWorkspace || !runnableArgs.workspaceRoot
? firstWorkspace
: workspaceFolders.find((w) => runnableArgs.workspaceRoot?.includes(w.uri.fsPath)) ||
- firstWorkspace;
+ firstWorkspace;
const workspace = unwrapUndefinable(maybeWorkspace);
const wsFolder = normalizeDriveLetter(path.normalize(workspace.uri.fsPath));
@@ -207,7 +207,7 @@ type SourceFileMap = {
};
async function discoverSourceFileMap(
- env: Record<string, string>,
+ env: Env,
cwd: string,
): Promise<SourceFileMap | undefined> {
const sysroot = env["RUSTC_TOOLCHAIN"];
@@ -232,7 +232,7 @@ type PropertyFetcher<Config, Input, Key extends keyof Config> = (
type DebugConfigProvider<Type extends string, DebugConfig extends BaseDebugConfig<Type>> = {
executableProperty: keyof DebugConfig;
- environmentProperty: PropertyFetcher<DebugConfig, Record<string, string>, keyof DebugConfig>;
+ environmentProperty: PropertyFetcher<DebugConfig, Env, keyof DebugConfig>;
runnableArgsProperty: PropertyFetcher<DebugConfig, ra.CargoRunnableArgs, keyof DebugConfig>;
sourceFileMapProperty?: keyof DebugConfig;
type: Type;
@@ -276,7 +276,7 @@ const knownEngines: {
"environment",
Object.entries(env).map((entry) => ({
name: entry[0],
- value: entry[1],
+ value: entry[1] ?? "",
})),
],
runnableArgsProperty: (runnableArgs: ra.CargoRunnableArgs) => [
@@ -306,7 +306,7 @@ const knownEngines: {
async function getDebugExecutable(
runnableArgs: ra.CargoRunnableArgs,
- env: Record<string, string>,
+ env: Env,
): Promise<string> {
const cargo = new Cargo(runnableArgs.workspaceRoot || ".", env);
const executable = await cargo.executableFromArgs(runnableArgs);
@@ -328,7 +328,7 @@ function getDebugConfig(
runnable: ra.Runnable,
runnableArgs: ra.CargoRunnableArgs,
executable: string,
- env: Record<string, string>,
+ env: Env,
sourceFileMap?: Record<string, string>,
): vscode.DebugConfiguration {
const {
@@ -380,14 +380,14 @@ type CodeLldbDebugConfig = {
args: string[];
sourceMap: Record<string, string> | undefined;
sourceLanguages: ["rust"];
- env: Record<string, string>;
+ env: Env;
} & BaseDebugConfig<"lldb">;
type NativeDebugConfig = {
target: string;
// See https://github.com/WebFreak001/code-debug/issues/359
arguments: string;
- env: Record<string, string>;
+ env: Env;
valuesFormatting: "prettyPrinters";
} & BaseDebugConfig<"gdb">;
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts
index 95166c427b..bed874705d 100644
--- a/editors/code/src/run.ts
+++ b/editors/code/src/run.ts
@@ -7,7 +7,7 @@ import type { CtxInit } from "./ctx";
import { makeDebugConfig } from "./debug";
import type { Config } from "./config";
import type { LanguageClient } from "vscode-languageclient/node";
-import { log, unwrapUndefinable, type RustEditor } from "./util";
+import { Env, log, unwrapUndefinable, type RustEditor } from "./util";
const quickPickButtons = [
{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." },
@@ -124,9 +124,9 @@ export class RunnableQuickPick implements vscode.QuickPickItem {
export function prepareBaseEnv(
inheritEnv: boolean,
- base?: Record<string, string>,
-): Record<string, string> {
- const env: Record<string, string> = { RUST_BACKTRACE: "short" };
+ base?: Env,
+): Env {
+ const env: Env = { RUST_BACKTRACE: "short" };
if (inheritEnv) {
Object.assign(env, process.env);
}
@@ -138,9 +138,9 @@ export function prepareBaseEnv(
export function prepareEnv(
inheritEnv: boolean,
- runnableEnv?: Record<string, string>,
- runnableEnvCfg?: Record<string, string>,
-): Record<string, string> {
+ runnableEnv?: Env,
+ runnableEnvCfg?: Env,
+): Env {
const env = prepareBaseEnv(inheritEnv, runnableEnv);
if (runnableEnvCfg) {
diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts
index 730ec6d1e9..417c28f0ee 100644
--- a/editors/code/src/tasks.ts
+++ b/editors/code/src/tasks.ts
@@ -1,6 +1,7 @@
import * as vscode from "vscode";
import type { Config } from "./config";
import * as toolchain from "./toolchain";
+import { Env } from "./util";
// This ends up as the `type` key in tasks.json. RLS also uses `cargo` and
// our configuration should be compatible with it so use the same key.
@@ -117,8 +118,8 @@ export async function buildRustTask(
export async function targetToExecution(
definition: TaskDefinition,
options?: {
- env?: { [key: string]: string };
cwd?: string;
+ env?: Env;
},
cargo?: string,
): Promise<vscode.ProcessExecution | vscode.ShellExecution> {
@@ -131,7 +132,14 @@ export async function targetToExecution(
command = definition.command;
args = definition.args || [];
}
- return new vscode.ProcessExecution(command, args, options);
+ return new vscode.ProcessExecution(command, args, {
+ cwd: options?.cwd,
+ env:
+ Object.fromEntries(
+ Object.entries(options?.env ?? {}).map(([key, value]) => [key, value ?? ""])
+ )
+ ,
+ });
}
export function activateTaskProvider(config: Config): vscode.Disposable {
diff --git a/editors/code/src/toolchain.ts b/editors/code/src/toolchain.ts
index a859ce6ff0..f64dec2ccf 100644
--- a/editors/code/src/toolchain.ts
+++ b/editors/code/src/toolchain.ts
@@ -3,7 +3,7 @@ import * as os from "os";
import * as path from "path";
import * as readline from "readline";
import * as vscode from "vscode";
-import { log, memoizeAsync, unwrapUndefinable } from "./util";
+import { Env, log, memoizeAsync, unwrapUndefinable } from "./util";
import type { CargoRunnableArgs } from "./lsp_ext";
interface CompilationArtifact {
@@ -37,8 +37,8 @@ interface CompilerMessage {
export class Cargo {
constructor(
readonly rootFolder: string,
- readonly env: Record<string, string>,
- ) {}
+ readonly env: Env,
+ ) { }
// Made public for testing purposes
static artifactSpec(cargoArgs: string[], executableArgs?: string[]): ArtifactSpec {
@@ -156,7 +156,7 @@ export class Cargo {
/** Mirrors `toolchain::cargo()` implementation */
// FIXME: The server should provide this
-export function cargoPath(env?: Record<string, string>): Promise<string> {
+export function cargoPath(env?: Env): Promise<string> {
if (env?.["RUSTC_TOOLCHAIN"]) {
return Promise.resolve("cargo");
}