Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/project-model/src/cargo_workspace.rs')
-rw-r--r--crates/project-model/src/cargo_workspace.rs61
1 files changed, 52 insertions, 9 deletions
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index 38eeedec62..7cc21bcf13 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -13,7 +13,7 @@ use serde_json::from_value;
use span::Edition;
use toolchain::Tool;
-use crate::{utf8_stdout, InvocationLocation, ManifestPath, Sysroot};
+use crate::{utf8_stdout, ManifestPath, Sysroot};
use crate::{CfgOverrides, InvocationStrategy};
/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
@@ -98,7 +98,6 @@ pub struct CargoConfig {
/// Extra env vars to set when invoking the cargo command
pub extra_env: FxHashMap<String, String>,
pub invocation_strategy: InvocationStrategy,
- pub invocation_location: InvocationLocation,
/// Optional path to use instead of `target` when building
pub target_dir: Option<Utf8PathBuf>,
}
@@ -242,6 +241,10 @@ impl TargetKind {
pub fn is_executable(self) -> bool {
matches!(self, TargetKind::Bin | TargetKind::Example)
}
+
+ pub fn is_proc_macro(self) -> bool {
+ matches!(self, TargetKind::Lib { is_proc_macro: true })
+ }
}
// Deserialize helper for the cargo metadata
@@ -252,6 +255,9 @@ struct PackageMetadata {
}
impl CargoWorkspace {
+ /// Fetches the metadata for the given `cargo_toml` manifest.
+ /// A successful result may contain another metadata error if the initial fetching failed but
+ /// the `--no-deps` retry succeeded.
pub fn fetch_metadata(
cargo_toml: &ManifestPath,
current_dir: &AbsPath,
@@ -259,7 +265,19 @@ impl CargoWorkspace {
sysroot: &Sysroot,
locked: bool,
progress: &dyn Fn(String),
- ) -> anyhow::Result<cargo_metadata::Metadata> {
+ ) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
+ Self::fetch_metadata_(cargo_toml, current_dir, config, sysroot, locked, false, progress)
+ }
+
+ fn fetch_metadata_(
+ cargo_toml: &ManifestPath,
+ current_dir: &AbsPath,
+ config: &CargoConfig,
+ sysroot: &Sysroot,
+ locked: bool,
+ no_deps: bool,
+ progress: &dyn Fn(String),
+ ) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
let targets = find_list_of_build_targets(config, cargo_toml, sysroot);
let cargo = sysroot.tool(Tool::Cargo);
@@ -314,6 +332,9 @@ impl CargoWorkspace {
if locked {
other_options.push("--locked".to_owned());
}
+ if no_deps {
+ other_options.push("--no-deps".to_owned());
+ }
meta.other_options(other_options);
// FIXME: Fetching metadata is a slow process, as it might require
@@ -321,19 +342,42 @@ impl CargoWorkspace {
// unclear whether cargo itself supports it.
progress("metadata".to_owned());
- (|| -> Result<cargo_metadata::Metadata, cargo_metadata::Error> {
+ (|| -> anyhow::Result<(_, _)> {
let output = meta.cargo_command().output()?;
if !output.status.success() {
- return Err(cargo_metadata::Error::CargoMetadata {
+ let error = cargo_metadata::Error::CargoMetadata {
stderr: String::from_utf8(output.stderr)?,
- });
+ }
+ .into();
+ if !no_deps {
+ // If we failed to fetch metadata with deps, try again without them.
+ // This makes r-a still work partially when offline.
+ if let Ok((metadata, _)) = Self::fetch_metadata_(
+ cargo_toml,
+ current_dir,
+ config,
+ sysroot,
+ locked,
+ true,
+ progress,
+ ) {
+ return Ok((metadata, Some(error)));
+ }
+ }
+ return Err(error);
}
let stdout = from_utf8(&output.stdout)?
.lines()
.find(|line| line.starts_with('{'))
.ok_or(cargo_metadata::Error::NoJson)?;
- cargo_metadata::MetadataCommand::parse(stdout)
+ Ok((cargo_metadata::MetadataCommand::parse(stdout)?, None))
})()
+ .map(|(metadata, error)| {
+ (
+ metadata,
+ error.map(|e| e.context(format!("Failed to run `{:?}`", meta.cargo_command()))),
+ )
+ })
.with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))
}
@@ -431,8 +475,7 @@ impl CargoWorkspace {
pkg_data.targets.push(tgt);
}
}
- let resolve = meta.resolve.expect("metadata executed with deps");
- for mut node in resolve.nodes {
+ for mut node in meta.resolve.map_or_else(Vec::new, |it| it.nodes) {
let &source = pkg_by_id.get(&node.id).unwrap();
node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg));
let dependencies = node