Skip to content

Commit 1adb52c

Browse files
committed
Auto merge of #17549 - Veykril:runnables-fix, r=Veykril
fix: Fix runnables being incorrectly constructed I've misunderstood parts of the code here which caused runnables to arbitrarily break :) (I have yet to understand the conditions that made them break though, there is some odd caching involved I feel like ...) Fixes #17402
2 parents c888c0f + bb9678e commit 1adb52c

File tree

8 files changed

+223
-113
lines changed

8 files changed

+223
-113
lines changed

editors/code/package.json

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -333,14 +333,6 @@
333333
{
334334
"title": "general",
335335
"properties": {
336-
"rust-analyzer.cargoRunner": {
337-
"type": [
338-
"null",
339-
"string"
340-
],
341-
"default": null,
342-
"description": "Custom cargo runner extension ID."
343-
},
344336
"rust-analyzer.restartServerOnConfigChange": {
345337
"markdownDescription": "Whether to restart the server automatically when certain settings that require a restart are changed.",
346338
"default": false,

editors/code/src/bootstrap.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,20 @@ async function getServer(
3636
config: Config,
3737
state: PersistentState,
3838
): Promise<string | undefined> {
39+
const packageJson: {
40+
version: string;
41+
releaseTag: string | null;
42+
enableProposedApi: boolean | undefined;
43+
} = context.extension.packageJSON;
44+
3945
const explicitPath = process.env["__RA_LSP_SERVER_DEBUG"] ?? config.serverPath;
4046
if (explicitPath) {
4147
if (explicitPath.startsWith("~/")) {
4248
return os.homedir() + explicitPath.slice("~".length);
4349
}
4450
return explicitPath;
4551
}
46-
if (config.package.releaseTag === null) return "rust-analyzer";
52+
if (packageJson.releaseTag === null) return "rust-analyzer";
4753

4854
const ext = process.platform === "win32" ? ".exe" : "";
4955
const bundled = vscode.Uri.joinPath(context.extensionUri, "server", `rust-analyzer${ext}`);
@@ -54,8 +60,15 @@ async function getServer(
5460
if (bundledExists) {
5561
let server = bundled;
5662
if (await isNixOs()) {
57-
server = await getNixOsServer(config, ext, state, bundled, server);
58-
await state.updateServerVersion(config.package.version);
63+
server = await getNixOsServer(
64+
context.globalStorageUri,
65+
packageJson.version,
66+
ext,
67+
state,
68+
bundled,
69+
server,
70+
);
71+
await state.updateServerVersion(packageJson.version);
5972
}
6073
return server.fsPath;
6174
}
@@ -86,19 +99,20 @@ export function isValidExecutable(path: string, extraEnv: Env): boolean {
8699
}
87100

88101
async function getNixOsServer(
89-
config: Config,
102+
globalStorageUri: vscode.Uri,
103+
version: string,
90104
ext: string,
91105
state: PersistentState,
92106
bundled: vscode.Uri,
93107
server: vscode.Uri,
94108
) {
95-
await vscode.workspace.fs.createDirectory(config.globalStorageUri).then();
96-
const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer${ext}`);
109+
await vscode.workspace.fs.createDirectory(globalStorageUri).then();
110+
const dest = vscode.Uri.joinPath(globalStorageUri, `rust-analyzer${ext}`);
97111
let exists = await vscode.workspace.fs.stat(dest).then(
98112
() => true,
99113
() => false,
100114
);
101-
if (exists && config.package.version !== state.serverVersion) {
115+
if (exists && version !== state.serverVersion) {
102116
await vscode.workspace.fs.delete(dest);
103117
exists = false;
104118
}

editors/code/src/config.ts

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as path from "path";
44
import * as vscode from "vscode";
55
import { type Env, log, unwrapUndefinable, expectNotUndefined } from "./util";
66
import type { JsonProject } from "./rust_project";
7+
import type { Disposable } from "./ctx";
78

89
export type RunnableEnvCfgItem = {
910
mask?: string;
@@ -29,22 +30,9 @@ export class Config {
2930
(opt) => `${this.rootSection}.${opt}`,
3031
);
3132

32-
readonly package: {
33-
version: string;
34-
releaseTag: string | null;
35-
enableProposedApi: boolean | undefined;
36-
} = vscode.extensions.getExtension(this.extensionId)!.packageJSON;
37-
38-
readonly globalStorageUri: vscode.Uri;
39-
40-
constructor(ctx: vscode.ExtensionContext) {
41-
this.globalStorageUri = ctx.globalStorageUri;
33+
constructor(disposables: Disposable[]) {
4234
this.discoveredWorkspaces = [];
43-
vscode.workspace.onDidChangeConfiguration(
44-
this.onDidChangeConfiguration,
45-
this,
46-
ctx.subscriptions,
47-
);
35+
vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, disposables);
4836
this.refreshLogging();
4937
this.configureLanguage();
5038
}
@@ -55,7 +43,10 @@ export class Config {
5543

5644
private refreshLogging() {
5745
log.setEnabled(this.traceExtension ?? false);
58-
log.info("Extension version:", this.package.version);
46+
log.info(
47+
"Extension version:",
48+
vscode.extensions.getExtension(this.extensionId)!.packageJSON.version,
49+
);
5950

6051
const cfg = Object.entries(this.cfg).filter(([_, val]) => !(val instanceof Function));
6152
log.info("Using configuration", Object.fromEntries(cfg));
@@ -277,10 +268,6 @@ export class Config {
277268
return this.get<string[]>("runnables.problemMatcher") || [];
278269
}
279270

280-
get cargoRunner() {
281-
return this.get<string | undefined>("cargoRunner");
282-
}
283-
284271
get testExplorer() {
285272
return this.get<boolean | undefined>("testExplorer");
286273
}

editors/code/src/ctx.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export class Ctx implements RustAnalyzerExtensionApi {
118118
extCtx.subscriptions.push(this);
119119
this.version = extCtx.extension.packageJSON.version ?? "<unknown>";
120120
this._serverVersion = "<not running>";
121-
this.config = new Config(extCtx);
121+
this.config = new Config(extCtx.subscriptions);
122122
this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
123123
if (this.config.testExplorer) {
124124
this.testController = vscode.tests.createTestController(

editors/code/src/run.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,26 +111,31 @@ export async function createTaskFromRunnable(
111111
runnable: ra.Runnable,
112112
config: Config,
113113
): Promise<vscode.Task> {
114-
let definition: tasks.RustTargetDefinition;
114+
const target = vscode.workspace.workspaceFolders?.[0];
115+
116+
let definition: tasks.TaskDefinition;
117+
let options;
118+
let cargo;
115119
if (runnable.kind === "cargo") {
116120
const runnableArgs = runnable.args;
117121
let args = createCargoArgs(runnableArgs);
118122

119-
let program: string;
120123
if (runnableArgs.overrideCargo) {
121124
// Split on spaces to allow overrides like "wrapper cargo".
122125
const cargoParts = runnableArgs.overrideCargo.split(" ");
123126

124-
program = unwrapUndefinable(cargoParts[0]);
127+
cargo = unwrapUndefinable(cargoParts[0]);
125128
args = [...cargoParts.slice(1), ...args];
126129
} else {
127-
program = await toolchain.cargoPath();
130+
cargo = await toolchain.cargoPath();
128131
}
129132

130133
definition = {
131134
type: tasks.CARGO_TASK_TYPE,
132-
command: program,
133-
args,
135+
command: unwrapUndefinable(args[0]),
136+
args: args.slice(1),
137+
};
138+
options = {
134139
cwd: runnableArgs.workspaceRoot || ".",
135140
env: prepareEnv(runnable.label, runnableArgs, config.runnablesExtraEnv),
136141
};
@@ -140,13 +145,14 @@ export async function createTaskFromRunnable(
140145
type: tasks.SHELL_TASK_TYPE,
141146
command: runnableArgs.program,
142147
args: runnableArgs.args,
148+
};
149+
options = {
143150
cwd: runnableArgs.cwd,
144151
env: prepareBaseEnv(),
145152
};
146153
}
147154

148-
const target = vscode.workspace.workspaceFolders?.[0];
149-
const exec = await tasks.targetToExecution(definition, config.cargoRunner, true);
155+
const exec = await tasks.targetToExecution(definition, options, cargo);
150156
const task = await tasks.buildRustTask(
151157
target,
152158
definition,

editors/code/src/tasks.ts

Lines changed: 37 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as vscode from "vscode";
22
import type { Config } from "./config";
3-
import { log, unwrapUndefinable } from "./util";
43
import * as toolchain from "./toolchain";
54

65
// This ends up as the `type` key in tasks.json. RLS also uses `cargo` and
@@ -10,21 +9,21 @@ export const SHELL_TASK_TYPE = "shell";
109

1110
export const RUST_TASK_SOURCE = "rust";
1211

13-
export type RustTargetDefinition = {
12+
export type TaskDefinition = vscode.TaskDefinition & {
1413
readonly type: typeof CARGO_TASK_TYPE | typeof SHELL_TASK_TYPE;
15-
} & vscode.TaskDefinition &
16-
RustTarget;
17-
export type RustTarget = {
18-
// The command to run, usually `cargo`.
19-
command: string;
20-
// Additional arguments passed to the command.
2114
args?: string[];
22-
// The working directory to run the command in.
23-
cwd?: string;
24-
// The shell environment.
25-
env?: { [key: string]: string };
15+
command: string;
2616
};
2717

18+
export type CargoTaskDefinition = {
19+
env?: Record<string, string>;
20+
type: typeof CARGO_TASK_TYPE;
21+
} & TaskDefinition;
22+
23+
function isCargoTask(definition: vscode.TaskDefinition): definition is CargoTaskDefinition {
24+
return definition.type === CARGO_TASK_TYPE;
25+
}
26+
2827
class RustTaskProvider implements vscode.TaskProvider {
2928
private readonly config: Config;
3029

@@ -58,13 +57,13 @@ class RustTaskProvider implements vscode.TaskProvider {
5857
for (const workspaceTarget of vscode.workspace.workspaceFolders) {
5958
for (const def of defs) {
6059
const definition = {
61-
command: cargo,
62-
args: [def.command],
63-
};
64-
const exec = await targetToExecution(definition, this.config.cargoRunner);
60+
command: def.command,
61+
type: CARGO_TASK_TYPE,
62+
} as const;
63+
const exec = await targetToExecution(definition, {}, cargo);
6564
const vscodeTask = await buildRustTask(
6665
workspaceTarget,
67-
{ ...definition, type: CARGO_TASK_TYPE },
66+
definition,
6867
`cargo ${def.command}`,
6968
this.config.problemMatcher,
7069
exec,
@@ -81,23 +80,13 @@ class RustTaskProvider implements vscode.TaskProvider {
8180
// VSCode calls this for every cargo task in the user's tasks.json,
8281
// we need to inform VSCode how to execute that command by creating
8382
// a ShellExecution for it.
84-
if (task.definition.type === CARGO_TASK_TYPE) {
85-
const taskDefinition = task.definition as RustTargetDefinition;
86-
const cargo = await toolchain.cargoPath();
87-
const exec = await targetToExecution(
88-
{
89-
command: cargo,
90-
args: [taskDefinition.command].concat(taskDefinition.args || []),
91-
cwd: taskDefinition.cwd,
92-
env: taskDefinition.env,
93-
},
94-
this.config.cargoRunner,
95-
);
96-
return await buildRustTask(
83+
if (isCargoTask(task.definition)) {
84+
const exec = await targetToExecution(task.definition, { env: task.definition.env });
85+
return buildRustTask(
9786
task.scope,
98-
taskDefinition,
87+
task.definition,
9988
task.name,
100-
this.config.problemMatcher,
89+
task.problemMatchers,
10190
exec,
10291
);
10392
}
@@ -108,7 +97,7 @@ class RustTaskProvider implements vscode.TaskProvider {
10897

10998
export async function buildRustTask(
11099
scope: vscode.WorkspaceFolder | vscode.TaskScope | undefined,
111-
definition: RustTargetDefinition,
100+
definition: TaskDefinition,
112101
name: string,
113102
problemMatcher: string[],
114103
exec: vscode.ProcessExecution | vscode.ShellExecution,
@@ -126,40 +115,23 @@ export async function buildRustTask(
126115
}
127116

128117
export async function targetToExecution(
129-
definition: RustTarget,
130-
customRunner?: string,
131-
throwOnError: boolean = false,
118+
definition: TaskDefinition,
119+
options?: {
120+
env?: { [key: string]: string };
121+
cwd?: string;
122+
},
123+
cargo?: string,
132124
): Promise<vscode.ProcessExecution | vscode.ShellExecution> {
133-
if (customRunner) {
134-
const runnerCommand = `${customRunner}.buildShellExecution`;
135-
136-
try {
137-
const runnerArgs = {
138-
kind: CARGO_TASK_TYPE,
139-
args: definition.args,
140-
cwd: definition.cwd,
141-
env: definition.env,
142-
};
143-
const customExec = await vscode.commands.executeCommand(runnerCommand, runnerArgs);
144-
if (customExec) {
145-
if (customExec instanceof vscode.ShellExecution) {
146-
return customExec;
147-
} else {
148-
log.debug("Invalid cargo ShellExecution", customExec);
149-
throw "Invalid cargo ShellExecution.";
150-
}
151-
}
152-
// fallback to default processing
153-
} catch (e) {
154-
if (throwOnError) throw `Cargo runner '${customRunner}' failed! ${e}`;
155-
// fallback to default processing
156-
}
125+
let command, args;
126+
if (isCargoTask(definition)) {
127+
// FIXME: The server should provide cargo
128+
command = cargo || (await toolchain.cargoPath());
129+
args = [definition.command].concat(definition.args || []);
130+
} else {
131+
command = definition.command;
132+
args = definition.args || [];
157133
}
158-
const args = unwrapUndefinable(definition.args);
159-
return new vscode.ProcessExecution(definition.command, args, {
160-
cwd: definition.cwd,
161-
env: definition.env,
162-
});
134+
return new vscode.ProcessExecution(command, args, options);
163135
}
164136

165137
export function activateTaskProvider(config: Config): vscode.Disposable {

editors/code/tests/unit/settings.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export async function getTests(ctx: Context) {
1313
USING_MY_VAR: "test test test",
1414
MY_VAR: "test",
1515
};
16-
const actualEnv = await substituteVariablesInEnv(envJson);
16+
const actualEnv = substituteVariablesInEnv(envJson);
1717
assert.deepStrictEqual(actualEnv, expectedEnv);
1818
});
1919

@@ -34,7 +34,7 @@ export async function getTests(ctx: Context) {
3434
E_IS_ISOLATED: "test",
3535
F_USES_E: "test",
3636
};
37-
const actualEnv = await substituteVariablesInEnv(envJson);
37+
const actualEnv = substituteVariablesInEnv(envJson);
3838
assert.deepStrictEqual(actualEnv, expectedEnv);
3939
});
4040

@@ -47,7 +47,7 @@ export async function getTests(ctx: Context) {
4747
USING_EXTERNAL_VAR: "test test test",
4848
};
4949

50-
const actualEnv = await substituteVariablesInEnv(envJson);
50+
const actualEnv = substituteVariablesInEnv(envJson);
5151
assert.deepStrictEqual(actualEnv, expectedEnv);
5252
delete process.env["TEST_VARIABLE"];
5353
});
@@ -56,7 +56,7 @@ export async function getTests(ctx: Context) {
5656
const envJson = {
5757
USING_VSCODE_VAR: "${workspaceFolderBasename}",
5858
};
59-
const actualEnv = await substituteVariablesInEnv(envJson);
59+
const actualEnv = substituteVariablesInEnv(envJson);
6060
assert.deepStrictEqual(actualEnv["USING_VSCODE_VAR"], "code");
6161
});
6262
});

0 commit comments

Comments
 (0)