Skip to content

Commit b25f657

Browse files
committed
Auto merge of #13466 - Veykril:invocation-location, r=Veykril
Implement invocation location config This allows setting the working directory for build-scripts on flycheck Complements #13128 This will be followed up by one more PR that adds a few simple interpolation vars for `overrideCommand`, with that we should cover the needs for most build systems I believe.
2 parents 19efa0b + 0f8904e commit b25f657

File tree

9 files changed

+188
-57
lines changed

9 files changed

+188
-57
lines changed

crates/flycheck/src/lib.rs

+38-10
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+
Root(AbsPathBuf),
34+
#[default]
35+
Workspace,
36+
}
37+
3138
#[derive(Clone, Debug, PartialEq, Eq)]
3239
pub enum FlycheckConfig {
3340
CargoCommand {
@@ -39,13 +46,13 @@ pub enum FlycheckConfig {
3946
features: Vec<String>,
4047
extra_args: Vec<String>,
4148
extra_env: FxHashMap<String, String>,
42-
invocation_strategy: InvocationStrategy,
4349
},
4450
CustomCommand {
4551
command: String,
4652
args: Vec<String>,
4753
extra_env: FxHashMap<String, String>,
4854
invocation_strategy: InvocationStrategy,
55+
invocation_location: InvocationLocation,
4956
},
5057
}
5158

@@ -275,7 +282,7 @@ impl FlycheckActor {
275282
}
276283

277284
fn check_command(&self) -> Command {
278-
let (mut cmd, args, invocation_strategy) = match &self.config {
285+
let (mut cmd, args) = match &self.config {
279286
FlycheckConfig::CargoCommand {
280287
command,
281288
target_triple,
@@ -285,7 +292,6 @@ impl FlycheckActor {
285292
extra_args,
286293
features,
287294
extra_env,
288-
invocation_strategy,
289295
} => {
290296
let mut cmd = Command::new(toolchain::cargo());
291297
cmd.arg(command);
@@ -309,18 +315,40 @@ impl FlycheckActor {
309315
}
310316
}
311317
cmd.envs(extra_env);
312-
(cmd, extra_args, invocation_strategy)
318+
(cmd, extra_args)
313319
}
314-
FlycheckConfig::CustomCommand { command, args, extra_env, invocation_strategy } => {
320+
FlycheckConfig::CustomCommand {
321+
command,
322+
args,
323+
extra_env,
324+
invocation_strategy,
325+
invocation_location,
326+
} => {
315327
let mut cmd = Command::new(command);
316328
cmd.envs(extra_env);
317-
(cmd, args, invocation_strategy)
329+
330+
match invocation_location {
331+
InvocationLocation::Workspace => {
332+
match invocation_strategy {
333+
InvocationStrategy::Once => {
334+
cmd.current_dir(&self.root);
335+
}
336+
InvocationStrategy::PerWorkspace => {
337+
// FIXME: cmd.current_dir(&affected_workspace);
338+
cmd.current_dir(&self.root);
339+
}
340+
}
341+
}
342+
InvocationLocation::Root(root) => {
343+
cmd.current_dir(root);
344+
}
345+
}
346+
347+
(cmd, args)
318348
}
319349
};
320-
match invocation_strategy {
321-
InvocationStrategy::PerWorkspace => cmd.current_dir(&self.root),
322-
InvocationStrategy::Once => cmd.args(args),
323-
};
350+
351+
cmd.args(args);
324352
cmd
325353
}
326354

crates/project-model/src/build_scripts.rs

+24-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,21 @@ 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::Root(root) if config.run_build_script_command.is_some() => {
124+
root.as_path()
125+
}
126+
_ => &workspace.workspace_root(),
127+
}
128+
.as_ref();
128129

129-
match Self::run_per_ws(
130-
Self::build_command(config, Some(workspace_root))?,
131-
workspace,
132-
progress,
133-
) {
130+
match Self::run_per_ws(Self::build_command(config, current_dir)?, workspace, progress) {
134131
Ok(WorkspaceBuildScripts { error: Some(error), .. })
135132
if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) =>
136133
{
137134
// building build scripts failed, attempt to build with --keep-going so
138135
// that we potentially get more build data
139-
let mut cmd = Self::build_command(config, Some(workspace_root))?;
136+
let mut cmd = Self::build_command(config, current_dir)?;
140137
cmd.args(&["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
141138
let mut res = Self::run_per_ws(cmd, workspace, progress)?;
142139
res.error = Some(error);
@@ -154,7 +151,17 @@ impl WorkspaceBuildScripts {
154151
progress: &dyn Fn(String),
155152
) -> io::Result<Vec<WorkspaceBuildScripts>> {
156153
assert_eq!(config.invocation_strategy, InvocationStrategy::Once);
157-
let cmd = Self::build_command(config, None)?;
154+
155+
let current_dir = match &config.invocation_location {
156+
InvocationLocation::Root(root) => root,
157+
InvocationLocation::Workspace => {
158+
return Err(io::Error::new(
159+
io::ErrorKind::Other,
160+
"Cannot run build scripts from workspace with invocation strategy `once`",
161+
))
162+
}
163+
};
164+
let cmd = Self::build_command(config, current_dir.as_path().as_ref())?;
158165
// NB: Cargo.toml could have been modified between `cargo metadata` and
159166
// `cargo check`. We shouldn't assume that package ids we see here are
160167
// 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+
Root(AbsPathBuf),
171+
#[default]
172+
Workspace,
173+
}

crates/project-model/src/workspace.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,9 @@ impl ProjectWorkspace {
332332
config: &CargoConfig,
333333
progress: &dyn Fn(String),
334334
) -> Vec<Result<WorkspaceBuildScripts>> {
335-
if let InvocationStrategy::PerWorkspace = config.invocation_strategy {
335+
if matches!(config.invocation_strategy, InvocationStrategy::PerWorkspace)
336+
|| config.run_build_script_command.is_some()
337+
{
336338
return workspaces.iter().map(|it| it.run_build_scripts(config, progress)).collect();
337339
}
338340

crates/rust-analyzer/src/config.rs

+54-14
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,16 @@ 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+
/// - "root": run build scripts in the project's root directory.
76+
/// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
77+
/// is set.
78+
cargo_buildScripts_invocationLocation: InvocationLocation = "\"workspace\"",
7279
/// Specifies the invocation strategy to use when running the build scripts command.
73-
/// If `per_workspace` is set, the command will be executed for each workspace from the
74-
/// corresponding workspace root.
75-
/// If `once` is set, the command will be executed once in the project root.
80+
/// If `per_workspace` is set, the command will be executed for each workspace.
81+
/// If `once` is set, the command will be executed once.
7682
/// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
7783
/// is set.
7884
cargo_buildScripts_invocationStrategy: InvocationStrategy = "\"per_workspace\"",
@@ -129,10 +135,17 @@ config_data! {
129135
///
130136
/// Set to `"all"` to pass `--all-features` to Cargo.
131137
checkOnSave_features: Option<CargoFeaturesDef> = "null",
138+
/// Specifies the working directory for running checks.
139+
/// - "workspace": run checks for workspaces in the corresponding workspaces' root directories.
140+
// FIXME: Ideally we would support this in some way
141+
/// This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`.
142+
/// - "root": run checks in the project's root directory.
143+
/// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
144+
/// is set.
145+
checkOnSave_invocationLocation: InvocationLocation = "\"workspace\"",
132146
/// Specifies the invocation strategy to use when running the checkOnSave command.
133-
/// If `per_workspace` is set, the command will be executed for each workspace from the
134-
/// corresponding workspace root.
135-
/// If `once` is set, the command will be executed once in the project root.
147+
/// If `per_workspace` is set, the command will be executed for each workspace.
148+
/// If `once` is set, the command will be executed once.
136149
/// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
137150
/// is set.
138151
checkOnSave_invocationStrategy: InvocationStrategy = "\"per_workspace\"",
@@ -1074,6 +1087,12 @@ impl Config {
10741087
InvocationStrategy::Once => project_model::InvocationStrategy::Once,
10751088
InvocationStrategy::PerWorkspace => project_model::InvocationStrategy::PerWorkspace,
10761089
},
1090+
invocation_location: match self.data.cargo_buildScripts_invocationLocation {
1091+
InvocationLocation::Root => {
1092+
project_model::InvocationLocation::Root(self.root_path.clone())
1093+
}
1094+
InvocationLocation::Workspace => project_model::InvocationLocation::Workspace,
1095+
},
10771096
run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(),
10781097
extra_env: self.data.cargo_extraEnv.clone(),
10791098
}
@@ -1097,10 +1116,6 @@ impl Config {
10971116
if !self.data.checkOnSave_enable {
10981117
return None;
10991118
}
1100-
let invocation_strategy = match self.data.checkOnSave_invocationStrategy {
1101-
InvocationStrategy::Once => flycheck::InvocationStrategy::Once,
1102-
InvocationStrategy::PerWorkspace => flycheck::InvocationStrategy::PerWorkspace,
1103-
};
11041119
let flycheck_config = match &self.data.checkOnSave_overrideCommand {
11051120
Some(args) if !args.is_empty() => {
11061121
let mut args = args.clone();
@@ -1109,7 +1124,18 @@ impl Config {
11091124
command,
11101125
args,
11111126
extra_env: self.check_on_save_extra_env(),
1112-
invocation_strategy,
1127+
invocation_strategy: match self.data.checkOnSave_invocationStrategy {
1128+
InvocationStrategy::Once => flycheck::InvocationStrategy::Once,
1129+
InvocationStrategy::PerWorkspace => {
1130+
flycheck::InvocationStrategy::PerWorkspace
1131+
}
1132+
},
1133+
invocation_location: match self.data.checkOnSave_invocationLocation {
1134+
InvocationLocation::Root => {
1135+
flycheck::InvocationLocation::Root(self.root_path.clone())
1136+
}
1137+
InvocationLocation::Workspace => flycheck::InvocationLocation::Workspace,
1138+
},
11131139
}
11141140
}
11151141
Some(_) | None => FlycheckConfig::CargoCommand {
@@ -1139,7 +1165,6 @@ impl Config {
11391165
},
11401166
extra_args: self.data.checkOnSave_extraArgs.clone(),
11411167
extra_env: self.check_on_save_extra_env(),
1142-
invocation_strategy,
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+
Root,
1650+
Workspace,
1651+
}
1652+
16211653
#[derive(Deserialize, Debug, Clone)]
16221654
#[serde(untagged)]
16231655
enum LifetimeElisionDef {
@@ -2036,8 +2068,16 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
20362068
"type": "string",
20372069
"enum": ["per_workspace", "once"],
20382070
"enumDescriptions": [
2039-
"The command will be executed for each workspace from the corresponding workspace root.",
2040-
"The command will be executed once in the project root."
2071+
"The command will be executed for each workspace.",
2072+
"The command will be executed once."
2073+
],
2074+
},
2075+
"InvocationLocation" => set! {
2076+
"type": "string",
2077+
"enum": ["workspace", "root"],
2078+
"enumDescriptions": [
2079+
"The command will be executed in the corresponding workspace root.",
2080+
"The command will be executed in the project root."
20412081
],
20422082
},
20432083
_ => panic!("missing entry for {}: {}", ty, default),

crates/rust-analyzer/src/reload.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -473,8 +473,10 @@ impl GlobalState {
473473
};
474474

475475
let sender = self.flycheck_sender.clone();
476-
let (FlycheckConfig::CargoCommand { invocation_strategy, .. }
477-
| FlycheckConfig::CustomCommand { invocation_strategy, .. }) = config;
476+
let invocation_strategy = match config {
477+
FlycheckConfig::CargoCommand { .. } => flycheck::InvocationStrategy::PerWorkspace,
478+
FlycheckConfig::CustomCommand { invocation_strategy, .. } => invocation_strategy,
479+
};
478480

479481
self.flycheck = match invocation_strategy {
480482
flycheck::InvocationStrategy::Once => vec![FlycheckHandle::spawn(

0 commit comments

Comments
 (0)