Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/project-model/src/workspace.rs')
-rw-r--r--crates/project-model/src/workspace.rs355
1 files changed, 125 insertions, 230 deletions
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 9f6e75171b..7f845f85ae 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -44,50 +44,39 @@ pub struct PackageRoot {
}
#[derive(Clone)]
-pub enum ProjectWorkspace {
+pub struct ProjectWorkspace {
+ pub kind: ProjectWorkspaceKind,
+ /// The sysroot loaded for this workspace.
+ pub sysroot: Result<Sysroot, Option<String>>,
+ /// Holds cfg flags for the current target. We get those by running
+ /// `rustc --print cfg`.
+ // FIXME: make this a per-crate map, as, eg, build.rs might have a
+ // different target.
+ pub rustc_cfg: Vec<CfgFlag>,
+ /// The toolchain version used by this workspace.
+ pub toolchain: Option<Version>,
+ /// The target data layout queried for workspace.
+ pub target_layout: TargetLayoutLoadResult,
+ /// A set of cfg overrides for this workspace.
+ pub cfg_overrides: CfgOverrides,
+}
+
+#[derive(Clone)]
+pub enum ProjectWorkspaceKind {
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
Cargo {
/// The workspace as returned by `cargo metadata`.
cargo: CargoWorkspace,
/// The build script results for the workspace.
build_scripts: WorkspaceBuildScripts,
- /// The sysroot loaded for this workspace.
- sysroot: Result<Sysroot, Option<String>>,
/// The rustc workspace loaded for this workspace. An `Err(None)` means loading has been
/// disabled or was otherwise not requested.
rustc: Result<Box<(CargoWorkspace, WorkspaceBuildScripts)>, Option<String>>,
- /// Holds cfg flags for the current target. We get those by running
- /// `rustc --print cfg`.
- // FIXME: make this a per-crate map, as, eg, build.rs might have a
- // different target.
- rustc_cfg: Vec<CfgFlag>,
- /// A set of cfg overrides for this workspace.
- cfg_overrides: CfgOverrides,
- /// The toolchain version used by this workspace.
- toolchain: Option<Version>,
- /// The target data layout queried for workspace.
- target_layout: TargetLayoutLoadResult,
/// Environment variables set in the `.cargo/config` file.
cargo_config_extra_env: FxHashMap<String, String>,
},
/// Project workspace was manually specified using a `rust-project.json` file.
- Json {
- /// The loaded project json file.
- project: ProjectJson,
- /// The sysroot loaded for this workspace.
- sysroot: Result<Sysroot, Option<String>>,
- /// Holds cfg flags for the current target. We get those by running
- /// `rustc --print cfg`.
- // FIXME: make this a per-crate map, as, eg, build.rs might have a
- // different target.
- rustc_cfg: Vec<CfgFlag>,
- /// The toolchain version used by this workspace.
- toolchain: Option<Version>,
- /// The target data layout queried for workspace.
- target_layout: TargetLayoutLoadResult,
- /// A set of cfg overrides for this workspace.
- cfg_overrides: CfgOverrides,
- },
+ Json(ProjectJson),
// FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
// That's not the end user experience we should strive for.
// Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working.
@@ -101,37 +90,22 @@ pub enum ProjectWorkspace {
DetachedFile {
/// The file in question.
file: ManifestPath,
- /// The sysroot loaded for this workspace.
- sysroot: Result<Sysroot, Option<String>>,
- /// Holds cfg flags for the current target. We get those by running
- /// `rustc --print cfg`.
- // FIXME: make this a per-crate map, as, eg, build.rs might have a
- // different target.
- rustc_cfg: Vec<CfgFlag>,
- /// The toolchain version used by this workspace.
- toolchain: Option<Version>,
- /// The target data layout queried for workspace.
- target_layout: TargetLayoutLoadResult,
- /// A set of cfg overrides for the files.
- cfg_overrides: CfgOverrides,
/// Is this file a cargo script file?
- cargo_script: Option<(CargoWorkspace, WorkspaceBuildScripts)>,
+ cargo: Option<(CargoWorkspace, WorkspaceBuildScripts)>,
+ /// Environment variables set in the `.cargo/config` file.
+ cargo_config_extra_env: FxHashMap<String, String>,
},
}
impl fmt::Debug for ProjectWorkspace {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Make sure this isn't too verbose.
- match self {
- ProjectWorkspace::Cargo {
+ let Self { kind, sysroot, rustc_cfg, toolchain, target_layout, cfg_overrides } = self;
+ match kind {
+ ProjectWorkspaceKind::Cargo {
cargo,
build_scripts: _,
- sysroot,
rustc,
- rustc_cfg,
- cfg_overrides,
- toolchain,
- target_layout,
cargo_config_extra_env,
} => f
.debug_struct("Cargo")
@@ -148,14 +122,7 @@ impl fmt::Debug for ProjectWorkspace {
.field("data_layout", &target_layout)
.field("cargo_config_extra_env", &cargo_config_extra_env)
.finish(),
- ProjectWorkspace::Json {
- project,
- sysroot,
- rustc_cfg,
- toolchain,
- target_layout: data_layout,
- cfg_overrides,
- } => {
+ ProjectWorkspaceKind::Json(project) => {
let mut debug_struct = f.debug_struct("Json");
debug_struct.field("n_crates", &project.n_crates());
if let Ok(sysroot) = sysroot {
@@ -164,18 +131,14 @@ impl fmt::Debug for ProjectWorkspace {
debug_struct
.field("n_rustc_cfg", &rustc_cfg.len())
.field("toolchain", &toolchain)
- .field("data_layout", &data_layout)
+ .field("data_layout", &target_layout)
.field("n_cfg_overrides", &cfg_overrides.len());
debug_struct.finish()
}
- ProjectWorkspace::DetachedFile {
+ ProjectWorkspaceKind::DetachedFile {
file,
- sysroot,
- rustc_cfg,
- toolchain,
- target_layout,
- cfg_overrides,
- cargo_script,
+ cargo: cargo_script,
+ cargo_config_extra_env,
} => f
.debug_struct("DetachedFiles")
.field("file", &file)
@@ -186,6 +149,7 @@ impl fmt::Debug for ProjectWorkspace {
.field("toolchain", &toolchain)
.field("data_layout", &target_layout)
.field("n_cfg_overrides", &cfg_overrides.len())
+ .field("cargo_config_extra_env", &cargo_config_extra_env)
.finish(),
}
}
@@ -361,18 +325,20 @@ impl ProjectWorkspace {
let cargo_config_extra_env =
cargo_config_env(cargo_toml, &config.extra_env, sysroot_ref);
- ProjectWorkspace::Cargo {
- cargo,
- build_scripts: WorkspaceBuildScripts::default(),
+ ProjectWorkspace {
+ kind: ProjectWorkspaceKind::Cargo {
+ cargo,
+ build_scripts: WorkspaceBuildScripts::default(),
+ rustc,
+ cargo_config_extra_env,
+ },
sysroot,
- rustc,
rustc_cfg,
cfg_overrides,
toolchain,
target_layout: data_layout
.map(Arc::from)
.map_err(|it| Arc::from(it.to_string())),
- cargo_config_extra_env,
}
}
};
@@ -425,8 +391,8 @@ impl ProjectWorkspace {
let rustc_cfg = rustc_cfg::get(target, extra_env, cfg_config);
let data_layout = target_data_layout::get(data_layout_config, target, extra_env);
- ProjectWorkspace::Json {
- project: project_json,
+ ProjectWorkspace {
+ kind: ProjectWorkspaceKind::Json(project_json),
sysroot,
rustc_cfg,
toolchain,
@@ -484,14 +450,19 @@ impl ProjectWorkspace {
)
});
- Ok(ProjectWorkspace::DetachedFile {
- file: detached_file.to_owned(),
+ let cargo_config_extra_env =
+ cargo_config_env(detached_file, &config.extra_env, sysroot_ref);
+ Ok(ProjectWorkspace {
+ kind: ProjectWorkspaceKind::DetachedFile {
+ file: detached_file.to_owned(),
+ cargo: cargo_script,
+ cargo_config_extra_env,
+ },
sysroot,
rustc_cfg,
toolchain,
target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
cfg_overrides: config.cfg_overrides.clone(),
- cargo_script,
})
}
@@ -508,27 +479,22 @@ impl ProjectWorkspace {
config: &CargoConfig,
progress: &dyn Fn(String),
) -> anyhow::Result<WorkspaceBuildScripts> {
- match self {
- ProjectWorkspace::DetachedFile {
- cargo_script: Some((cargo, _)),
- toolchain,
- sysroot,
- ..
- }
- | ProjectWorkspace::Cargo { cargo, toolchain, sysroot, .. } => {
+ match &self.kind {
+ ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. }
+ | ProjectWorkspaceKind::Cargo { cargo, .. } => {
WorkspaceBuildScripts::run_for_workspace(
config,
cargo,
progress,
- toolchain,
- sysroot.as_ref().ok(),
+ &self.toolchain,
+ self.sysroot.as_ref().ok(),
)
.with_context(|| {
format!("Failed to run build scripts for {}", cargo.workspace_root())
})
}
- ProjectWorkspace::DetachedFile { cargo_script: None, .. }
- | ProjectWorkspace::Json { .. } => Ok(WorkspaceBuildScripts::default()),
+ ProjectWorkspaceKind::DetachedFile { cargo: None, .. }
+ | ProjectWorkspaceKind::Json { .. } => Ok(WorkspaceBuildScripts::default()),
}
}
@@ -548,8 +514,8 @@ impl ProjectWorkspace {
let cargo_ws: Vec<_> = workspaces
.iter()
- .filter_map(|it| match it {
- ProjectWorkspace::Cargo { cargo, .. } => Some(cargo),
+ .filter_map(|it| match &it.kind {
+ ProjectWorkspaceKind::Cargo { cargo, .. } => Some(cargo),
_ => None,
})
.collect();
@@ -563,8 +529,8 @@ impl ProjectWorkspace {
workspaces
.iter()
- .map(|it| match it {
- ProjectWorkspace::Cargo { cargo, .. } => match outputs {
+ .map(|it| match &it.kind {
+ ProjectWorkspaceKind::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())
@@ -576,40 +542,33 @@ impl ProjectWorkspace {
}
pub fn set_build_scripts(&mut self, bs: WorkspaceBuildScripts) {
- match self {
- ProjectWorkspace::Cargo { build_scripts, .. }
- | ProjectWorkspace::DetachedFile { cargo_script: Some((_, build_scripts)), .. } => {
+ match &mut self.kind {
+ ProjectWorkspaceKind::Cargo { build_scripts, .. }
+ | ProjectWorkspaceKind::DetachedFile { cargo: Some((_, build_scripts)), .. } => {
*build_scripts = bs
}
_ => assert_eq!(bs, WorkspaceBuildScripts::default()),
}
}
- pub fn workspace_definition_path(&self) -> &AbsPath {
- match self {
- ProjectWorkspace::Cargo { cargo, .. } => cargo.workspace_root(),
- ProjectWorkspace::Json { project, .. } => project.path(),
- ProjectWorkspace::DetachedFile { file, .. } => file,
+ pub fn manifest_or_root(&self) -> &AbsPath {
+ match &self.kind {
+ ProjectWorkspaceKind::Cargo { cargo, .. } => cargo.manifest_path(),
+ ProjectWorkspaceKind::Json(project) => project.path(),
+ ProjectWorkspaceKind::DetachedFile { file, .. } => file,
}
}
pub fn find_sysroot_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> {
- match self {
- ProjectWorkspace::Cargo { sysroot: Ok(sysroot), .. }
- | ProjectWorkspace::Json { sysroot: Ok(sysroot), .. }
- | ProjectWorkspace::DetachedFile { sysroot: Ok(sysroot), .. } => {
- sysroot.discover_proc_macro_srv()
- }
- ProjectWorkspace::DetachedFile { .. } => {
- Err(anyhow::format_err!("cannot find proc-macro server, no sysroot was found"))
- }
- ProjectWorkspace::Cargo { cargo, .. } => Err(anyhow::format_err!(
- "cannot find proc-macro-srv, the workspace `{}` is missing a sysroot",
- cargo.workspace_root()
+ match &self.sysroot {
+ Ok(sysroot) => sysroot.discover_proc_macro_srv(),
+ Err(None) => Err(anyhow::format_err!(
+ "cannot find proc-macro server, the workspace `{}` is missing a sysroot",
+ self.manifest_or_root()
)),
- ProjectWorkspace::Json { project, .. } => Err(anyhow::format_err!(
- "cannot find proc-macro-srv, the workspace `{}` is missing a sysroot",
- project.path()
+ Err(Some(e)) => Err(anyhow::format_err!(
+ "cannot find proc-macro server, the workspace `{}` is missing a sysroot: {e}",
+ self.manifest_or_root()
)),
}
}
@@ -618,8 +577,8 @@ impl ProjectWorkspace {
/// The return type contains the path and whether or not
/// the root is a member of the current workspace
pub fn to_roots(&self) -> Vec<PackageRoot> {
- let mk_sysroot = |sysroot: Result<_, _>| {
- sysroot.into_iter().flat_map(move |sysroot: &Sysroot| {
+ let mk_sysroot = || {
+ self.sysroot.as_ref().into_iter().flat_map(move |sysroot: &Sysroot| {
let mut r = match sysroot.mode() {
SysrootMode::Workspace(ws) => ws
.packages()
@@ -653,15 +612,8 @@ impl ProjectWorkspace {
r
})
};
- match self {
- ProjectWorkspace::Json {
- project,
- sysroot,
- rustc_cfg: _,
- toolchain: _,
- target_layout: _,
- cfg_overrides: _,
- } => project
+ match &self.kind {
+ ProjectWorkspaceKind::Json(project) => project
.crates()
.map(|(_, krate)| PackageRoot {
is_local: krate.is_workspace_member,
@@ -670,17 +622,12 @@ impl ProjectWorkspace {
})
.collect::<FxHashSet<_>>()
.into_iter()
- .chain(mk_sysroot(sysroot.as_ref()))
+ .chain(mk_sysroot())
.collect::<Vec<_>>(),
- ProjectWorkspace::Cargo {
+ ProjectWorkspaceKind::Cargo {
cargo,
- sysroot,
rustc,
- rustc_cfg: _,
- cfg_overrides: _,
build_scripts,
- toolchain: _,
- target_layout: _,
cargo_config_extra_env: _,
} => {
cargo
@@ -721,7 +668,7 @@ impl ProjectWorkspace {
}
PackageRoot { is_local, include, exclude }
})
- .chain(mk_sysroot(sysroot.as_ref()))
+ .chain(mk_sysroot())
.chain(rustc.iter().map(|a| a.as_ref()).flat_map(|(rustc, _)| {
rustc.packages().map(move |krate| PackageRoot {
is_local: false,
@@ -731,7 +678,7 @@ impl ProjectWorkspace {
}))
.collect()
}
- ProjectWorkspace::DetachedFile { file, cargo_script, sysroot, .. } => {
+ ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, .. } => {
iter::once(PackageRoot {
is_local: true,
include: vec![file.as_ref().to_owned()],
@@ -775,26 +722,26 @@ impl ProjectWorkspace {
PackageRoot { is_local, include, exclude }
})
}))
- .chain(mk_sysroot(sysroot.as_ref()))
+ .chain(mk_sysroot())
.collect()
}
}
}
pub fn n_packages(&self) -> usize {
- match self {
- ProjectWorkspace::Json { project, sysroot, .. } => {
- let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages());
+ match &self.kind {
+ ProjectWorkspaceKind::Json(project) => {
+ let sysroot_package_len = self.sysroot.as_ref().map_or(0, |it| it.num_packages());
sysroot_package_len + project.n_crates()
}
- ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => {
+ ProjectWorkspaceKind::Cargo { cargo, rustc, .. } => {
let rustc_package_len =
rustc.as_ref().map(|a| a.as_ref()).map_or(0, |(it, _)| it.packages().len());
- let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages());
+ let sysroot_package_len = self.sysroot.as_ref().map_or(0, |it| it.num_packages());
cargo.packages().len() + sysroot_package_len + rustc_package_len
}
- ProjectWorkspace::DetachedFile { sysroot, cargo_script, .. } => {
- let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages());
+ ProjectWorkspaceKind::DetachedFile { cargo: cargo_script, .. } => {
+ let sysroot_package_len = self.sysroot.as_ref().map_or(0, |it| it.num_packages());
sysroot_package_len
+ cargo_script.as_ref().map_or(1, |(cargo, _)| cargo.packages().len())
}
@@ -808,15 +755,9 @@ impl ProjectWorkspace {
) -> (CrateGraph, ProcMacroPaths) {
let _p = tracing::span!(tracing::Level::INFO, "ProjectWorkspace::to_crate_graph").entered();
- let ((mut crate_graph, proc_macros), sysroot) = match self {
- ProjectWorkspace::Json {
- project,
- sysroot,
- rustc_cfg,
- toolchain: _,
- target_layout: _,
- cfg_overrides,
- } => (
+ let Self { kind, sysroot, cfg_overrides, rustc_cfg, .. } = self;
+ let ((mut crate_graph, proc_macros), sysroot) = match kind {
+ ProjectWorkspaceKind::Json(project) => (
project_json_to_crate_graph(
rustc_cfg.clone(),
load,
@@ -827,15 +768,10 @@ impl ProjectWorkspace {
),
sysroot,
),
- ProjectWorkspace::Cargo {
+ ProjectWorkspaceKind::Cargo {
cargo,
- sysroot,
rustc,
- rustc_cfg,
- cfg_overrides,
build_scripts,
- toolchain: _,
- target_layout: _,
cargo_config_extra_env: _,
} => (
cargo_to_crate_graph(
@@ -849,15 +785,7 @@ impl ProjectWorkspace {
),
sysroot,
),
- ProjectWorkspace::DetachedFile {
- file,
- sysroot,
- rustc_cfg,
- toolchain: _,
- target_layout: _,
- cfg_overrides,
- cargo_script,
- } => (
+ ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, .. } => (
if let Some((cargo, build_scripts)) = cargo_script {
cargo_to_crate_graph(
&mut |path| load(path),
@@ -892,93 +820,60 @@ impl ProjectWorkspace {
}
pub fn eq_ignore_build_data(&self, other: &Self) -> bool {
- match (self, other) {
+ let Self { kind, sysroot, rustc_cfg, toolchain, target_layout, cfg_overrides, .. } = self;
+ let Self {
+ kind: o_kind,
+ sysroot: o_sysroot,
+ rustc_cfg: o_rustc_cfg,
+ toolchain: o_toolchain,
+ target_layout: o_target_layout,
+ cfg_overrides: o_cfg_overrides,
+ ..
+ } = other;
+ (match (kind, o_kind) {
(
- Self::Cargo {
+ ProjectWorkspaceKind::Cargo {
cargo,
- sysroot,
rustc,
- rustc_cfg,
- cfg_overrides,
- toolchain,
cargo_config_extra_env,
build_scripts: _,
- target_layout: _,
},
- Self::Cargo {
+ ProjectWorkspaceKind::Cargo {
cargo: o_cargo,
- sysroot: o_sysroot,
rustc: o_rustc,
- rustc_cfg: o_rustc_cfg,
- cfg_overrides: o_cfg_overrides,
- toolchain: o_toolchain,
cargo_config_extra_env: o_cargo_config_extra_env,
build_scripts: _,
- target_layout: _,
},
) => {
cargo == o_cargo
&& rustc == o_rustc
- && rustc_cfg == o_rustc_cfg
- && cfg_overrides == o_cfg_overrides
- && toolchain == o_toolchain
- && sysroot == o_sysroot
&& cargo_config_extra_env == o_cargo_config_extra_env
}
- (
- Self::Json {
- project,
- sysroot,
- rustc_cfg,
- toolchain,
- target_layout: _,
- cfg_overrides,
- },
- Self::Json {
- project: o_project,
- sysroot: o_sysroot,
- rustc_cfg: o_rustc_cfg,
- toolchain: o_toolchain,
- target_layout: _,
- cfg_overrides: o_cfg_overrides,
- },
- ) => {
+ (ProjectWorkspaceKind::Json(project), ProjectWorkspaceKind::Json(o_project)) => {
project == o_project
- && rustc_cfg == o_rustc_cfg
- && sysroot == o_sysroot
- && toolchain == o_toolchain
- && cfg_overrides == o_cfg_overrides
}
(
- Self::DetachedFile {
+ ProjectWorkspaceKind::DetachedFile {
file,
- sysroot,
- rustc_cfg,
- cargo_script: Some((cargo_script, _)),
- toolchain,
- target_layout,
- cfg_overrides,
+ cargo: Some((cargo_script, _)),
+ cargo_config_extra_env,
},
- Self::DetachedFile {
+ ProjectWorkspaceKind::DetachedFile {
file: o_file,
- sysroot: o_sysroot,
- rustc_cfg: o_rustc_cfg,
- cargo_script: Some((o_cargo_script, _)),
- toolchain: o_toolchain,
- target_layout: o_target_layout,
- cfg_overrides: o_cfg_overrides,
+ cargo: Some((o_cargo_script, _)),
+ cargo_config_extra_env: o_cargo_config_extra_env,
},
) => {
file == o_file
- && sysroot == o_sysroot
- && rustc_cfg == o_rustc_cfg
- && toolchain == o_toolchain
- && target_layout == o_target_layout
- && cfg_overrides == o_cfg_overrides
&& cargo_script == o_cargo_script
+ && cargo_config_extra_env == o_cargo_config_extra_env
}
- _ => false,
- }
+ _ => return false,
+ }) && sysroot == o_sysroot
+ && rustc_cfg == o_rustc_cfg
+ && toolchain == o_toolchain
+ && target_layout == o_target_layout
+ && cfg_overrides == o_cfg_overrides
}
/// Returns `true` if the project workspace is [`Json`].
@@ -986,7 +881,7 @@ impl ProjectWorkspace {
/// [`Json`]: ProjectWorkspace::Json
#[must_use]
pub fn is_json(&self) -> bool {
- matches!(self, Self::Json { .. })
+ matches!(self.kind, ProjectWorkspaceKind::Json { .. })
}
}