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.rs | 114 |
1 files changed, 26 insertions, 88 deletions
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index ba4946bf0b..4d906c2aeb 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -4,6 +4,7 @@ use std::ops; use std::str::from_utf8; use anyhow::Context; +use base_db::Env; use cargo_metadata::{CargoOpt, MetadataCommand}; use la_arena::{Arena, Idx}; use paths::{AbsPath, AbsPathBuf, Utf8PathBuf}; @@ -13,8 +14,8 @@ use serde_json::from_value; use span::Edition; use toolchain::Tool; -use crate::{utf8_stdout, ManifestPath, Sysroot, SysrootQueryMetadata}; use crate::{CfgOverrides, InvocationStrategy}; +use crate::{ManifestPath, Sysroot}; /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo /// workspace. It pretty closely mirrors `cargo metadata` output. @@ -34,6 +35,8 @@ pub struct CargoWorkspace { target_directory: AbsPathBuf, manifest_path: ManifestPath, is_virtual_workspace: bool, + /// Environment variables set in the `.cargo/config` file. + config_env: Env, } impl ops::Index<Package> for CargoWorkspace { @@ -86,8 +89,6 @@ pub struct CargoConfig { pub target: Option<String>, /// Sysroot loading behavior pub sysroot: Option<RustLibSource>, - /// How to query metadata for the sysroot crate. - pub sysroot_query_metadata: SysrootQueryMetadata, pub sysroot_src: Option<AbsPathBuf>, /// rustc private crate source pub rustc_source: Option<RustLibSource>, @@ -251,6 +252,18 @@ impl TargetKind { } } +#[derive(Default, Clone, Debug, PartialEq, Eq)] +pub struct CargoMetadataConfig { + /// List of features to activate. + pub features: CargoFeatures, + /// rustc targets + pub targets: Vec<String>, + /// Extra args to pass to the cargo command. + pub extra_args: Vec<String>, + /// Extra env vars to set when invoking the cargo command + pub extra_env: FxHashMap<String, String>, +} + // Deserialize helper for the cargo metadata #[derive(Deserialize, Default)] struct PackageMetadata { @@ -265,7 +278,7 @@ impl CargoWorkspace { pub fn fetch_metadata( cargo_toml: &ManifestPath, current_dir: &AbsPath, - config: &CargoConfig, + config: &CargoMetadataConfig, sysroot: &Sysroot, locked: bool, progress: &dyn Fn(String), @@ -276,15 +289,13 @@ impl CargoWorkspace { fn fetch_metadata_( cargo_toml: &ManifestPath, current_dir: &AbsPath, - config: &CargoConfig, + config: &CargoMetadataConfig, 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); + let cargo = sysroot.tool(Tool::Cargo, current_dir); let mut meta = MetadataCommand::new(); meta.cargo_path(cargo.get_program()); cargo.get_envs().for_each(|(var, val)| _ = meta.env(var, val.unwrap_or_default())); @@ -319,12 +330,9 @@ impl CargoWorkspace { } } - if !targets.is_empty() { - other_options.append( - &mut targets - .into_iter() - .flat_map(|target| ["--filter-platform".to_owned(), target]) - .collect(), + if !config.targets.is_empty() { + other_options.extend( + config.targets.iter().flat_map(|it| ["--filter-platform".to_owned(), it.clone()]), ); } // The manifest is a rust file, so this means its a script manifest @@ -388,6 +396,7 @@ impl CargoWorkspace { pub fn new( mut meta: cargo_metadata::Metadata, ws_manifest_path: ManifestPath, + cargo_config_env: Env, ) -> CargoWorkspace { let mut pkg_by_id = FxHashMap::default(); let mut packages = Arena::default(); @@ -509,6 +518,7 @@ impl CargoWorkspace { target_directory, manifest_path: ws_manifest_path, is_virtual_workspace, + config_env: cargo_config_env, } } @@ -595,80 +605,8 @@ impl CargoWorkspace { pub fn is_virtual_workspace(&self) -> bool { self.is_virtual_workspace } -} - -fn find_list_of_build_targets( - config: &CargoConfig, - cargo_toml: &ManifestPath, - sysroot: &Sysroot, -) -> Vec<String> { - if let Some(target) = &config.target { - return [target.into()].to_vec(); - } - - let build_targets = cargo_config_build_target(cargo_toml, &config.extra_env, sysroot); - if !build_targets.is_empty() { - return build_targets; - } - - rustc_discover_host_triple(cargo_toml, &config.extra_env, sysroot).into_iter().collect() -} - -fn rustc_discover_host_triple( - cargo_toml: &ManifestPath, - extra_env: &FxHashMap<String, String>, - sysroot: &Sysroot, -) -> Option<String> { - let mut rustc = sysroot.tool(Tool::Rustc); - rustc.envs(extra_env); - rustc.current_dir(cargo_toml.parent()).arg("-vV"); - tracing::debug!("Discovering host platform by {:?}", rustc); - match utf8_stdout(rustc) { - Ok(stdout) => { - let field = "host: "; - let target = stdout.lines().find_map(|l| l.strip_prefix(field)); - if let Some(target) = target { - Some(target.to_owned()) - } else { - // If we fail to resolve the host platform, it's not the end of the world. - tracing::info!("rustc -vV did not report host platform, got:\n{}", stdout); - None - } - } - Err(e) => { - tracing::warn!("Failed to discover host platform: {}", e); - None - } - } -} - -fn cargo_config_build_target( - cargo_toml: &ManifestPath, - extra_env: &FxHashMap<String, String>, - sysroot: &Sysroot, -) -> Vec<String> { - let mut cargo_config = sysroot.tool(Tool::Cargo); - cargo_config.envs(extra_env); - cargo_config - .current_dir(cargo_toml.parent()) - .args(["-Z", "unstable-options", "config", "get", "build.target"]) - .env("RUSTC_BOOTSTRAP", "1"); - // if successful we receive `build.target = "target-triple"` - // or `build.target = ["<target 1>", ..]` - tracing::debug!("Discovering cargo config target by {:?}", cargo_config); - utf8_stdout(cargo_config).map(parse_output_cargo_config_build_target).unwrap_or_default() -} - -fn parse_output_cargo_config_build_target(stdout: String) -> Vec<String> { - let trimmed = stdout.trim_start_matches("build.target = ").trim_matches('"'); - - if !trimmed.starts_with('[') { - return [trimmed.to_owned()].to_vec(); - } - let res = serde_json::from_str(trimmed); - if let Err(e) = &res { - tracing::warn!("Failed to parse `build.target` as an array of target: {}`", e); + pub fn env(&self) -> &Env { + &self.config_env } - res.unwrap_or_default() } |