Skip to content

Commit 96ce14f

Browse files
committed
Implement invocation location config
1 parent 19efa0b commit 96ce14f

File tree

5 files changed

+102
-26
lines changed

5 files changed

+102
-26
lines changed

crates/flycheck/src/lib.rs

+39-8
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ pub enum InvocationStrategy {
2828
PerWorkspace,
2929
}
3030

31+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
32+
pub enum InvocationLocation {
33+
Project(AbsPathBuf),
34+
#[default]
35+
Workspace,
36+
}
37+
3138
#[derive(Clone, Debug, PartialEq, Eq)]
3239
pub enum FlycheckConfig {
3340
CargoCommand {
@@ -40,12 +47,14 @@ pub enum FlycheckConfig {
4047
extra_args: Vec<String>,
4148
extra_env: FxHashMap<String, String>,
4249
invocation_strategy: InvocationStrategy,
50+
invocation_location: InvocationLocation,
4351
},
4452
CustomCommand {
4553
command: String,
4654
args: Vec<String>,
4755
extra_env: FxHashMap<String, String>,
4856
invocation_strategy: InvocationStrategy,
57+
invocation_location: InvocationLocation,
4958
},
5059
}
5160

@@ -275,7 +284,7 @@ impl FlycheckActor {
275284
}
276285

277286
fn check_command(&self) -> Command {
278-
let (mut cmd, args, invocation_strategy) = match &self.config {
287+
let (mut cmd, args, invocation_strategy, invocation_location) = match &self.config {
279288
FlycheckConfig::CargoCommand {
280289
command,
281290
target_triple,
@@ -286,6 +295,7 @@ impl FlycheckActor {
286295
features,
287296
extra_env,
288297
invocation_strategy,
298+
invocation_location,
289299
} => {
290300
let mut cmd = Command::new(toolchain::cargo());
291301
cmd.arg(command);
@@ -309,18 +319,39 @@ impl FlycheckActor {
309319
}
310320
}
311321
cmd.envs(extra_env);
312-
(cmd, extra_args, invocation_strategy)
322+
(cmd, extra_args, invocation_strategy, invocation_location)
313323
}
314-
FlycheckConfig::CustomCommand { command, args, extra_env, invocation_strategy } => {
324+
FlycheckConfig::CustomCommand {
325+
command,
326+
args,
327+
extra_env,
328+
invocation_strategy,
329+
invocation_location,
330+
} => {
315331
let mut cmd = Command::new(command);
316332
cmd.envs(extra_env);
317-
(cmd, args, invocation_strategy)
333+
(cmd, args, invocation_strategy, invocation_location)
318334
}
319335
};
320-
match invocation_strategy {
321-
InvocationStrategy::PerWorkspace => cmd.current_dir(&self.root),
322-
InvocationStrategy::Once => cmd.args(args),
323-
};
336+
337+
match invocation_location {
338+
InvocationLocation::Workspace => {
339+
match invocation_strategy {
340+
InvocationStrategy::Once => {
341+
cmd.current_dir(&self.root);
342+
}
343+
InvocationStrategy::PerWorkspace => {
344+
// FIXME: cmd.current_dir(&affected_workspace);
345+
cmd.current_dir(&self.root);
346+
}
347+
}
348+
}
349+
InvocationLocation::Project(root) => {
350+
cmd.current_dir(root);
351+
}
352+
}
353+
354+
cmd.args(args);
324355
cmd
325356
}
326357

crates/project-model/src/build_scripts.rs

+22-17
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ use semver::Version;
2121
use serde::Deserialize;
2222

2323
use crate::{
24-
cfg_flag::CfgFlag, CargoConfig, CargoFeatures, CargoWorkspace, InvocationStrategy, Package,
24+
cfg_flag::CfgFlag, CargoConfig, CargoFeatures, CargoWorkspace, InvocationLocation,
25+
InvocationStrategy, Package,
2526
};
2627

2728
#[derive(Debug, Default, Clone, PartialEq, Eq)]
@@ -55,10 +56,7 @@ impl BuildScriptOutput {
5556
}
5657

5758
impl WorkspaceBuildScripts {
58-
fn build_command(
59-
config: &CargoConfig,
60-
workspace_root: Option<&path::Path>,
61-
) -> io::Result<Command> {
59+
fn build_command(config: &CargoConfig, current_dir: &path::Path) -> io::Result<Command> {
6260
let mut cmd = match config.run_build_script_command.as_deref() {
6361
Some([program, args @ ..]) => {
6462
let mut cmd = Command::new(program);
@@ -94,14 +92,11 @@ impl WorkspaceBuildScripts {
9492
}
9593
}
9694

97-
if let Some(workspace_root) = workspace_root {
98-
cmd.current_dir(workspace_root);
99-
}
100-
10195
cmd
10296
}
10397
};
10498

99+
cmd.current_dir(current_dir);
105100
cmd.envs(&config.extra_env);
106101
if config.wrap_rustc_in_build_scripts {
107102
// Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
@@ -124,19 +119,19 @@ impl WorkspaceBuildScripts {
124119
) -> io::Result<WorkspaceBuildScripts> {
125120
const RUST_1_62: Version = Version::new(1, 62, 0);
126121

127-
let workspace_root: &path::Path = &workspace.workspace_root().as_ref();
122+
let current_dir = match &config.invocation_location {
123+
InvocationLocation::Project(root) => root.as_path(),
124+
InvocationLocation::Workspace => &workspace.workspace_root(),
125+
}
126+
.as_ref();
128127

129-
match Self::run_per_ws(
130-
Self::build_command(config, Some(workspace_root))?,
131-
workspace,
132-
progress,
133-
) {
128+
match Self::run_per_ws(Self::build_command(config, current_dir)?, workspace, progress) {
134129
Ok(WorkspaceBuildScripts { error: Some(error), .. })
135130
if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) =>
136131
{
137132
// building build scripts failed, attempt to build with --keep-going so
138133
// that we potentially get more build data
139-
let mut cmd = Self::build_command(config, Some(workspace_root))?;
134+
let mut cmd = Self::build_command(config, current_dir)?;
140135
cmd.args(&["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
141136
let mut res = Self::run_per_ws(cmd, workspace, progress)?;
142137
res.error = Some(error);
@@ -154,7 +149,17 @@ impl WorkspaceBuildScripts {
154149
progress: &dyn Fn(String),
155150
) -> io::Result<Vec<WorkspaceBuildScripts>> {
156151
assert_eq!(config.invocation_strategy, InvocationStrategy::Once);
157-
let cmd = Self::build_command(config, None)?;
152+
153+
let current_dir = match &config.invocation_location {
154+
InvocationLocation::Project(root) => root,
155+
InvocationLocation::Workspace => {
156+
return Err(io::Error::new(
157+
io::ErrorKind::Other,
158+
"Cannot run build scripts from workspace with invocation strategy `once`",
159+
))
160+
}
161+
};
162+
let cmd = Self::build_command(config, current_dir.as_path().as_ref())?;
158163
// NB: Cargo.toml could have been modified between `cargo metadata` and
159164
// `cargo check`. We shouldn't assume that package ids we see here are
160165
// exactly those from `config`.

crates/project-model/src/cargo_workspace.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_hash::FxHashMap;
1414
use serde::Deserialize;
1515
use serde_json::from_value;
1616

17-
use crate::{utf8_stdout, ManifestPath};
17+
use crate::{utf8_stdout, InvocationLocation, ManifestPath};
1818
use crate::{CfgOverrides, InvocationStrategy};
1919

2020
/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
@@ -107,6 +107,7 @@ pub struct CargoConfig {
107107
/// Extra env vars to set when invoking the cargo command
108108
pub extra_env: FxHashMap<String, String>,
109109
pub invocation_strategy: InvocationStrategy,
110+
pub invocation_location: InvocationLocation,
110111
}
111112

112113
impl CargoConfig {

crates/project-model/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,10 @@ pub enum InvocationStrategy {
164164
#[default]
165165
PerWorkspace,
166166
}
167+
168+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
169+
pub enum InvocationLocation {
170+
Project(AbsPathBuf),
171+
#[default]
172+
Workspace,
173+
}

crates/rust-analyzer/src/config.rs

+32
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ config_data! {
6969
cargo_autoreload: bool = "true",
7070
/// Run build scripts (`build.rs`) for more precise code analysis.
7171
cargo_buildScripts_enable: bool = "true",
72+
/// Specifies the working directory for running build scripts.
73+
/// - "workspace": run build scripts for a workspace in the workspace's root directory.
74+
/// This is incompatible with `#rust-analyzer.cargo.buildScripts.invocationStrategy#` set to `once`.
75+
/// - "project": run build scripts in the project's root directory.
76+
cargo_buildScripts_invocationLocation: InvocationLocation = "\"workspace\"",
7277
/// Specifies the invocation strategy to use when running the build scripts command.
7378
/// If `per_workspace` is set, the command will be executed for each workspace from the
7479
/// corresponding workspace root.
@@ -129,6 +134,12 @@ config_data! {
129134
///
130135
/// Set to `"all"` to pass `--all-features` to Cargo.
131136
checkOnSave_features: Option<CargoFeaturesDef> = "null",
137+
/// Specifies the working directory for running checks.
138+
/// - "workspace": run checks for workspaces in the corresponding workspaces' root directories.
139+
// FIXME: Ideally we would support this in some way
140+
/// This falls back to "project" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`.
141+
/// - "project": run checks in the project's root directory.
142+
checkOnSave_invocationLocation: InvocationLocation = "\"workspace\"",
132143
/// Specifies the invocation strategy to use when running the checkOnSave command.
133144
/// If `per_workspace` is set, the command will be executed for each workspace from the
134145
/// corresponding workspace root.
@@ -1074,6 +1085,12 @@ impl Config {
10741085
InvocationStrategy::Once => project_model::InvocationStrategy::Once,
10751086
InvocationStrategy::PerWorkspace => project_model::InvocationStrategy::PerWorkspace,
10761087
},
1088+
invocation_location: match self.data.cargo_buildScripts_invocationLocation {
1089+
InvocationLocation::Project => {
1090+
project_model::InvocationLocation::Project(self.root_path.clone())
1091+
}
1092+
InvocationLocation::Workspace => project_model::InvocationLocation::Workspace,
1093+
},
10771094
run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(),
10781095
extra_env: self.data.cargo_extraEnv.clone(),
10791096
}
@@ -1101,6 +1118,12 @@ impl Config {
11011118
InvocationStrategy::Once => flycheck::InvocationStrategy::Once,
11021119
InvocationStrategy::PerWorkspace => flycheck::InvocationStrategy::PerWorkspace,
11031120
};
1121+
let invocation_location = match self.data.checkOnSave_invocationLocation {
1122+
InvocationLocation::Project => {
1123+
flycheck::InvocationLocation::Project(self.root_path.clone())
1124+
}
1125+
InvocationLocation::Workspace => flycheck::InvocationLocation::Workspace,
1126+
};
11041127
let flycheck_config = match &self.data.checkOnSave_overrideCommand {
11051128
Some(args) if !args.is_empty() => {
11061129
let mut args = args.clone();
@@ -1110,6 +1133,7 @@ impl Config {
11101133
args,
11111134
extra_env: self.check_on_save_extra_env(),
11121135
invocation_strategy,
1136+
invocation_location,
11131137
}
11141138
}
11151139
Some(_) | None => FlycheckConfig::CargoCommand {
@@ -1140,6 +1164,7 @@ impl Config {
11401164
extra_args: self.data.checkOnSave_extraArgs.clone(),
11411165
extra_env: self.check_on_save_extra_env(),
11421166
invocation_strategy,
1167+
invocation_location,
11431168
},
11441169
};
11451170
Some(flycheck_config)
@@ -1618,6 +1643,13 @@ enum InvocationStrategy {
16181643
PerWorkspace,
16191644
}
16201645

1646+
#[derive(Deserialize, Debug, Clone)]
1647+
#[serde(rename_all = "snake_case")]
1648+
enum InvocationLocation {
1649+
Project,
1650+
Workspace,
1651+
}
1652+
16211653
#[derive(Deserialize, Debug, Clone)]
16221654
#[serde(untagged)]
16231655
enum LifetimeElisionDef {

0 commit comments

Comments
 (0)