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.rs114
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()
}