Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/project-model/src/sysroot.rs')
-rw-r--r--crates/project-model/src/sysroot.rs100
1 files changed, 60 insertions, 40 deletions
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs
index d4055d9a0a..9781c46737 100644
--- a/crates/project-model/src/sysroot.rs
+++ b/crates/project-model/src/sysroot.rs
@@ -4,18 +4,20 @@
//! but we can't process `.rlib` and need source code instead. The source code
//! is typically installed with `rustup component add rust-src` command.
+use core::fmt;
use std::{env, fs, ops::Not, path::Path, process::Command};
use anyhow::{Result, format_err};
use itertools::Itertools;
-use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
use rustc_hash::FxHashMap;
use stdx::format_to;
use toolchain::{Tool, probe_for_binary};
use crate::{
CargoWorkspace, ManifestPath, ProjectJson, RustSourceWorkspaceConfig,
- cargo_workspace::CargoMetadataConfig, utf8_stdout,
+ cargo_workspace::{CargoMetadataConfig, FetchMetadata},
+ utf8_stdout,
};
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -34,6 +36,19 @@ pub enum RustLibSrcWorkspace {
Empty,
}
+impl fmt::Display for RustLibSrcWorkspace {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ RustLibSrcWorkspace::Workspace(ws) => write!(f, "workspace {}", ws.workspace_root()),
+ RustLibSrcWorkspace::Json(json) => write!(f, "json {}", json.manifest_or_root()),
+ RustLibSrcWorkspace::Stitched(stitched) => {
+ write!(f, "stitched with {} crates", stitched.crates.len())
+ }
+ RustLibSrcWorkspace::Empty => write!(f, "empty"),
+ }
+ }
+}
+
impl Sysroot {
pub const fn empty() -> Sysroot {
Sysroot {
@@ -149,18 +164,18 @@ impl Sysroot {
}
}
- pub fn discover_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> {
- let Some(root) = self.root() else {
- return Err(anyhow::format_err!("no sysroot",));
- };
- ["libexec", "lib"]
- .into_iter()
- .map(|segment| root.join(segment).join("rust-analyzer-proc-macro-srv"))
- .find_map(|server_path| probe_for_binary(server_path.into()))
- .map(AbsPathBuf::assert)
- .ok_or_else(|| {
- anyhow::format_err!("cannot find proc-macro server in sysroot `{}`", root)
- })
+ pub fn discover_proc_macro_srv(&self) -> Option<anyhow::Result<AbsPathBuf>> {
+ let root = self.root()?;
+ Some(
+ ["libexec", "lib"]
+ .into_iter()
+ .map(|segment| root.join(segment).join("rust-analyzer-proc-macro-srv"))
+ .find_map(|server_path| probe_for_binary(server_path.into()))
+ .map(AbsPathBuf::assert)
+ .ok_or_else(|| {
+ anyhow::format_err!("cannot find proc-macro server in sysroot `{}`", root)
+ }),
+ )
}
fn assemble(
@@ -195,6 +210,10 @@ impl Sysroot {
pub fn load_workspace(
&self,
sysroot_source_config: &RustSourceWorkspaceConfig,
+ no_deps: bool,
+ current_dir: &AbsPath,
+ target_dir: &Utf8Path,
+ progress: &dyn Fn(String),
) -> Option<RustLibSrcWorkspace> {
assert!(matches!(self.workspace, RustLibSrcWorkspace::Empty), "workspace already loaded");
let Self { root: _, rust_lib_src_root: Some(src_root), workspace: _, error: _ } = self
@@ -204,10 +223,18 @@ impl Sysroot {
if let RustSourceWorkspaceConfig::CargoMetadata(cargo_config) = sysroot_source_config {
let library_manifest = ManifestPath::try_from(src_root.join("Cargo.toml")).unwrap();
if fs::metadata(&library_manifest).is_ok() {
- if let Some(loaded) =
- self.load_library_via_cargo(library_manifest, src_root, cargo_config)
- {
- return Some(loaded);
+ match self.load_library_via_cargo(
+ &library_manifest,
+ current_dir,
+ target_dir,
+ cargo_config,
+ no_deps,
+ progress,
+ ) {
+ Ok(loaded) => return Some(loaded),
+ Err(e) => {
+ tracing::error!("`cargo metadata` failed on `{library_manifest}` : {e}")
+ }
}
}
tracing::debug!("Stitching sysroot library: {src_root}");
@@ -293,10 +320,13 @@ impl Sysroot {
fn load_library_via_cargo(
&self,
- library_manifest: ManifestPath,
- rust_lib_src_dir: &AbsPathBuf,
+ library_manifest: &ManifestPath,
+ current_dir: &AbsPath,
+ target_dir: &Utf8Path,
cargo_config: &CargoMetadataConfig,
- ) -> Option<RustLibSrcWorkspace> {
+ no_deps: bool,
+ progress: &dyn Fn(String),
+ ) -> Result<RustLibSrcWorkspace> {
tracing::debug!("Loading library metadata: {library_manifest}");
let mut cargo_config = cargo_config.clone();
// the sysroot uses `public-dependency`, so we make cargo think it's a nightly
@@ -305,22 +335,11 @@ impl Sysroot {
Some("nightly".to_owned()),
);
- let (mut res, _) = match CargoWorkspace::fetch_metadata(
- &library_manifest,
- rust_lib_src_dir,
- &cargo_config,
- self,
- false,
- // Make sure we never attempt to write to the sysroot
- true,
- &|_| (),
- ) {
- Ok(it) => it,
- Err(e) => {
- tracing::error!("`cargo metadata` failed on `{library_manifest}` : {e}");
- return None;
- }
- };
+ // Make sure we never attempt to write to the sysroot
+ let locked = true;
+ let (mut res, _) =
+ FetchMetadata::new(library_manifest, current_dir, &cargo_config, self, no_deps)
+ .exec(target_dir, locked, progress)?;
// Patch out `rustc-std-workspace-*` crates to point to the real crates.
// This is done prior to `CrateGraph` construction to prevent de-duplication logic from failing.
@@ -339,7 +358,7 @@ impl Sysroot {
Some(_) => {
tracing::warn!("unknown rustc-std-workspace-* crate: {}", package.name)
}
- None => match &*package.name {
+ None => match &**package.name {
"core" => real_core = Some(package.id.clone()),
"alloc" => real_alloc = Some(package.id.clone()),
"std" => real_std = Some(package.id.clone()),
@@ -371,8 +390,9 @@ impl Sysroot {
res.packages.remove(idx);
});
- let cargo_workspace = CargoWorkspace::new(res, library_manifest, Default::default(), true);
- Some(RustLibSrcWorkspace::Workspace(cargo_workspace))
+ let cargo_workspace =
+ CargoWorkspace::new(res, library_manifest.clone(), Default::default(), true);
+ Ok(RustLibSrcWorkspace::Workspace(cargo_workspace))
}
}