Skip to content

Commit a3549dd

Browse files
committed
{manifest-path} interpolation
1 parent b2a20da commit a3549dd

File tree

8 files changed

+118
-103
lines changed

8 files changed

+118
-103
lines changed

Diff for: crates/flycheck/src/lib.rs

+32-37
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
use std::{
88
fmt, io,
9-
path::Path,
109
process::{ChildStderr, ChildStdout, Command, Stdio},
1110
time::Duration,
1211
};
@@ -25,7 +24,6 @@ pub use cargo_metadata::diagnostic::{
2524
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
2625
pub enum InvocationStrategy {
2726
OnceInRoot,
28-
PerWorkspaceWithManifestPath,
2927
#[default]
3028
PerWorkspace,
3129
}
@@ -153,7 +151,9 @@ struct FlycheckActor {
153151
id: usize,
154152
sender: Box<dyn Fn(Message) + Send>,
155153
config: FlycheckConfig,
156-
workspace_root: AbsPathBuf,
154+
/// Either the workspace root of the workspace we are flychecking,
155+
/// or the project root of the project.
156+
root: AbsPathBuf,
157157
/// CargoHandle exists to wrap around the communication needed to be able to
158158
/// run `cargo check` without blocking. Currently the Rust standard library
159159
/// doesn't provide a way to read sub-process output without blocking, so we
@@ -175,7 +175,7 @@ impl FlycheckActor {
175175
workspace_root: AbsPathBuf,
176176
) -> FlycheckActor {
177177
tracing::info!(%id, ?workspace_root, "Spawning flycheck");
178-
FlycheckActor { id, sender, config, workspace_root, cargo_handle: None }
178+
FlycheckActor { id, sender, config, root: workspace_root, cargo_handle: None }
179179
}
180180

181181
fn report_progress(&self, progress: Progress) {
@@ -201,20 +201,7 @@ impl FlycheckActor {
201201
self.cancel_check_process();
202202
while let Ok(_) = inbox.recv_timeout(Duration::from_millis(50)) {}
203203

204-
let mut command = self.check_command();
205-
let invocation_strategy = self.invocation_strategy();
206-
match invocation_strategy {
207-
InvocationStrategy::OnceInRoot => (),
208-
InvocationStrategy::PerWorkspaceWithManifestPath => {
209-
command.arg("--manifest-path");
210-
command.arg(<_ as AsRef<Path>>::as_ref(
211-
&self.workspace_root.join("Cargo.toml"),
212-
));
213-
}
214-
InvocationStrategy::PerWorkspace => {
215-
command.current_dir(&self.workspace_root);
216-
}
217-
}
204+
let command = self.check_command();
218205
tracing::debug!(?command, "will restart flycheck");
219206
match CargoHandle::spawn(command) {
220207
Ok(cargo_handle) => {
@@ -256,7 +243,7 @@ impl FlycheckActor {
256243
CargoMessage::Diagnostic(msg) => {
257244
self.send(Message::AddDiagnostic {
258245
id: self.id,
259-
workspace_root: self.workspace_root.clone(),
246+
workspace_root: self.root.clone(),
260247
diagnostic: msg,
261248
});
262249
}
@@ -278,15 +265,8 @@ impl FlycheckActor {
278265
}
279266
}
280267

281-
fn invocation_strategy(&self) -> InvocationStrategy {
282-
match self.config {
283-
FlycheckConfig::CargoCommand { invocation_strategy, .. }
284-
| FlycheckConfig::CustomCommand { invocation_strategy, .. } => invocation_strategy,
285-
}
286-
}
287-
288268
fn check_command(&self) -> Command {
289-
let mut cmd = match &self.config {
269+
let (mut cmd, args, invocation_strategy) = match &self.config {
290270
FlycheckConfig::CargoCommand {
291271
command,
292272
target_triple,
@@ -296,13 +276,11 @@ impl FlycheckActor {
296276
extra_args,
297277
features,
298278
extra_env,
299-
invocation_strategy: _,
279+
invocation_strategy,
300280
} => {
301281
let mut cmd = Command::new(toolchain::cargo());
302282
cmd.arg(command);
303-
cmd.current_dir(&self.workspace_root);
304-
cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
305-
.arg(self.workspace_root.join("Cargo.toml").as_os_str());
283+
cmd.args(&["--workspace", "--message-format=json"]);
306284

307285
if let Some(target) = target_triple {
308286
cmd.args(&["--target", target.as_str()]);
@@ -321,18 +299,35 @@ impl FlycheckActor {
321299
cmd.arg(features.join(" "));
322300
}
323301
}
324-
cmd.args(extra_args);
325302
cmd.envs(extra_env);
326-
cmd
303+
(cmd, extra_args, invocation_strategy)
327304
}
328-
FlycheckConfig::CustomCommand { command, args, extra_env, invocation_strategy: _ } => {
305+
FlycheckConfig::CustomCommand { command, args, extra_env, invocation_strategy } => {
329306
let mut cmd = Command::new(command);
330-
cmd.args(args);
331307
cmd.envs(extra_env);
332-
cmd
308+
(cmd, args, invocation_strategy)
333309
}
334310
};
335-
cmd.current_dir(&self.workspace_root);
311+
if let InvocationStrategy::PerWorkspace = invocation_strategy {
312+
let mut with_manifest_path = false;
313+
for arg in args {
314+
if let Some(_) = arg.find("$manifest_path") {
315+
with_manifest_path = true;
316+
cmd.arg(arg.replace(
317+
"$manifest_path",
318+
&self.root.join("Cargo.toml").display().to_string(),
319+
));
320+
} else {
321+
cmd.arg(arg);
322+
}
323+
}
324+
325+
if !with_manifest_path {
326+
cmd.current_dir(&self.root);
327+
}
328+
} else {
329+
cmd.args(args);
330+
}
336331
cmd
337332
}
338333

Diff for: crates/project-model/src/build_scripts.rs

+45-21
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,37 @@ impl BuildScriptOutput {
5555
}
5656

5757
impl WorkspaceBuildScripts {
58-
fn build_command(config: &CargoConfig) -> io::Result<Command> {
58+
fn build_command(
59+
config: &CargoConfig,
60+
workspace_root: Option<&path::Path>,
61+
) -> io::Result<Command> {
5962
let mut cmd = match config.run_build_script_command.as_deref() {
6063
Some([program, args @ ..]) => {
6164
let mut cmd = Command::new(program);
62-
cmd.args(args);
65+
66+
// FIXME: strategy and workspace root are coupled, express that in code
67+
if let (InvocationStrategy::PerWorkspace, Some(workspace_root)) =
68+
(config.invocation_strategy, workspace_root)
69+
{
70+
let mut with_manifest_path = false;
71+
for arg in args {
72+
if let Some(_) = arg.find("$manifest_path") {
73+
with_manifest_path = true;
74+
cmd.arg(arg.replace(
75+
"$manifest_path",
76+
&workspace_root.join("Cargo.toml").display().to_string(),
77+
));
78+
} else {
79+
cmd.arg(arg);
80+
}
81+
}
82+
83+
if !with_manifest_path {
84+
cmd.current_dir(workspace_root);
85+
}
86+
} else {
87+
cmd.args(args);
88+
}
6389
cmd
6490
}
6591
_ => {
@@ -90,9 +116,15 @@ impl WorkspaceBuildScripts {
90116
}
91117
}
92118
}
119+
120+
if let Some(workspace_root) = workspace_root {
121+
cmd.current_dir(workspace_root);
122+
}
123+
93124
cmd
94125
}
95126
};
127+
96128
cmd.envs(&config.extra_env);
97129
if config.wrap_rustc_in_build_scripts {
98130
// Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
@@ -115,15 +147,21 @@ impl WorkspaceBuildScripts {
115147
) -> io::Result<WorkspaceBuildScripts> {
116148
const RUST_1_62: Version = Version::new(1, 62, 0);
117149

118-
match Self::run_per_ws(Self::build_command(config)?, config, workspace, progress) {
150+
let workspace_root: &path::Path = &workspace.workspace_root().as_ref();
151+
152+
match Self::run_per_ws(
153+
Self::build_command(config, Some(workspace_root))?,
154+
workspace,
155+
progress,
156+
) {
119157
Ok(WorkspaceBuildScripts { error: Some(error), .. })
120158
if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) =>
121159
{
122160
// building build scripts failed, attempt to build with --keep-going so
123161
// that we potentially get more build data
124-
let mut cmd = Self::build_command(config)?;
162+
let mut cmd = Self::build_command(config, Some(workspace_root))?;
125163
cmd.args(&["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
126-
let mut res = Self::run_per_ws(cmd, config, workspace, progress)?;
164+
let mut res = Self::run_per_ws(cmd, workspace, progress)?;
127165
res.error = Some(error);
128166
Ok(res)
129167
}
@@ -139,7 +177,7 @@ impl WorkspaceBuildScripts {
139177
progress: &dyn Fn(String),
140178
) -> io::Result<Vec<WorkspaceBuildScripts>> {
141179
assert_eq!(config.invocation_strategy, InvocationStrategy::OnceInRoot);
142-
let cmd = Self::build_command(config)?;
180+
let cmd = Self::build_command(config, None)?;
143181
// NB: Cargo.toml could have been modified between `cargo metadata` and
144182
// `cargo check`. We shouldn't assume that package ids we see here are
145183
// exactly those from `config`.
@@ -188,24 +226,10 @@ impl WorkspaceBuildScripts {
188226
}
189227

190228
fn run_per_ws(
191-
mut cmd: Command,
192-
config: &CargoConfig,
229+
cmd: Command,
193230
workspace: &CargoWorkspace,
194231
progress: &dyn Fn(String),
195232
) -> io::Result<WorkspaceBuildScripts> {
196-
let workspace_root: &path::Path = &workspace.workspace_root().as_ref();
197-
198-
match config.invocation_strategy {
199-
InvocationStrategy::OnceInRoot => (),
200-
InvocationStrategy::PerWorkspaceWithManifestPath => {
201-
cmd.arg("--manifest-path");
202-
cmd.arg(workspace_root.join("Cargo.toml"));
203-
}
204-
InvocationStrategy::PerWorkspace => {
205-
cmd.current_dir(workspace_root);
206-
}
207-
}
208-
209233
let mut res = WorkspaceBuildScripts::default();
210234
let outputs = &mut res.outputs;
211235
// NB: Cargo.toml could have been modified between `cargo metadata` and

Diff for: crates/project-model/src/lib.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,9 @@ fn utf8_stdout(mut cmd: Command) -> Result<String> {
158158
Ok(stdout.trim().to_string())
159159
}
160160

161-
#[derive(Clone, Debug, Default, PartialEq, Eq)]
161+
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
162162
pub enum InvocationStrategy {
163163
OnceInRoot,
164-
PerWorkspaceWithManifestPath,
165164
#[default]
166165
PerWorkspace,
167166
}

Diff for: crates/project-model/src/workspace.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,7 @@ impl ProjectWorkspace {
314314
config: &CargoConfig,
315315
progress: &dyn Fn(String),
316316
) -> Vec<Result<WorkspaceBuildScripts>> {
317-
if let InvocationStrategy::PerWorkspaceWithManifestPath | InvocationStrategy::PerWorkspace =
318-
config.invocation_strategy
319-
{
317+
if let InvocationStrategy::PerWorkspace = config.invocation_strategy {
320318
return workspaces.iter().map(|it| it.run_build_scripts(config, progress)).collect();
321319
}
322320

Diff for: crates/rust-analyzer/src/config.rs

+18-20
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,15 @@ config_data! {
7070
/// Run build scripts (`build.rs`) for more precise code analysis.
7171
cargo_buildScripts_enable: bool = "true",
7272
/// Specifies the invocation strategy to use when running the build scripts command.
73-
/// If `per_workspace_with_manifest_path` is set, the command will be executed for each
74-
/// workspace, `--manifest-path {workspace-dir}` will be passed to the invoked command and
75-
/// the command will be executed from the project root.
76-
/// If `per_workspace` is set, the command will be executed for each workspace and the
77-
/// command will be executed from the corresponding workspace root.
73+
/// If `per_workspace` is set, the command will be executed for each workspace and all
74+
/// occurrences of `$manifest_path` in the command will be replaced by the corresponding
75+
/// manifest path of the workspace that the command is being invoked for. If interpolation
76+
/// for the manifest path happens at least once, the commands will be executed from the
77+
/// project root, otherwise the commands will be executed from the corresponding workspace
78+
/// root.
7879
/// If `once_in_root` is set, the command will be executed once in the project root.
80+
/// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
81+
/// is set.
7982
cargo_buildScripts_invocationStrategy: InvocationStrategy = "\"per_workspace\"",
8083
/// Override the command rust-analyzer uses to run build scripts and
8184
/// build procedural macros. The command is required to output json
@@ -126,12 +129,15 @@ config_data! {
126129
/// Set to `"all"` to pass `--all-features` to Cargo.
127130
checkOnSave_features: Option<CargoFeaturesDef> = "null",
128131
/// Specifies the invocation strategy to use when running the checkOnSave command.
129-
/// If `per_workspace_with_manifest_path` is set, the command will be executed for each
130-
/// workspace, `--manifest-path {workspace-dir}` will be passed to the invoked command and
131-
/// the command will be executed from the project root.
132-
/// If `per_workspace` is set, the command will be executed for each workspace and the
133-
/// command will be executed from the corresponding workspace root.
132+
/// If `per_workspace` is set, the command will be executed for each workspace and all
133+
/// occurrences of `$manifest_path` in the command will be replaced by the corresponding
134+
/// manifest path of the workspace that the command is being invoked for. If interpolation
135+
/// for the manifest path happens at least once, the commands will be executed from the
136+
/// project root, otherwise the commands will be executed from the corresponding workspace
137+
/// root.
134138
/// If `once_in_root` is set, the command will be executed once in the project root.
139+
/// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
140+
/// is set.
135141
checkOnSave_invocationStrategy: InvocationStrategy = "\"per_workspace\"",
136142
/// Whether to pass `--no-default-features` to Cargo. Defaults to
137143
/// `#rust-analyzer.cargo.noDefaultFeatures#`.
@@ -1060,9 +1066,6 @@ impl Config {
10601066
wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper,
10611067
invocation_strategy: match self.data.cargo_buildScripts_invocationStrategy {
10621068
InvocationStrategy::OnceInRoot => project_model::InvocationStrategy::OnceInRoot,
1063-
InvocationStrategy::PerWorkspaceWithManifestPath => {
1064-
project_model::InvocationStrategy::PerWorkspaceWithManifestPath
1065-
}
10661069
InvocationStrategy::PerWorkspace => project_model::InvocationStrategy::PerWorkspace,
10671070
},
10681071
run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(),
@@ -1090,9 +1093,6 @@ impl Config {
10901093
}
10911094
let invocation_strategy = match self.data.checkOnSave_invocationStrategy {
10921095
InvocationStrategy::OnceInRoot => flycheck::InvocationStrategy::OnceInRoot,
1093-
InvocationStrategy::PerWorkspaceWithManifestPath => {
1094-
flycheck::InvocationStrategy::PerWorkspaceWithManifestPath
1095-
}
10961096
InvocationStrategy::PerWorkspace => flycheck::InvocationStrategy::PerWorkspace,
10971097
};
10981098
let flycheck_config = match &self.data.checkOnSave_overrideCommand {
@@ -1609,7 +1609,6 @@ enum CargoFeaturesDef {
16091609
#[serde(rename_all = "snake_case")]
16101610
enum InvocationStrategy {
16111611
OnceInRoot,
1612-
PerWorkspaceWithManifestPath,
16131612
PerWorkspace,
16141613
}
16151614

@@ -2029,10 +2028,9 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
20292028
},
20302029
"InvocationStrategy" => set! {
20312030
"type": "string",
2032-
"enum": ["per_workspace", "per_workspace_with_manifest_path", "once_in_root"],
2031+
"enum": ["per_workspace", "once_in_root"],
20332032
"enumDescriptions": [
2034-
"The command will be executed for each workspace, `--manifest-path {workspace-dir}` will be passed to the invoked command and the command will be executed from the project root.",
2035-
"The command will be executed for each workspace and the command will be executed from the corresponding workspace root.",
2033+
"The command will be executed for each workspace and `{manifest-path}` usages will be interpolated with the corresponding workspace manifests. If `{manifest-path}` is used, the commands will be executed in the project root, otherwise in the corresponding workspace roots.",
20362034
"The command will be executed once in the project root."
20372035
],
20382036
},

Diff for: crates/rust-analyzer/src/reload.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -474,8 +474,7 @@ impl GlobalState {
474474
config.clone(),
475475
self.config.root_path().clone(),
476476
)],
477-
flycheck::InvocationStrategy::PerWorkspaceWithManifestPath
478-
| flycheck::InvocationStrategy::PerWorkspace => {
477+
flycheck::InvocationStrategy::PerWorkspace => {
479478
self.workspaces
480479
.iter()
481480
.enumerate()

0 commit comments

Comments
 (0)