diff --git a/src/cargo/core/profiles.rs b/src/cargo/core/profiles.rs index 1ad9ed5f725..2897dab42a5 100644 --- a/src/cargo/core/profiles.rs +++ b/src/cargo/core/profiles.rs @@ -8,8 +8,8 @@ //! //! - Create a `Profiles` by merging profiles from configs onto the profile //! from root manifest (see [`merge_config_profiles`]). -//! - Add built-in profiles onto it (see [`Profiles::add_root_profiles`]). -//! - Process profile inheritance for each profiles. (see [`Profiles::add_maker`]). +//! - Add built-in profiles onto it (see [`root_profiles`]). +//! - Process profile inheritance for each profiles. (see [`create_profile_maker`]). //! //! Then you can query a [`Profile`] via [`Profiles::get_profile`], which respects //! the profile overridden hierarchy described in below. The [`Profile`] you get @@ -31,6 +31,7 @@ use crate::util::toml::{ }; use crate::util::{closest_msg, config, CargoResult, Config}; use anyhow::{bail, Context as _}; +use std::collections::btree_map::Entry; use std::collections::{BTreeMap, HashMap, HashSet}; use std::hash::Hash; use std::{cmp, fmt, hash}; @@ -62,196 +63,84 @@ pub struct Profiles { } impl Profiles { + /// Returns all the profiles defined in a workspace, including root and predefined profiles. + /// This function resolves inheritances between profiles. + pub fn all(ws: &Workspace<'_>) -> CargoResult> { + let mut definitions = merge_config_profiles(ws, None)?; + + merge_predefined_profiles(&mut definitions); + + let mut makers = HashMap::new(); + for (name, profile) in root_profiles(&definitions) { + makers.insert(name, profile); + } + + for (name, profile) in &definitions { + let name = *name; + if let Some(maker) = create_profile_maker(name, profile, &makers, &definitions)? { + makers.insert(name, maker); + } + } + + for (name, profile) in &definitions { + let name = *name; + if let Some(maker) = create_profile_maker(name, profile, &makers, &definitions)? { + makers.insert(name, maker); + } + } + + let mut profiles = HashMap::new(); + for (name, maker) in makers { + profiles.insert(name, maker.get_profile(name, None, true, false)); + } + + Ok(profiles) + } + + /// Returns all the profiles defined in a workspace, verifying that + /// the requested profile exists in the workspace. pub fn new(ws: &Workspace<'_>, requested_profile: InternedString) -> CargoResult { let config = ws.config(); let incremental = match config.get_env_os("CARGO_INCREMENTAL") { Some(v) => Some(v == "1"), None => config.build_config()?.incremental, }; - let mut profiles = merge_config_profiles(ws, requested_profile)?; + let mut profiles = merge_config_profiles(ws, Some(requested_profile))?; let rustc_host = ws.config().load_global_rustc(Some(ws))?.host; let mut profile_makers = Profiles { incremental, - dir_names: Self::predefined_dir_names(), + dir_names: predefined_dir_names(), by_name: HashMap::new(), original_profiles: profiles.clone(), requested_profile, rustc_host, }; - Self::add_root_profiles(&mut profile_makers, &profiles); - - // Merge with predefined profiles. - use std::collections::btree_map::Entry; - for (predef_name, mut predef_prof) in Self::predefined_profiles().into_iter() { - match profiles.entry(InternedString::new(predef_name)) { - Entry::Vacant(vac) => { - vac.insert(predef_prof); - } - Entry::Occupied(mut oc) => { - // Override predefined with the user-provided Toml. - let r = oc.get_mut(); - predef_prof.merge(r); - *r = predef_prof; - } - } + for (name, profile) in root_profiles(&profiles) { + profile_makers.by_name.insert(name, profile); } + merge_predefined_profiles(&mut profiles); + for (name, profile) in &profiles { - profile_makers.add_maker(*name, profile, &profiles)?; + let name = *name; + if let Some(dir_name) = profile.dir_name { + profile_makers.dir_names.insert(name, dir_name.to_owned()); + } + if let Some(maker) = + create_profile_maker(name, profile, &profile_makers.by_name, &profiles)? + { + profile_makers.by_name.insert(name, maker); + } } // Verify that the requested profile is defined *somewhere*. // This simplifies the API (no need for CargoResult), and enforces // assumptions about how config profiles are loaded. - profile_makers.get_profile_maker(requested_profile)?; + get_profile_maker(&profile_makers.by_name, requested_profile)?; Ok(profile_makers) } - /// Returns the hard-coded directory names for built-in profiles. - fn predefined_dir_names() -> HashMap { - [ - (InternedString::new("dev"), InternedString::new("debug")), - (InternedString::new("test"), InternedString::new("debug")), - (InternedString::new("bench"), InternedString::new("release")), - ] - .into() - } - - /// Initialize `by_name` with the two "root" profiles, `dev`, and - /// `release` given the user's definition. - fn add_root_profiles( - profile_makers: &mut Profiles, - profiles: &BTreeMap, - ) { - profile_makers.by_name.insert( - InternedString::new("dev"), - ProfileMaker::new(Profile::default_dev(), profiles.get("dev").cloned()), - ); - - profile_makers.by_name.insert( - InternedString::new("release"), - ProfileMaker::new(Profile::default_release(), profiles.get("release").cloned()), - ); - } - - /// Returns the built-in profiles (not including dev/release, which are - /// "root" profiles). - fn predefined_profiles() -> Vec<(&'static str, TomlProfile)> { - vec![ - ( - "bench", - TomlProfile { - inherits: Some(InternedString::new("release")), - ..TomlProfile::default() - }, - ), - ( - "test", - TomlProfile { - inherits: Some(InternedString::new("dev")), - ..TomlProfile::default() - }, - ), - ( - "doc", - TomlProfile { - inherits: Some(InternedString::new("dev")), - ..TomlProfile::default() - }, - ), - ] - } - - /// Creates a `ProfileMaker`, and inserts it into `self.by_name`. - fn add_maker( - &mut self, - name: InternedString, - profile: &TomlProfile, - profiles: &BTreeMap, - ) -> CargoResult<()> { - match &profile.dir_name { - None => {} - Some(dir_name) => { - self.dir_names.insert(name, dir_name.to_owned()); - } - } - - // dev/release are "roots" and don't inherit. - if name == "dev" || name == "release" { - if profile.inherits.is_some() { - bail!( - "`inherits` must not be specified in root profile `{}`", - name - ); - } - // Already inserted from `add_root_profiles`, no need to do anything. - return Ok(()); - } - - // Keep track for inherits cycles. - let mut set = HashSet::new(); - set.insert(name); - let maker = self.process_chain(name, profile, &mut set, profiles)?; - self.by_name.insert(name, maker); - Ok(()) - } - - /// Build a `ProfileMaker` by recursively following the `inherits` setting. - /// - /// * `name`: The name of the profile being processed. - /// * `profile`: The TOML profile being processed. - /// * `set`: Set of profiles that have been visited, used to detect cycles. - /// * `profiles`: Map of all TOML profiles. - /// - /// Returns a `ProfileMaker` to be used for the given named profile. - fn process_chain( - &mut self, - name: InternedString, - profile: &TomlProfile, - set: &mut HashSet, - profiles: &BTreeMap, - ) -> CargoResult { - let mut maker = match profile.inherits { - Some(inherits_name) if inherits_name == "dev" || inherits_name == "release" => { - // These are the root profiles added in `add_root_profiles`. - self.get_profile_maker(inherits_name).unwrap().clone() - } - Some(inherits_name) => { - if !set.insert(inherits_name) { - bail!( - "profile inheritance loop detected with profile `{}` inheriting `{}`", - name, - inherits_name - ); - } - - match profiles.get(&inherits_name) { - None => { - bail!( - "profile `{}` inherits from `{}`, but that profile is not defined", - name, - inherits_name - ); - } - Some(parent) => self.process_chain(inherits_name, parent, set, profiles)?, - } - } - None => { - bail!( - "profile `{}` is missing an `inherits` directive \ - (`inherits` is required for all profiles except `dev` or `release`)", - name - ); - } - }; - match &mut maker.toml { - Some(toml) => toml.merge(profile), - None => maker.toml = Some(profile.clone()), - }; - Ok(maker) - } - /// Retrieves the profile for a target. /// `is_member` is whether or not this package is a member of the /// workspace. @@ -263,8 +152,13 @@ impl Profiles { unit_for: UnitFor, kind: CompileKind, ) -> Profile { - let maker = self.get_profile_maker(self.requested_profile).unwrap(); - let mut profile = maker.get_profile(Some(pkg_id), is_member, unit_for.is_for_host()); + let maker = get_profile_maker(&self.by_name, self.requested_profile).unwrap(); + let mut profile = maker.get_profile( + self.requested_profile, + Some(pkg_id), + is_member, + unit_for.is_for_host(), + ); // Dealing with `panic=abort` and `panic=unwind` requires some special // treatment. Be sure to process all the various options here. @@ -302,7 +196,6 @@ impl Profiles { if !is_local { profile.incremental = false; } - profile.name = self.requested_profile; profile } @@ -325,8 +218,13 @@ impl Profiles { /// select for the package that was actually built. pub fn base_profile(&self) -> Profile { let profile_name = self.requested_profile; - let maker = self.get_profile_maker(profile_name).unwrap(); - maker.get_profile(None, /*is_member*/ true, /*is_for_host*/ false) + let maker = get_profile_maker(&self.by_name, profile_name).unwrap(); + maker.get_profile( + profile_name, + None, + /*is_member*/ true, + /*is_for_host*/ false, + ) } /// Gets the directory name for a profile, like `debug` or `release`. @@ -370,13 +268,170 @@ impl Profiles { } Ok(()) } +} + +/// Returns the hard-coded directory names for built-in profiles. +fn predefined_dir_names() -> HashMap { + [ + (InternedString::new("dev"), InternedString::new("debug")), + (InternedString::new("test"), InternedString::new("debug")), + (InternedString::new("bench"), InternedString::new("release")), + ] + .into() +} + +/// Returns the "root" profiles (dev/release) +fn root_profiles( + profiles: &BTreeMap, +) -> Vec<(InternedString, ProfileMaker)> { + vec![ + ( + InternedString::new("dev"), + ProfileMaker::new(Profile::default_dev(), profiles.get("dev").cloned()), + ), + ( + InternedString::new("release"), + ProfileMaker::new(Profile::default_release(), profiles.get("release").cloned()), + ), + ] +} + +/// Returns the built-in profiles (not including dev/release, which are +/// "root" profiles). +fn predefined_profiles() -> Vec<(&'static str, TomlProfile)> { + vec![ + ( + "bench", + TomlProfile { + inherits: Some(InternedString::new("release")), + ..TomlProfile::default() + }, + ), + ( + "test", + TomlProfile { + inherits: Some(InternedString::new("dev")), + ..TomlProfile::default() + }, + ), + ( + "doc", + TomlProfile { + inherits: Some(InternedString::new("dev")), + ..TomlProfile::default() + }, + ), + ] +} + +/// Merge a list of TOML profile definitions with the predefined list from Cargo. +fn merge_predefined_profiles(definitions: &mut BTreeMap) { + for (predef_name, mut predef_prof) in predefined_profiles().into_iter() { + match definitions.entry(InternedString::new(predef_name)) { + Entry::Vacant(vac) => { + vac.insert(predef_prof); + } + Entry::Occupied(mut oc) => { + // Override predefined with the user-provided Toml. + let r = oc.get_mut(); + predef_prof.merge(r); + *r = predef_prof; + } + } + } +} - /// Returns the profile maker for the given profile name. - fn get_profile_maker(&self, name: InternedString) -> CargoResult<&ProfileMaker> { - self.by_name - .get(&name) - .ok_or_else(|| anyhow::format_err!("profile `{}` is not defined", name)) +/// Creates a `ProfileMaker`. +fn create_profile_maker( + name: InternedString, + profile: &TomlProfile, + makers: &HashMap, + definitions: &BTreeMap, +) -> CargoResult> { + // dev/release are "roots" and don't inherit. + if name == "dev" || name == "release" { + if profile.inherits.is_some() { + bail!( + "`inherits` must not be specified in root profile `{}`", + name + ); + } + // Already created in `root_profiles`, ignore them to prevent overwrites. + return Ok(None); } + + // Keep track for inherits cycles. + let mut set = HashSet::new(); + set.insert(name); + let maker = process_chain(name, profile, &mut set, makers, definitions)?; + Ok(Some(maker)) +} + +/// Build a `ProfileMaker` by recursively following the `inherits` setting. +/// +/// * `name`: The name of the profile being processed. +/// * `profile`: The TOML profile being processed. +/// * `set`: Set of profiles that have been visited, used to detect cycles. +/// * `makers`: Map of all `ProfileMaker` already defined in the workspace. +/// * `definitions`: Map of all TOML profiles. +/// +/// Returns a `ProfileMaker` to be used for the given named profile. +fn process_chain( + name: InternedString, + profile: &TomlProfile, + set: &mut HashSet, + makers: &HashMap, + definitions: &BTreeMap, +) -> CargoResult { + let mut maker = match profile.inherits { + Some(inherits_name) if inherits_name == "dev" || inherits_name == "release" => { + // These are the root profiles. They must exist in the list of makers + // before calling `process_chain`. + get_profile_maker(makers, inherits_name)?.clone() + } + Some(inherits_name) => { + if !set.insert(inherits_name) { + bail!( + "profile inheritance loop detected with profile `{}` inheriting `{}`", + name, + inherits_name + ); + } + + match definitions.get(&inherits_name) { + None => { + bail!( + "profile `{}` inherits from `{}`, but that profile is not defined", + name, + inherits_name + ); + } + Some(parent) => process_chain(inherits_name, parent, set, makers, definitions)?, + } + } + None => { + bail!( + "profile `{}` is missing an `inherits` directive \ + (`inherits` is required for all profiles except `dev` or `release`)", + name + ); + } + }; + match &mut maker.toml { + Some(toml) => toml.merge(profile), + None => maker.toml = Some(profile.clone()), + }; + Ok(maker) +} + +/// Returns the profile maker for the given profile name. +fn get_profile_maker( + profiles: &HashMap, + name: InternedString, +) -> CargoResult<&ProfileMaker> { + profiles + .get(&name) + .ok_or_else(|| anyhow::format_err!("profile `{}` is not defined", name)) } /// An object used for handling the profile hierarchy. @@ -413,6 +468,7 @@ impl ProfileMaker { /// Generates a new `Profile`. fn get_profile( &self, + name: InternedString, pkg_id: Option, is_member: bool, is_for_host: bool, @@ -457,6 +513,7 @@ impl ProfileMaker { if let Some(toml) = &self.toml { merge_toml_overrides(pkg_id, is_member, is_for_host, &mut profile, toml); } + profile.name = name; profile } } @@ -849,9 +906,7 @@ impl fmt::Display for PanicStrategy { } /// The setting for choosing which symbols to strip -#[derive( - Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize, -)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord, serde::Deserialize)] #[serde(rename_all = "lowercase")] pub enum Strip { /// Don't remove any symbols @@ -870,6 +925,18 @@ impl fmt::Display for Strip { } } +impl serde::ser::Serialize for Strip { + fn serialize(&self, s: S) -> Result + where + S: serde::ser::Serializer, + { + match self { + Strip::None => "none".serialize(s), + Strip::Named(n) => n.serialize(s), + } + } +} + /// Flags used in creating `Unit`s to indicate the purpose for the target, and /// to ensure the target's dependencies have the correct settings. /// @@ -1159,7 +1226,7 @@ impl UnitFor { /// Returns a new copy of the profile map with all the mergers complete. fn merge_config_profiles( ws: &Workspace<'_>, - requested_profile: InternedString, + requested_profile: Option, ) -> CargoResult> { let mut profiles = match ws.profiles() { Some(profiles) => profiles.get_all().clone(), @@ -1167,7 +1234,9 @@ fn merge_config_profiles( }; // Set of profile names to check if defined in config only. let mut check_to_add = HashSet::new(); - check_to_add.insert(requested_profile); + if let Some(requested_profile) = requested_profile { + check_to_add.insert(requested_profile); + } // Merge config onto manifest profiles. for (name, profile) in &mut profiles { if let Some(config_profile) = get_config_profile(ws, name)? { diff --git a/src/cargo/ops/cargo_output_metadata.rs b/src/cargo/ops/cargo_output_metadata.rs index 83dae50ea8d..ac5627ccafc 100644 --- a/src/cargo/ops/cargo_output_metadata.rs +++ b/src/cargo/ops/cargo_output_metadata.rs @@ -2,6 +2,7 @@ use crate::core::compiler::artifact::match_artifacts_kind_with_targets; use crate::core::compiler::{CompileKind, RustcTargetData}; use crate::core::dependency::DepKind; use crate::core::package::SerializedPackage; +use crate::core::profiles::{Profile, Profiles}; use crate::core::resolver::{features::CliFeatures, HasDevUnits, Resolve}; use crate::core::{Package, PackageId, Workspace}; use crate::ops::{self, Packages}; @@ -9,7 +10,7 @@ use crate::util::interning::InternedString; use crate::util::CargoResult; use cargo_platform::Platform; use serde::Serialize; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use std::path::PathBuf; const VERSION: u32 = 1; @@ -49,6 +50,7 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo version: VERSION, workspace_root: ws.root().to_path_buf(), metadata: ws.custom_metadata().cloned(), + profiles: Profiles::all(ws)?, }) } @@ -65,6 +67,7 @@ pub struct ExportInfo { version: u32, workspace_root: PathBuf, metadata: Option, + profiles: HashMap, } #[derive(Serialize)] diff --git a/tests/testsuite/alt_registry.rs b/tests/testsuite/alt_registry.rs index d6d7dd531cc..0e4d6767743 100644 --- a/tests/testsuite/alt_registry.rs +++ b/tests/testsuite/alt_registry.rs @@ -6,6 +6,8 @@ use cargo_test_support::registry::{self, Package, RegistryBuilder}; use cargo_test_support::{basic_manifest, paths, project}; use std::fs; +use crate::metadata::DEFAULT_PROFILES; + #[cargo_test] fn depend_on_alt_registry() { registry::alt_init(); @@ -844,7 +846,7 @@ fn alt_reg_metadata() { // iodep -> altdep2: alternative-registry p.cargo("metadata --format-version=1 --no-deps") .with_json( - r#" + &r#" { "packages": [ { @@ -909,15 +911,17 @@ fn alt_reg_metadata() { "target_directory": "[..]/foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); // --no-deps uses a different code path, make sure both work. p.cargo("metadata --format-version=1") .with_json( - r#" + &r#" { "packages": [ { @@ -1112,8 +1116,10 @@ fn alt_reg_metadata() { "target_directory": "[..]/foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -1160,7 +1166,7 @@ fn unknown_registry() { // bar -> baz registry = alternate p.cargo("metadata --format-version=1") .with_json( - r#" + &r#" { "packages": [ { @@ -1278,9 +1284,11 @@ fn unknown_registry() { "target_directory": "[..]/foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } diff --git a/tests/testsuite/features_namespaced.rs b/tests/testsuite/features_namespaced.rs index f24186c1591..299bada3800 100644 --- a/tests/testsuite/features_namespaced.rs +++ b/tests/testsuite/features_namespaced.rs @@ -1,5 +1,7 @@ //! Tests for namespaced features. +use crate::metadata::DEFAULT_PROFILES; + use super::features2::switch_to_resolver_2; use cargo_test_support::registry::{Dependency, Package, RegistryBuilder}; use cargo_test_support::{project, publish}; @@ -576,7 +578,7 @@ fn json_exposed() { p.cargo("metadata --no-deps") .with_json( - r#" + &r#" { "packages": [ { @@ -614,9 +616,11 @@ fn json_exposed() { "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } diff --git a/tests/testsuite/git.rs b/tests/testsuite/git.rs index e27315346c2..91591dc2e22 100644 --- a/tests/testsuite/git.rs +++ b/tests/testsuite/git.rs @@ -15,6 +15,8 @@ use cargo_test_support::registry::Package; use cargo_test_support::{basic_lib_manifest, basic_manifest, git, main_file, path2url, project}; use cargo_test_support::{sleep_ms, t, Project}; +use crate::metadata::DEFAULT_PROFILES; + #[cargo_test] fn cargo_compile_simple_git_dep() { let project = project(); @@ -3370,11 +3372,13 @@ fn metadata_master_consistency() { "target_directory": "[..]", "version": 1, "workspace_root": "[..]", - "metadata": null + "metadata": null, + "profiles": $PROFILES } "# .replace("__BAR_SOURCE__", bar_source) .replace("__BAR_HASH__", &bar_hash) + .replace("$PROFILES", DEFAULT_PROFILES) }; let bar_source = format!("git+{}?branch=master", git_project.url()); diff --git a/tests/testsuite/metadata.rs b/tests/testsuite/metadata.rs index fbead4dea97..d72b13c6328 100644 --- a/tests/testsuite/metadata.rs +++ b/tests/testsuite/metadata.rs @@ -6,6 +6,84 @@ use cargo_test_support::registry::Package; use cargo_test_support::{basic_bin_manifest, basic_lib_manifest, main_file, project, rustc_host}; use serde_json::json; +pub(crate) const DEFAULT_PROFILES: &str = r#"{ + "bench": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": false, + "debuginfo": 0, + "incremental": false, + "lto": "false", + "name": "bench", + "opt_level": "3", + "overflow_checks": false, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "dev": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "dev", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "doc": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "doc", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "release": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": false, + "debuginfo": 0, + "incremental": false, + "lto": "false", + "name": "release", + "opt_level": "3", + "overflow_checks": false, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "test": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "test", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + } +}"#; + #[cargo_test] fn cargo_metadata_simple() { let p = project() @@ -15,7 +93,7 @@ fn cargo_metadata_simple() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -80,8 +158,10 @@ fn cargo_metadata_simple() { "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -117,7 +197,7 @@ crate-type = ["lib", "staticlib"] p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -180,8 +260,10 @@ crate-type = ["lib", "staticlib"] "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -207,7 +289,7 @@ optional_feat = [] p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -277,8 +359,10 @@ optional_feat = [] "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -313,7 +397,7 @@ fn cargo_metadata_with_deps_and_version() { p.cargo("metadata -q --format-version 1") .with_json( - r#" + &r#" { "packages": [ { @@ -594,8 +678,10 @@ fn cargo_metadata_with_deps_and_version() { "foo 0.5.0 (path+file:[..]foo)" ], "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -620,7 +706,7 @@ name = "ex" p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -691,8 +777,10 @@ name = "ex" "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -718,7 +806,7 @@ crate-type = ["rlib", "dylib"] p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -789,8 +877,10 @@ crate-type = ["rlib", "dylib"] "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -821,7 +911,7 @@ fn workspace_metadata() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -931,8 +1021,10 @@ fn workspace_metadata() { "foo": { "bar": 3 } - } - }"#, + }, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -972,7 +1064,7 @@ fn workspace_metadata_with_dependencies_no_deps() { p.cargo("metadata --no-deps -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_json( - r#" + &r#" { "packages": [ { @@ -1145,8 +1237,10 @@ fn workspace_metadata_with_dependencies_no_deps() { "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -1240,7 +1334,7 @@ fn workspace_metadata_with_dependencies_and_resolve() { p.cargo("metadata -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_json( - r#" + &r#" { "metadata": null, "packages": [ @@ -1779,9 +1873,11 @@ fn workspace_metadata_with_dependencies_and_resolve() { "bin-only-artifact 0.5.0 (path+file://[..]/foo/bin-only-artifact)", "non-artifact 0.5.0 (path+file://[..]/foo/non-artifact)" ], - "workspace_root": "[..]/foo" + "workspace_root": "[..]/foo", + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -1991,7 +2087,8 @@ const MANIFEST_OUTPUT: &str = r#" "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES }"#; #[cargo_test] @@ -2003,7 +2100,7 @@ fn cargo_metadata_no_deps_path_to_cargo_toml_relative() { p.cargo("metadata --no-deps --manifest-path foo/Cargo.toml") .cwd(p.root().parent().unwrap()) - .with_json(MANIFEST_OUTPUT) + .with_json(&MANIFEST_OUTPUT.replace("$PROFILES", DEFAULT_PROFILES)) .run(); } @@ -2017,7 +2114,7 @@ fn cargo_metadata_no_deps_path_to_cargo_toml_absolute() { p.cargo("metadata --no-deps --manifest-path") .arg(p.root().join("Cargo.toml")) .cwd(p.root().parent().unwrap()) - .with_json(MANIFEST_OUTPUT) + .with_json(&MANIFEST_OUTPUT.replace("$PROFILES", DEFAULT_PROFILES)) .run(); } @@ -2064,7 +2161,7 @@ fn cargo_metadata_no_deps_cwd() { .build(); p.cargo("metadata --no-deps") - .with_json(MANIFEST_OUTPUT) + .with_json(&MANIFEST_OUTPUT.replace("$PROFILES", DEFAULT_PROFILES)) .run(); } @@ -2135,7 +2232,7 @@ fn package_metadata() { p.cargo("metadata --no-deps") .with_json( - r#" + &r#" { "packages": [ { @@ -2186,8 +2283,10 @@ fn package_metadata() { "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -2215,7 +2314,7 @@ fn package_publish() { p.cargo("metadata --no-deps") .with_json( - r#" + &r#" { "packages": [ { @@ -2262,8 +2361,10 @@ fn package_publish() { "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null - }"#, + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -2290,7 +2391,7 @@ fn cargo_metadata_path_to_cargo_toml_project() { p.cargo("metadata --manifest-path") .arg(p.root().join("target/package/bar-0.5.0/Cargo.toml")) .with_json( - r#" + &r#" { "packages": [ { @@ -2357,9 +2458,11 @@ fn cargo_metadata_path_to_cargo_toml_project() { "bar 0.5.0 (path+file:[..])" ], "workspace_root": "[..]", - "metadata": null + "metadata": null, + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -2381,7 +2484,7 @@ fn package_edition_2018() { .build(); p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -2448,9 +2551,11 @@ fn package_edition_2018() { "foo 0.1.0 (path+file:[..])" ], "workspace_root": "[..]", - "metadata": null + "metadata": null, + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -2518,7 +2623,7 @@ fn target_edition_2018() { .build(); p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -2599,9 +2704,11 @@ fn target_edition_2018() { "foo 0.1.0 (path+file:[..])" ], "workspace_root": "[..]", - "metadata": null + "metadata": null, + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -2630,7 +2737,7 @@ fn rename_dependency() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -2838,8 +2945,10 @@ fn rename_dependency() { "foo 0.0.1[..]" ], "workspace_root": "[..]", - "metadata": null -}"#, + "metadata": null, + "profiles": $PROFILES +}"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -2862,7 +2971,7 @@ fn metadata_links() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -2941,9 +3050,11 @@ fn metadata_links() { "foo 0.5.0 [..]" ], "workspace_root": "[..]/foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run() } @@ -2968,7 +3079,7 @@ fn deps_with_bin_only() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": [ { @@ -3047,9 +3158,11 @@ fn deps_with_bin_only() { "target_directory": "[..]/foo/target", "version": 1, "workspace_root": "[..]foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -3499,7 +3612,8 @@ fn filter_platform() { "target_directory": "[..]/foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } "# .replace("$ALT_TRIPLE", alt_target) @@ -3508,7 +3622,8 @@ fn filter_platform() { .replace("$CFG_DEP", cfg_dep) .replace("$HOST_DEP", host_dep) .replace("$NORMAL_DEP", normal_dep) - .replace("$FOO", &foo), + .replace("$FOO", &foo) + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); clear(); @@ -3585,13 +3700,15 @@ fn filter_platform() { "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } "# .replace("$ALT_TRIPLE", alt_target) .replace("$ALT_DEP", alt_dep) .replace("$NORMAL_DEP", normal_dep) - .replace("$FOO", &foo), + .replace("$FOO", &foo) + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); clear(); @@ -3667,13 +3784,15 @@ fn filter_platform() { "target_directory": "[..]foo/target", "version": 1, "workspace_root": "[..]foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } "# .replace("$HOST_TRIPLE", host_target) .replace("$HOST_DEP", host_dep) .replace("$NORMAL_DEP", normal_dep) - .replace("$FOO", &foo), + .replace("$FOO", &foo) + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); clear(); @@ -3769,14 +3888,16 @@ fn filter_platform() { "target_directory": "[..]/foo/target", "version": 1, "workspace_root": "[..]/foo", - "metadata": null + "metadata": null, + "profiles": $PROFILES } "# .replace("$HOST_TRIPLE", host_target) .replace("$CFG_DEP", cfg_dep) .replace("$HOST_DEP", host_dep) .replace("$NORMAL_DEP", normal_dep) - .replace("$FOO", &foo), + .replace("$FOO", &foo) + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -3812,7 +3933,7 @@ fn dep_kinds() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": "{...}", "workspace_members": "{...}", @@ -3821,6 +3942,7 @@ fn dep_kinds() { "version": 1, "workspace_root": "{...}", "metadata": null, + "profiles": $PROFILES, "resolve": { "nodes": [ { @@ -3877,7 +3999,8 @@ fn dep_kinds() { "root": "foo 0.1.0 [..]" } } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -3928,7 +4051,7 @@ fn dep_kinds_workspace() { p.cargo("metadata") .with_json( - r#" + &r#" { "packages": "{...}", "workspace_members": "{...}", @@ -3937,6 +4060,7 @@ fn dep_kinds_workspace() { "version": 1, "workspace_root": "[..]/foo", "metadata": null, + "profiles": $PROFILES, "resolve": { "nodes": [ { @@ -3989,7 +4113,8 @@ fn dep_kinds_workspace() { "root": "foo 0.1.0 (path+file://[..]/foo)" } } - "#, + "# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run(); } @@ -4057,9 +4182,10 @@ fn workspace_metadata_with_dependencies_no_deps_artifact() { p.cargo("metadata --no-deps -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_json( - r#" + &r#" { "metadata": null, + "profiles": $PROFILES, "packages": [ { "authors": [ @@ -4253,7 +4379,329 @@ fn workspace_metadata_with_dependencies_no_deps_artifact() { ], "workspace_root": "[..]/foo" } -"#, +"# + .replace("$PROFILES", DEFAULT_PROFILES), + ) + .run(); +} + +const CUSTOM_PROFILES: &str = r#"{ + "bench": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": false, + "debuginfo": 0, + "incremental": false, + "lto": "false", + "name": "bench", + "opt_level": "3", + "overflow_checks": false, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "symbols" + }, + "custom-lto": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": false, + "debuginfo": 0, + "incremental": false, + "lto": "thin", + "name": "custom-lto", + "opt_level": "3", + "overflow_checks": false, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "symbols" + }, + "dev": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "dev", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "doc": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "doc", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "release": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": false, + "debuginfo": 0, + "incremental": false, + "lto": "false", + "name": "release", + "opt_level": "3", + "overflow_checks": false, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "symbols" + }, + "test": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "test", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + } +}"#; + +#[cargo_test] +fn library_metadata_with_profiles() { + let p = project() + .file("src/lib.rs", "") + .file( + "Cargo.toml", + r#" +[package] +name = "foo" +version = "0.5.0" + +[profile.release] +strip = "symbols" + +[profile.custom-lto] +inherits = "release" +lto = "thin" + "#, + ) + .build(); + + p.cargo("metadata") + .with_json( + &r#" + { + "packages": [ + { + "authors": [], + "categories": [], + "default_run": null, + "name": "foo", + "readme": null, + "repository": null, + "homepage": null, + "documentation": null, + "version": "0.5.0", + "rust_version": null, + "id": "foo[..]", + "keywords": [], + "source": null, + "dependencies": [], + "edition": "2015", + "license": null, + "license_file": null, + "links": null, + "description": null, + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "doc": true, + "doctest": true, + "test": true, + "edition": "2015", + "name": "foo", + "src_path": "[..]/foo/src/lib.rs" + } + ], + "features": {}, + "manifest_path": "[..]Cargo.toml", + "metadata": null, + "publish": null + } + ], + "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"], + "workspace_default_members": ["foo 0.5.0 (path+file:[..]foo)"], + "resolve": { + "nodes": [ + { + "dependencies": [], + "deps": [], + "features": [], + "id": "foo 0.5.0 (path+file:[..]foo)" + } + ], + "root": "foo 0.5.0 (path+file:[..]foo)" + }, + "target_directory": "[..]foo/target", + "version": 1, + "workspace_root": "[..]/foo", + "metadata": null, + "profiles": $PROFILES + }"# + .replace("$PROFILES", CUSTOM_PROFILES), + ) + .run(); +} + +#[cargo_test] +fn workspace_metadata_with_profiles() { + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["bar", "baz"] + + [profile.release] + strip = "symbols" + + [profile.custom-lto] + inherits = "release" + lto = "thin" + "#, + ) + .file("bar/Cargo.toml", &basic_lib_manifest("bar")) + .file("bar/src/lib.rs", "") + .file("baz/Cargo.toml", &basic_lib_manifest("baz")) + .file("baz/src/lib.rs", "") + .build(); + + p.cargo("metadata") + .with_json( + &r#" + { + "packages": [ + { + "authors": [ + "wycats@example.com" + ], + "categories": [], + "default_run": null, + "name": "bar", + "version": "0.5.0", + "id": "bar[..]", + "readme": null, + "repository": null, + "rust_version": null, + "homepage": null, + "documentation": null, + "keywords": [], + "source": null, + "dependencies": [], + "license": null, + "license_file": null, + "links": null, + "description": null, + "edition": "2015", + "targets": [ + { + "kind": [ "lib" ], + "crate_types": [ "lib" ], + "doc": true, + "doctest": true, + "test": true, + "edition": "2015", + "name": "bar", + "src_path": "[..]bar/src/lib.rs" + } + ], + "features": {}, + "manifest_path": "[..]bar/Cargo.toml", + "metadata": null, + "publish": null + }, + { + "authors": [ + "wycats@example.com" + ], + "categories": [], + "default_run": null, + "name": "baz", + "readme": null, + "repository": null, + "rust_version": null, + "homepage": null, + "documentation": null, + "version": "0.5.0", + "id": "baz[..]", + "keywords": [], + "source": null, + "dependencies": [], + "license": null, + "license_file": null, + "links": null, + "description": null, + "edition": "2015", + "targets": [ + { + "kind": [ "lib" ], + "crate_types": [ "lib" ], + "doc": true, + "doctest": true, + "test": true, + "edition": "2015", + "name": "baz", + "src_path": "[..]baz/src/lib.rs" + } + ], + "features": {}, + "manifest_path": "[..]baz/Cargo.toml", + "metadata": null, + "publish": null + } + ], + "workspace_members": ["bar 0.5.0 (path+file:[..]bar)", "baz 0.5.0 (path+file:[..]baz)"], + "workspace_default_members": ["bar 0.5.0 (path+file:[..]bar)", "baz 0.5.0 (path+file:[..]baz)"], + "resolve": { + "nodes": [ + { + "dependencies": [], + "deps": [], + "features": [], + "id": "bar 0.5.0 (path+file:[..]bar)" + }, + { + "dependencies": [], + "deps": [], + "features": [], + "id": "baz 0.5.0 (path+file:[..]baz)" + } + ], + "root": null + }, + "target_directory": "[..]foo/target", + "version": 1, + "workspace_root": "[..]/foo", + "metadata": null, + "profiles": $PROFILES + }"#.replace("$PROFILES", CUSTOM_PROFILES) ) .run(); } diff --git a/tests/testsuite/script.rs b/tests/testsuite/script.rs index c869b43f7d6..12ccc9a0d89 100644 --- a/tests/testsuite/script.rs +++ b/tests/testsuite/script.rs @@ -1081,7 +1081,84 @@ fn cmd_metadata_with_embedded() { "target_directory": "[ROOT]/home/.cargo/target/[..]", "version": 1, "workspace_root": "[..]/foo", - "metadata": null + "metadata": null, + "profiles": { + "bench": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": false, + "debuginfo": 0, + "incremental": false, + "lto": "false", + "name": "bench", + "opt_level": "3", + "overflow_checks": false, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "symbols" + }, + "dev": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "dev", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "doc": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "doc", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + }, + "release": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": false, + "debuginfo": 0, + "incremental": false, + "lto": "false", + "name": "release", + "opt_level": "3", + "overflow_checks": false, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "symbols" + }, + "test": { + "codegen_backend": null, + "codegen_units": null, + "debug_assertions": true, + "debuginfo": 2, + "incremental": true, + "lto": "false", + "name": "test", + "opt_level": "0", + "overflow_checks": true, + "panic": "unwind", + "rpath": false, + "split_debuginfo": "{...}", + "strip": "none" + } + } }"#, ) .with_stderr( diff --git a/tests/testsuite/update.rs b/tests/testsuite/update.rs index fe1d86bd763..512b0c65946 100644 --- a/tests/testsuite/update.rs +++ b/tests/testsuite/update.rs @@ -3,6 +3,8 @@ use cargo_test_support::registry::Package; use cargo_test_support::{basic_lib_manifest, basic_manifest, git, project}; +use crate::metadata::DEFAULT_PROFILES; + #[cargo_test] fn minor_update_two_places() { Package::new("log", "0.1.0").publish(); @@ -577,7 +579,7 @@ fn update_precise_first_run() { // Assert `cargo metadata` shows serde 0.2.0 p.cargo("metadata") .with_json( - r#"{ + &r#"{ "packages": [ { "authors": [], @@ -714,8 +716,10 @@ fn update_precise_first_run() { "bar 0.0.1 (path+file://[..]/foo)" ], "workspace_root": "[..]/foo", - "metadata": null -}"#, + "metadata": null, + "profiles": $PROFILES +}"# + .replace("$PROFILES", DEFAULT_PROFILES), ) .run();