Auto merge of #13128 - Veykril:invocation-strategy, r=Veykril

Implement invocation strategy config

Fixes https://github.com/rust-lang/rust-analyzer/issues/10793

This allows to change how we run build scripts (and `checkOnSave`), exposing two configs:
- `once`: run the specified command once in the project root (the working dir of the server)
- `per_workspace`: run the specified command per workspace in the corresponding workspace

This also applies to `checkOnSave` likewise, though `once_in_root` is useless there currently, due to https://github.com/rust-lang/cargo/issues/11007
This commit is contained in:
bors 2022-10-19 21:53:19 +00:00
commit a77ac93b2a
9 changed files with 471 additions and 207 deletions

View file

@ -2,7 +2,7 @@
//! metadata` or `rust-project.json`) into representation stored in the salsa
//! database -- `CrateGraph`.
use std::{collections::VecDeque, fmt, fs, process::Command};
use std::{collections::VecDeque, fmt, fs, process::Command, sync::Arc};
use anyhow::{format_err, Context, Result};
use base_db::{
@ -21,8 +21,8 @@ use crate::{
cfg_flag::CfgFlag,
rustc_cfg,
sysroot::SysrootCrate,
utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath, Package, ProjectJson, ProjectManifest,
Sysroot, TargetKind, WorkspaceBuildScripts,
utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath, Package,
ProjectJson, ProjectManifest, Sysroot, TargetKind, WorkspaceBuildScripts,
};
/// A set of cfg-overrides per crate.
@ -303,6 +303,7 @@ impl ProjectWorkspace {
Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
}
/// Runs the build scripts for this [`ProjectWorkspace`].
pub fn run_build_scripts(
&self,
config: &CargoConfig,
@ -310,9 +311,13 @@ impl ProjectWorkspace {
) -> Result<WorkspaceBuildScripts> {
match self {
ProjectWorkspace::Cargo { cargo, toolchain, .. } => {
WorkspaceBuildScripts::run(config, cargo, progress, toolchain).with_context(|| {
format!("Failed to run build scripts for {}", &cargo.workspace_root().display())
})
WorkspaceBuildScripts::run_for_workspace(config, cargo, progress, toolchain)
.with_context(|| {
format!(
"Failed to run build scripts for {}",
&cargo.workspace_root().display()
)
})
}
ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFiles { .. } => {
Ok(WorkspaceBuildScripts::default())
@ -320,6 +325,47 @@ impl ProjectWorkspace {
}
}
/// Runs the build scripts for the given [`ProjectWorkspace`]s. Depending on the invocation
/// strategy this may run a single build process for all project workspaces.
pub fn run_all_build_scripts(
workspaces: &[ProjectWorkspace],
config: &CargoConfig,
progress: &dyn Fn(String),
) -> Vec<Result<WorkspaceBuildScripts>> {
if let InvocationStrategy::PerWorkspace = config.invocation_strategy {
return workspaces.iter().map(|it| it.run_build_scripts(config, progress)).collect();
}
let cargo_ws: Vec<_> = workspaces
.iter()
.filter_map(|it| match it {
ProjectWorkspace::Cargo { cargo, .. } => Some(cargo),
_ => None,
})
.collect();
let ref mut outputs = match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress) {
Ok(it) => Ok(it.into_iter()),
// io::Error is not Clone?
Err(e) => Err(Arc::new(e)),
};
workspaces
.iter()
.map(|it| match it {
ProjectWorkspace::Cargo { cargo, .. } => match outputs {
Ok(outputs) => Ok(outputs.next().unwrap()),
Err(e) => Err(e.clone()).with_context(|| {
format!(
"Failed to run build scripts for {}",
&cargo.workspace_root().display()
)
}),
},
_ => Ok(WorkspaceBuildScripts::default()),
})
.collect()
}
pub fn set_build_scripts(&mut self, bs: WorkspaceBuildScripts) {
match self {
ProjectWorkspace::Cargo { build_scripts, .. } => *build_scripts = bs,