Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #17605 - Veykril:runnable-sysroot, r=Veykril
Set `RUSTC_TOOLCHAIN` for runnables With this the client doesn't necessarily need to guess the sysroot anymore
bors 2024-07-16
parent 566f927 · parent 33ce9a4 · commit 41dcb2d
-rw-r--r--crates/rust-analyzer/src/global_state.rs1
-rw-r--r--crates/rust-analyzer/src/handlers/request.rs17
-rw-r--r--crates/rust-analyzer/src/lsp/to_proto.rs6
-rw-r--r--crates/rust-analyzer/src/target_spec.rs1
-rw-r--r--editors/code/src/debug.ts31
-rw-r--r--editors/code/src/run.ts7
-rw-r--r--editors/code/src/tasks.ts2
-rw-r--r--editors/code/src/toolchain.ts37
8 files changed, 59 insertions, 43 deletions
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index de4c9586df..1976e4de30 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -579,6 +579,7 @@ impl GlobalStateSnapshot {
target_kind: target_data.kind,
required_features: target_data.required_features.clone(),
features: package_data.features.keys().cloned().collect(),
+ sysroot_root: workspace.sysroot.root().map(ToOwned::to_owned),
}));
}
ProjectWorkspaceKind::Json(project) => {
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index e19f7a4898..8996143114 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -50,7 +50,7 @@ use crate::{
self, CrateInfoResult, ExternalDocsPair, ExternalDocsResponse, FetchDependencyListParams,
FetchDependencyListResult, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams,
},
- target_spec::TargetSpec,
+ target_spec::{CargoTargetSpec, TargetSpec},
};
pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
@@ -848,6 +848,14 @@ pub(crate) fn handle_runnables(
if let lsp_ext::RunnableArgs::Cargo(r) = &mut runnable.args {
runnable.label = format!("{} + expect", runnable.label);
r.environment.insert("UPDATE_EXPECT".to_owned(), "1".to_owned());
+ if let Some(TargetSpec::Cargo(CargoTargetSpec {
+ sysroot_root: Some(sysroot_root),
+ ..
+ })) = &target_spec
+ {
+ r.environment
+ .insert("RUSTC_TOOLCHAIN".to_owned(), sysroot_root.to_string());
+ }
}
}
res.push(runnable);
@@ -889,7 +897,12 @@ pub(crate) fn handle_runnables(
override_cargo: config.override_cargo.clone(),
cargo_args,
executable_args: Vec::new(),
- environment: Default::default(),
+ environment: spec
+ .sysroot_root
+ .as_ref()
+ .map(|root| ("RUSTC_TOOLCHAIN".to_owned(), root.to_string()))
+ .into_iter()
+ .collect(),
}),
})
}
diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs
index 323926e435..cb9b141002 100644
--- a/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -1399,7 +1399,11 @@ pub(crate) fn runnable(
cargo_args,
cwd: cwd.into(),
executable_args,
- environment: Default::default(),
+ environment: spec
+ .sysroot_root
+ .map(|root| ("RUSTC_TOOLCHAIN".to_owned(), root.to_string()))
+ .into_iter()
+ .collect(),
}),
}))
}
diff --git a/crates/rust-analyzer/src/target_spec.rs b/crates/rust-analyzer/src/target_spec.rs
index 045b9e4198..162faa5619 100644
--- a/crates/rust-analyzer/src/target_spec.rs
+++ b/crates/rust-analyzer/src/target_spec.rs
@@ -57,6 +57,7 @@ pub(crate) struct CargoTargetSpec {
pub(crate) crate_id: CrateId,
pub(crate) required_features: Vec<String>,
pub(crate) features: FxHashSet<String>,
+ pub(crate) sysroot_root: Option<vfs::AbsPathBuf>,
}
#[derive(Clone, Debug)]
diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts
index f23e368093..d9622b4a0d 100644
--- a/editors/code/src/debug.ts
+++ b/editors/code/src/debug.ts
@@ -3,10 +3,10 @@ import * as vscode from "vscode";
import * as path from "path";
import type * as ra from "./lsp_ext";
-import { Cargo, getRustcId, getSysroot } from "./toolchain";
+import { Cargo } from "./toolchain";
import type { Ctx } from "./ctx";
import { prepareEnv } from "./run";
-import { isCargoRunnableArgs, unwrapUndefinable } from "./util";
+import { execute, isCargoRunnableArgs, unwrapUndefinable } from "./util";
const debugOutput = vscode.window.createOutputChannel("Debug");
type DebugConfigProvider = (
@@ -142,18 +142,29 @@ async function getDebugConfiguration(
const executable = await getDebugExecutable(runnableArgs, env);
let sourceFileMap = debugOptions.sourceFileMap;
if (sourceFileMap === "auto") {
- // let's try to use the default toolchain
- const [commitHash, sysroot] = await Promise.all([
- getRustcId(wsFolder),
- getSysroot(wsFolder),
- ]);
- const rustlib = path.normalize(sysroot + "/lib/rustlib/src/rust");
sourceFileMap = {};
- sourceFileMap[`/rustc/${commitHash}/`] = rustlib;
+ const sysroot = env["RUSTC_TOOLCHAIN"];
+ if (sysroot) {
+ // let's try to use the default toolchain
+ const data = await execute(`rustc -V -v`, { cwd: wsFolder, env });
+ const rx = /commit-hash:\s(.*)$/m;
+
+ const commitHash = rx.exec(data)?.[1];
+ if (commitHash) {
+ const rustlib = path.normalize(sysroot + "/lib/rustlib/src/rust");
+ sourceFileMap[`/rustc/${commitHash}/`] = rustlib;
+ }
+ }
}
const provider = unwrapUndefinable(knownEngines[debugEngine.id]);
- const debugConfig = provider(runnable, runnableArgs, simplifyPath(executable), env);
+ const debugConfig = provider(
+ runnable,
+ runnableArgs,
+ simplifyPath(executable),
+ env,
+ sourceFileMap,
+ );
if (debugConfig.type in debugOptions.engineSettings) {
const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type];
for (var key in settingsMap) {
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts
index 783bbc1607..7179eb3744 100644
--- a/editors/code/src/run.ts
+++ b/editors/code/src/run.ts
@@ -8,7 +8,6 @@ import { makeDebugConfig } from "./debug";
import type { Config, RunnableEnvCfg, RunnableEnvCfgItem } from "./config";
import type { LanguageClient } from "vscode-languageclient/node";
import { unwrapUndefinable, type RustEditor } from "./util";
-import * as toolchain from "./toolchain";
const quickPickButtons = [
{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." },
@@ -115,7 +114,7 @@ export async function createTaskFromRunnable(
let definition: tasks.TaskDefinition;
let options;
- let cargo;
+ let cargo = "cargo";
if (runnable.kind === "cargo") {
const runnableArgs = runnable.args;
let args = createCargoArgs(runnableArgs);
@@ -126,8 +125,6 @@ export async function createTaskFromRunnable(
cargo = unwrapUndefinable(cargoParts[0]);
args = [...cargoParts.slice(1), ...args];
- } else {
- cargo = await toolchain.cargoPath();
}
definition = {
@@ -200,7 +197,7 @@ async function getRunnables(
continue;
}
- if (debuggeeOnly && (r.label.startsWith("doctest") || r.label.startsWith("cargo"))) {
+ if (debuggeeOnly && r.label.startsWith("doctest")) {
continue;
}
items.push(new RunnableQuickPick(r));
diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts
index fac1cc6394..730ec6d1e9 100644
--- a/editors/code/src/tasks.ts
+++ b/editors/code/src/tasks.ts
@@ -125,7 +125,7 @@ export async function targetToExecution(
let command, args;
if (isCargoTask(definition)) {
// FIXME: The server should provide cargo
- command = cargo || (await toolchain.cargoPath());
+ command = cargo || (await toolchain.cargoPath(options?.env));
args = [definition.command].concat(definition.args || []);
} else {
command = definition.command;
diff --git a/editors/code/src/toolchain.ts b/editors/code/src/toolchain.ts
index 6a0b5c26d8..850a6a5561 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 { execute, log, memoizeAsync, unwrapNullable, unwrapUndefinable } from "./util";
+import { log, memoizeAsync, unwrapUndefinable } from "./util";
import type { CargoRunnableArgs } from "./lsp_ext";
interface CompilationArtifact {
@@ -55,7 +55,10 @@ export class Cargo {
return result;
}
- private async getArtifacts(spec: ArtifactSpec): Promise<CompilationArtifact[]> {
+ private async getArtifacts(
+ spec: ArtifactSpec,
+ env?: Record<string, string>,
+ ): Promise<CompilationArtifact[]> {
const artifacts: CompilationArtifact[] = [];
try {
@@ -78,6 +81,7 @@ export class Cargo {
}
},
(stderr) => this.output.append(stderr),
+ env,
);
} catch (err) {
this.output.show(true);
@@ -90,6 +94,7 @@ export class Cargo {
async executableFromArgs(runnableArgs: CargoRunnableArgs): Promise<string> {
const artifacts = await this.getArtifacts(
Cargo.artifactSpec(runnableArgs.cargoArgs, runnableArgs.executableArgs),
+ runnableArgs.environment,
);
if (artifacts.length === 0) {
@@ -106,8 +111,9 @@ export class Cargo {
cargoArgs: string[],
onStdoutJson: (obj: any) => void,
onStderrString: (data: string) => void,
+ env?: Record<string, string>,
): Promise<number> {
- const path = await cargoPath();
+ const path = await cargoPath(env);
return await new Promise((resolve, reject) => {
const cargo = cp.spawn(path, cargoArgs, {
stdio: ["ignore", "pipe", "pipe"],
@@ -133,29 +139,12 @@ export class Cargo {
}
}
-/** Mirrors `project_model::sysroot::discover_sysroot_dir()` implementation*/
-export async function getSysroot(dir: string): Promise<string> {
- const rustcPath = await getPathForExecutable("rustc");
-
- // do not memoize the result because the toolchain may change between runs
- return await execute(`${rustcPath} --print sysroot`, { cwd: dir });
-}
-
-export async function getRustcId(dir: string): Promise<string> {
- const rustcPath = await getPathForExecutable("rustc");
-
- // do not memoize the result because the toolchain may change between runs
- const data = await execute(`${rustcPath} -V -v`, { cwd: dir });
- const rx = /commit-hash:\s(.*)$/m;
-
- const result = unwrapNullable(rx.exec(data));
- const first = unwrapUndefinable(result[1]);
- return first;
-}
-
/** Mirrors `toolchain::cargo()` implementation */
// FIXME: The server should provide this
-export function cargoPath(): Promise<string> {
+export function cargoPath(env?: Record<string, string>): Promise<string> {
+ if (env?.["RUSTC_TOOLCHAIN"]) {
+ return Promise.resolve("cargo");
+ }
return getPathForExecutable("cargo");
}