Add named config profiles.

This commit is contained in:
Eric Huss 2019-12-26 19:59:19 -08:00
parent 56a5503268
commit 77ee608de3
27 changed files with 771 additions and 646 deletions

View File

@ -1,5 +1,4 @@
use crate::command_prelude::*; use crate::command_prelude::*;
use cargo::ops::{self, TestOptions}; use cargo::ops::{self, TestOptions};
pub fn cli() -> App { pub fn cli() -> App {
@ -80,11 +79,8 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
ProfileChecking::Checked, ProfileChecking::Checked,
)?; )?;
compile_opts.build_config.profile_kind = args.get_profile_kind( compile_opts.build_config.requested_profile =
config, args.get_profile_name(config, "bench", ProfileChecking::Checked)?;
ProfileKind::Custom("bench".to_owned()),
ProfileChecking::Checked,
)?;
let ops = TestOptions { let ops = TestOptions {
no_run: args.is_present("no-run"), no_run: args.is_present("no-run"),

View File

@ -29,7 +29,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
config, config,
spec: values(args, "package"), spec: values(args, "package"),
target: args.target(), target: args.target(),
profile_kind: args.get_profile_kind(config, ProfileKind::Dev, ProfileChecking::Checked)?, requested_profile: args.get_profile_name(config, "dev", ProfileChecking::Checked)?,
profile_specified: args.is_present("profile") || args.is_present("release"), profile_specified: args.is_present("profile") || args.is_present("release"),
doc: args.is_present("doc"), doc: args.is_present("doc"),
}; };

View File

@ -116,8 +116,8 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
ProfileChecking::Checked, ProfileChecking::Checked,
)?; )?;
compile_opts.build_config.profile_kind = compile_opts.build_config.requested_profile =
args.get_profile_kind(config, ProfileKind::Release, ProfileChecking::Checked)?; args.get_profile_name(config, "release", ProfileChecking::Checked)?;
let krates = args let krates = args
.values_of("crate") .values_of("crate")

View File

@ -108,11 +108,8 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
ProfileChecking::Checked, ProfileChecking::Checked,
)?; )?;
compile_opts.build_config.profile_kind = args.get_profile_kind( compile_opts.build_config.requested_profile =
config, args.get_profile_name(config, "test", ProfileChecking::Checked)?;
ProfileKind::Custom("test".to_owned()),
ProfileChecking::Checked,
)?;
// `TESTNAME` is actually an argument of the test binary, but it's // `TESTNAME` is actually an argument of the test binary, but it's
// important, so we explicitly mention it and reconfigure. // important, so we explicitly mention it and reconfigure.

View File

@ -1,27 +1,9 @@
use std::cell::RefCell;
use serde::ser;
use crate::core::compiler::{CompileKind, CompileTarget}; use crate::core::compiler::{CompileKind, CompileTarget};
use crate::core::interning::InternedString;
use crate::util::ProcessBuilder; use crate::util::ProcessBuilder;
use crate::util::{CargoResult, Config, RustfixDiagnosticServer}; use crate::util::{CargoResult, Config, RustfixDiagnosticServer};
use serde::ser;
#[derive(Debug, Clone)] use std::cell::RefCell;
pub enum ProfileKind {
Dev,
Release,
Custom(String),
}
impl ProfileKind {
pub fn name(&self) -> &str {
match self {
ProfileKind::Dev => "dev",
ProfileKind::Release => "release",
ProfileKind::Custom(name) => name,
}
}
}
/// Configuration information for a rustc build. /// Configuration information for a rustc build.
#[derive(Debug)] #[derive(Debug)]
@ -31,7 +13,7 @@ pub struct BuildConfig {
/// Number of rustc jobs to run in parallel. /// Number of rustc jobs to run in parallel.
pub jobs: u32, pub jobs: u32,
/// Build profile /// Build profile
pub profile_kind: ProfileKind, pub requested_profile: InternedString,
/// The mode we are compiling in. /// The mode we are compiling in.
pub mode: CompileMode, pub mode: CompileMode,
/// `true` to print stdout in JSON format (for machine reading). /// `true` to print stdout in JSON format (for machine reading).
@ -92,7 +74,7 @@ impl BuildConfig {
Ok(BuildConfig { Ok(BuildConfig {
requested_kind, requested_kind,
jobs, jobs,
profile_kind: ProfileKind::Dev, requested_profile: InternedString::new("dev"),
mode, mode,
message_format: MessageFormat::Human, message_format: MessageFormat::Human,
force_rebuild: false, force_rebuild: false,
@ -111,10 +93,6 @@ impl BuildConfig {
} }
} }
pub fn profile_name(&self) -> &str {
self.profile_kind.name()
}
pub fn test(&self) -> bool { pub fn test(&self) -> bool {
self.mode == CompileMode::Test || self.mode == CompileMode::Bench self.mode == CompileMode::Test || self.mode == CompileMode::Bench
} }

View File

@ -26,7 +26,7 @@ pub struct BuildContext<'a, 'cfg> {
pub ws: &'a Workspace<'cfg>, pub ws: &'a Workspace<'cfg>,
/// The cargo configuration. /// The cargo configuration.
pub config: &'cfg Config, pub config: &'cfg Config,
pub profiles: &'a Profiles, pub profiles: Profiles,
pub build_config: &'a BuildConfig, pub build_config: &'a BuildConfig,
/// Extra compiler args for either `rustc` or `rustdoc`. /// Extra compiler args for either `rustc` or `rustdoc`.
pub extra_compiler_args: HashMap<Unit<'a>, Vec<String>>, pub extra_compiler_args: HashMap<Unit<'a>, Vec<String>>,
@ -58,7 +58,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
packages: &'a PackageSet<'cfg>, packages: &'a PackageSet<'cfg>,
config: &'cfg Config, config: &'cfg Config,
build_config: &'a BuildConfig, build_config: &'a BuildConfig,
profiles: &'a Profiles, profiles: Profiles,
units: &'a UnitInterner<'a>, units: &'a UnitInterner<'a>,
extra_compiler_args: HashMap<Unit<'a>, Vec<String>>, extra_compiler_args: HashMap<Unit<'a>, Vec<String>>,
) -> CargoResult<BuildContext<'a, 'cfg>> { ) -> CargoResult<BuildContext<'a, 'cfg>> {

View File

@ -281,8 +281,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
export_dir: Option<PathBuf>, export_dir: Option<PathBuf>,
units: &[Unit<'a>], units: &[Unit<'a>],
) -> CargoResult<()> { ) -> CargoResult<()> {
let profile_kind = &self.bcx.build_config.profile_kind; let dest = self.bcx.profiles.get_dir_name();
let dest = self.bcx.profiles.get_dir_name(profile_kind);
let host_layout = Layout::new(self.bcx.ws, None, &dest)?; let host_layout = Layout::new(self.bcx.ws, None, &dest)?;
let mut targets = HashMap::new(); let mut targets = HashMap::new();
if let CompileKind::Target(target) = self.bcx.build_config.requested_kind { if let CompileKind::Target(target) = self.bcx.build_config.requested_kind {

View File

@ -19,7 +19,6 @@ use super::job::{
}; };
use super::timings::Timings; use super::timings::Timings;
use super::{BuildContext, BuildPlan, CompileMode, Context, Unit}; use super::{BuildContext, BuildPlan, CompileMode, Context, Unit};
use crate::core::compiler::ProfileKind;
use crate::core::{PackageId, TargetKind}; use crate::core::{PackageId, TargetKind};
use crate::handle_error; use crate::handle_error;
use crate::util; use crate::util;
@ -44,7 +43,6 @@ pub struct JobQueue<'a, 'cfg> {
progress: Progress<'cfg>, progress: Progress<'cfg>,
next_id: u32, next_id: u32,
timings: Timings<'a, 'cfg>, timings: Timings<'a, 'cfg>,
profile_kind: ProfileKind,
} }
pub struct JobState<'a> { pub struct JobState<'a> {
@ -148,7 +146,6 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
progress, progress,
next_id: 0, next_id: 0,
timings, timings,
profile_kind: bcx.build_config.profile_kind.clone(),
} }
} }
@ -415,7 +412,7 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
} }
self.progress.clear(); self.progress.clear();
let build_type = self.profile_kind.name(); let profile_name = cx.bcx.build_config.requested_profile;
// NOTE: this may be a bit inaccurate, since this may not display the // NOTE: this may be a bit inaccurate, since this may not display the
// profile for what was actually built. Profile overrides can change // profile for what was actually built. Profile overrides can change
// these settings, and in some cases different targets are built with // these settings, and in some cases different targets are built with
@ -423,7 +420,7 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
// list of Units built, and maybe display a list of the different // list of Units built, and maybe display a list of the different
// profiles used. However, to keep it simple and compatible with old // profiles used. However, to keep it simple and compatible with old
// behavior, we just display what the base profile is. // behavior, we just display what the base profile is.
let profile = cx.bcx.profiles.base_profile(&self.profile_kind)?; let profile = cx.bcx.profiles.base_profile();
let mut opt_type = String::from(if profile.opt_level.as_str() == "0" { let mut opt_type = String::from(if profile.opt_level.as_str() == "0" {
"unoptimized" "unoptimized"
} else { } else {
@ -440,7 +437,7 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
} else if self.queue.is_empty() && queue.is_empty() { } else if self.queue.is_empty() && queue.is_empty() {
let message = format!( let message = format!(
"{} [{}] target(s) in {}", "{} [{}] target(s) in {}",
build_type, opt_type, time_elapsed profile_name, opt_type, time_elapsed
); );
if !cx.bcx.build_config.build_plan { if !cx.bcx.build_config.build_plan {
cx.bcx.config.shell().status("Finished", message)?; cx.bcx.config.shell().status("Finished", message)?;

View File

@ -27,7 +27,7 @@ use anyhow::Error;
use lazycell::LazyCell; use lazycell::LazyCell;
use log::debug; use log::debug;
pub use self::build_config::{BuildConfig, CompileMode, MessageFormat, ProfileKind}; pub use self::build_config::{BuildConfig, CompileMode, MessageFormat};
pub use self::build_context::{BuildContext, FileFlavor, TargetInfo}; pub use self::build_context::{BuildContext, FileFlavor, TargetInfo};
use self::build_plan::BuildPlan; use self::build_plan::BuildPlan;
pub use self::compilation::{Compilation, Doctest}; pub use self::compilation::{Compilation, Doctest};

View File

@ -66,8 +66,7 @@ pub fn resolve_std<'cfg>(
/*replace*/ Vec::new(), /*replace*/ Vec::new(),
patch, patch,
ws_config, ws_config,
// Profiles are not used here, but we need something to pass in. /*profiles*/ None,
ws.profiles().clone(),
crate::core::Features::default(), crate::core::Features::default(),
); );
@ -139,7 +138,6 @@ pub fn generate_std_roots<'a>(
/*is_member*/ false, /*is_member*/ false,
unit_for, unit_for,
mode, mode,
bcx.build_config.profile_kind.clone(),
); );
let features = std_resolve.features_sorted(pkg.package_id()); let features = std_resolve.features_sorted(pkg.package_id());
Ok(bcx.units.intern( Ok(bcx.units.intern(

View File

@ -116,7 +116,7 @@ impl<'a, 'cfg> Timings<'a, 'cfg> {
}) })
.collect(); .collect();
let start_str = humantime::format_rfc3339_seconds(SystemTime::now()).to_string(); let start_str = humantime::format_rfc3339_seconds(SystemTime::now()).to_string();
let profile = bcx.build_config.profile_kind.name().to_owned(); let profile = bcx.build_config.requested_profile.to_string();
Timings { Timings {
config: bcx.config, config: bcx.config,

View File

@ -546,7 +546,6 @@ fn new_unit_dep<'a>(
state.bcx.ws.is_member(pkg), state.bcx.ws.is_member(pkg),
unit_for, unit_for,
mode, mode,
state.bcx.build_config.profile_kind.clone(),
); );
new_unit_dep_with_profile(state, parent, pkg, target, unit_for, kind, mode, profile) new_unit_dep_with_profile(state, parent, pkg, target, unit_for, kind, mode, profile)
} }

View File

@ -48,6 +48,18 @@ impl PartialEq for InternedString {
} }
} }
impl PartialEq<str> for InternedString {
fn eq(&self, other: &str) -> bool {
*self == other
}
}
impl<'a> PartialEq<&'a str> for InternedString {
fn eq(&self, other: &&str) -> bool {
**self == **other
}
}
impl Eq for InternedString {} impl Eq for InternedString {}
impl InternedString { impl InternedString {

View File

@ -10,11 +10,10 @@ use serde::Serialize;
use url::Url; use url::Url;
use crate::core::interning::InternedString; use crate::core::interning::InternedString;
use crate::core::profiles::Profiles;
use crate::core::{Dependency, PackageId, PackageIdSpec, SourceId, Summary}; use crate::core::{Dependency, PackageId, PackageIdSpec, SourceId, Summary};
use crate::core::{Edition, Feature, Features, WorkspaceConfig}; use crate::core::{Edition, Feature, Features, WorkspaceConfig};
use crate::util::errors::*; use crate::util::errors::*;
use crate::util::toml::TomlManifest; use crate::util::toml::{TomlManifest, TomlProfiles};
use crate::util::{short_hash, Config, Filesystem}; use crate::util::{short_hash, Config, Filesystem};
pub enum EitherManifest { pub enum EitherManifest {
@ -33,7 +32,7 @@ pub struct Manifest {
include: Vec<String>, include: Vec<String>,
metadata: ManifestMetadata, metadata: ManifestMetadata,
custom_metadata: Option<toml::Value>, custom_metadata: Option<toml::Value>,
profiles: Profiles, profiles: Option<TomlProfiles>,
publish: Option<Vec<String>>, publish: Option<Vec<String>>,
publish_lockfile: bool, publish_lockfile: bool,
replace: Vec<(PackageIdSpec, Dependency)>, replace: Vec<(PackageIdSpec, Dependency)>,
@ -64,7 +63,7 @@ pub struct VirtualManifest {
replace: Vec<(PackageIdSpec, Dependency)>, replace: Vec<(PackageIdSpec, Dependency)>,
patch: HashMap<Url, Vec<Dependency>>, patch: HashMap<Url, Vec<Dependency>>,
workspace: WorkspaceConfig, workspace: WorkspaceConfig,
profiles: Profiles, profiles: Option<TomlProfiles>,
warnings: Warnings, warnings: Warnings,
features: Features, features: Features,
} }
@ -399,7 +398,7 @@ impl Manifest {
links: Option<String>, links: Option<String>,
metadata: ManifestMetadata, metadata: ManifestMetadata,
custom_metadata: Option<toml::Value>, custom_metadata: Option<toml::Value>,
profiles: Profiles, profiles: Option<TomlProfiles>,
publish: Option<Vec<String>>, publish: Option<Vec<String>>,
publish_lockfile: bool, publish_lockfile: bool,
replace: Vec<(PackageIdSpec, Dependency)>, replace: Vec<(PackageIdSpec, Dependency)>,
@ -475,8 +474,8 @@ impl Manifest {
pub fn warnings(&self) -> &Warnings { pub fn warnings(&self) -> &Warnings {
&self.warnings &self.warnings
} }
pub fn profiles(&self) -> &Profiles { pub fn profiles(&self) -> Option<&TomlProfiles> {
&self.profiles self.profiles.as_ref()
} }
pub fn publish(&self) -> &Option<Vec<String>> { pub fn publish(&self) -> &Option<Vec<String>> {
&self.publish &self.publish
@ -563,7 +562,7 @@ impl VirtualManifest {
replace: Vec<(PackageIdSpec, Dependency)>, replace: Vec<(PackageIdSpec, Dependency)>,
patch: HashMap<Url, Vec<Dependency>>, patch: HashMap<Url, Vec<Dependency>>,
workspace: WorkspaceConfig, workspace: WorkspaceConfig,
profiles: Profiles, profiles: Option<TomlProfiles>,
features: Features, features: Features,
) -> VirtualManifest { ) -> VirtualManifest {
VirtualManifest { VirtualManifest {
@ -588,8 +587,8 @@ impl VirtualManifest {
&self.workspace &self.workspace
} }
pub fn profiles(&self) -> &Profiles { pub fn profiles(&self) -> Option<&TomlProfiles> {
&self.profiles self.profiles.as_ref()
} }
pub fn warnings_mut(&mut self) -> &mut Warnings { pub fn warnings_mut(&mut self) -> &mut Warnings {

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,6 @@ use log::debug;
use url::Url; use url::Url;
use crate::core::features::Features; use crate::core::features::Features;
use crate::core::profiles::Profiles;
use crate::core::registry::PackageRegistry; use crate::core::registry::PackageRegistry;
use crate::core::{Dependency, PackageId, PackageIdSpec}; use crate::core::{Dependency, PackageId, PackageIdSpec};
use crate::core::{EitherManifest, Package, SourceId, VirtualManifest}; use crate::core::{EitherManifest, Package, SourceId, VirtualManifest};
@ -17,7 +16,7 @@ use crate::ops;
use crate::sources::PathSource; use crate::sources::PathSource;
use crate::util::errors::{CargoResult, CargoResultExt, ManifestError}; use crate::util::errors::{CargoResult, CargoResultExt, ManifestError};
use crate::util::paths; use crate::util::paths;
use crate::util::toml::read_manifest; use crate::util::toml::{read_manifest, TomlProfiles};
use crate::util::{Config, Filesystem}; use crate::util::{Config, Filesystem};
/// The core abstraction in Cargo for working with a workspace of crates. /// The core abstraction in Cargo for working with a workspace of crates.
@ -273,7 +272,7 @@ impl<'cfg> Workspace<'cfg> {
self.config self.config
} }
pub fn profiles(&self) -> &Profiles { pub fn profiles(&self) -> Option<&TomlProfiles> {
match self.root_maybe() { match self.root_maybe() {
MaybePackage::Package(p) => p.manifest().profiles(), MaybePackage::Package(p) => p.manifest().profiles(),
MaybePackage::Virtual(vm) => vm.profiles(), MaybePackage::Virtual(vm) => vm.profiles(),
@ -583,14 +582,6 @@ impl<'cfg> Workspace<'cfg> {
/// 2. All workspace members agree on this one root as the root. /// 2. All workspace members agree on this one root as the root.
/// 3. The current crate is a member of this workspace. /// 3. The current crate is a member of this workspace.
fn validate(&mut self) -> CargoResult<()> { fn validate(&mut self) -> CargoResult<()> {
// Validate config profiles only once per workspace.
let features = self.features();
let mut warnings = Vec::new();
self.config.profiles()?.validate(features, &mut warnings)?;
for warning in warnings {
self.config.shell().warn(&warning)?;
}
// The rest of the checks require a VirtualManifest or multiple members. // The rest of the checks require a VirtualManifest or multiple members.
if self.root_manifest.is_none() { if self.root_manifest.is_none() {
return Ok(()); return Ok(());

View File

@ -1,13 +1,12 @@
use crate::core::InternedString;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
use crate::core::compiler::unit_dependencies; use crate::core::compiler::unit_dependencies;
use crate::core::compiler::UnitInterner; use crate::core::compiler::UnitInterner;
use crate::core::compiler::{ use crate::core::compiler::{BuildConfig, BuildContext, CompileKind, CompileMode, Context};
BuildConfig, BuildContext, CompileKind, CompileMode, Context, ProfileKind, use crate::core::profiles::{Profiles, UnitFor};
};
use crate::core::profiles::UnitFor;
use crate::core::Workspace; use crate::core::Workspace;
use crate::ops; use crate::ops;
use crate::util::errors::{CargoResult, CargoResultExt}; use crate::util::errors::{CargoResult, CargoResultExt};
@ -23,7 +22,7 @@ pub struct CleanOptions<'a> {
/// Whether to clean the release directory /// Whether to clean the release directory
pub profile_specified: bool, pub profile_specified: bool,
/// Whether to clean the directory of a certain build profile /// Whether to clean the directory of a certain build profile
pub profile_kind: ProfileKind, pub requested_profile: InternedString,
/// Whether to just clean the doc directory /// Whether to just clean the doc directory
pub doc: bool, pub doc: bool,
} }
@ -39,16 +38,13 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
return rm_rf(&target_dir.into_path_unlocked(), config); return rm_rf(&target_dir.into_path_unlocked(), config);
} }
let profiles = ws.profiles(); let profiles = Profiles::new(ws.profiles(), config, opts.requested_profile, ws.features())?;
// Check for whether the profile is defined.
let _ = profiles.base_profile(&opts.profile_kind)?;
if opts.profile_specified { if opts.profile_specified {
// After parsing profiles we know the dir-name of the profile, if a profile // After parsing profiles we know the dir-name of the profile, if a profile
// was passed from the command line. If so, delete only the directory of // was passed from the command line. If so, delete only the directory of
// that profile. // that profile.
let dir_name = profiles.get_dir_name(&opts.profile_kind); let dir_name = profiles.get_dir_name();
target_dir = target_dir.join(dir_name); target_dir = target_dir.join(dir_name);
} }
@ -64,8 +60,7 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
let interner = UnitInterner::new(); let interner = UnitInterner::new();
let mut build_config = BuildConfig::new(config, Some(1), &opts.target, CompileMode::Build)?; let mut build_config = BuildConfig::new(config, Some(1), &opts.target, CompileMode::Build)?;
let profile_kind = opts.profile_kind.clone(); build_config.requested_profile = opts.requested_profile;
build_config.profile_kind = profile_kind.clone();
let bcx = BuildContext::new( let bcx = BuildContext::new(
ws, ws,
&packages, &packages,
@ -88,20 +83,19 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> {
for mode in CompileMode::all_modes() { for mode in CompileMode::all_modes() {
for unit_for in UnitFor::all_values() { for unit_for in UnitFor::all_values() {
let profile = if mode.is_run_custom_build() { let profile = if mode.is_run_custom_build() {
profiles.get_profile_run_custom_build(&profiles.get_profile( bcx.profiles
pkg.package_id(), .get_profile_run_custom_build(&bcx.profiles.get_profile(
ws.is_member(pkg), pkg.package_id(),
*unit_for, ws.is_member(pkg),
CompileMode::Build, *unit_for,
profile_kind.clone(), CompileMode::Build,
)) ))
} else { } else {
profiles.get_profile( bcx.profiles.get_profile(
pkg.package_id(), pkg.package_id(),
ws.is_member(pkg), ws.is_member(pkg),
*unit_for, *unit_for,
*mode, *mode,
profile_kind.clone(),
) )
}; };
let features = resolve.features_sorted(pkg.package_id()); let features = resolve.features_sorted(pkg.package_id());

View File

@ -300,10 +300,12 @@ pub fn compile_ws<'a>(
} }
} }
let profiles = ws.profiles(); let profiles = Profiles::new(
ws.profiles(),
// Early check for whether the profile is defined. config,
let _ = profiles.base_profile(&build_config.profile_kind)?; build_config.requested_profile,
ws.features(),
)?;
let specs = spec.to_package_id_specs(ws)?; let specs = spec.to_package_id_specs(ws)?;
let dev_deps = ws.require_optional_deps() || filter.need_dev_deps(build_config.mode); let dev_deps = ws.require_optional_deps() || filter.need_dev_deps(build_config.mode);
@ -381,6 +383,7 @@ pub fn compile_ws<'a>(
} }
profiles.validate_packages( profiles.validate_packages(
ws.profiles(),
&mut config.shell(), &mut config.shell(),
workspace_resolve.as_ref().unwrap_or(&resolve), workspace_resolve.as_ref().unwrap_or(&resolve),
)?; )?;
@ -397,7 +400,6 @@ pub fn compile_ws<'a>(
)?; )?;
let units = generate_targets( let units = generate_targets(
ws, ws,
profiles,
&to_builds, &to_builds,
filter, filter,
build_config.requested_kind, build_config.requested_kind,
@ -652,7 +654,6 @@ struct Proposal<'a> {
/// compile. Dependencies for these targets are computed later in `unit_dependencies`. /// compile. Dependencies for these targets are computed later in `unit_dependencies`.
fn generate_targets<'a>( fn generate_targets<'a>(
ws: &Workspace<'_>, ws: &Workspace<'_>,
profiles: &Profiles,
packages: &[&'a Package], packages: &[&'a Package],
filter: &CompileFilter, filter: &CompileFilter,
default_arch_kind: CompileKind, default_arch_kind: CompileKind,
@ -716,13 +717,9 @@ fn generate_targets<'a>(
_ => target_mode, _ => target_mode,
}; };
let kind = default_arch_kind.for_target(target); let kind = default_arch_kind.for_target(target);
let profile = profiles.get_profile( let profile =
pkg.package_id(), bcx.profiles
ws.is_member(pkg), .get_profile(pkg.package_id(), ws.is_member(pkg), unit_for, target_mode);
unit_for,
target_mode,
bcx.build_config.profile_kind.clone(),
);
let features = resolve.features_sorted(pkg.package_id()); let features = resolve.features_sorted(pkg.package_id());
bcx.units.intern( bcx.units.intern(
pkg, pkg,

View File

@ -427,7 +427,7 @@ impl CrateListingV2 {
info.features = feature_set(&opts.features); info.features = feature_set(&opts.features);
info.all_features = opts.all_features; info.all_features = opts.all_features;
info.no_default_features = opts.no_default_features; info.no_default_features = opts.no_default_features;
info.profile = opts.build_config.profile_name().to_string(); info.profile = opts.build_config.requested_profile.to_string();
info.target = Some(target.to_string()); info.target = Some(target.to_string());
info.rustc = Some(rustc.to_string()); info.rustc = Some(rustc.to_string());
} else { } else {
@ -439,7 +439,7 @@ impl CrateListingV2 {
features: feature_set(&opts.features), features: feature_set(&opts.features),
all_features: opts.all_features, all_features: opts.all_features,
no_default_features: opts.no_default_features, no_default_features: opts.no_default_features,
profile: opts.build_config.profile_name().to_string(), profile: opts.build_config.requested_profile.to_string(),
target: Some(target.to_string()), target: Some(target.to_string()),
rustc: Some(rustc.to_string()), rustc: Some(rustc.to_string()),
other: BTreeMap::new(), other: BTreeMap::new(),
@ -499,7 +499,7 @@ impl InstallInfo {
self.features == feature_set(&opts.features) self.features == feature_set(&opts.features)
&& self.all_features == opts.all_features && self.all_features == opts.all_features
&& self.no_default_features == opts.no_default_features && self.no_default_features == opts.no_default_features
&& self.profile == opts.build_config.profile_name() && self.profile.as_str() == opts.build_config.requested_profile.as_str()
&& (self.target.is_none() || self.target.as_ref().map(|t| t.as_ref()) == Some(target)) && (self.target.is_none() || self.target.as_ref().map(|t| t.as_ref()) == Some(target))
&& &self.bins == exes && &self.bins == exes
} }

View File

@ -1,4 +1,5 @@
use crate::core::compiler::{BuildConfig, MessageFormat}; use crate::core::compiler::{BuildConfig, MessageFormat};
use crate::core::InternedString;
use crate::core::Workspace; use crate::core::Workspace;
use crate::ops::{CompileFilter, CompileOptions, NewOptions, Packages, VersionControl}; use crate::ops::{CompileFilter, CompileOptions, NewOptions, Packages, VersionControl};
use crate::sources::CRATES_IO_REGISTRY; use crate::sources::CRATES_IO_REGISTRY;
@ -15,7 +16,7 @@ use std::ffi::{OsStr, OsString};
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
pub use crate::core::compiler::{CompileMode, ProfileKind}; pub use crate::core::compiler::CompileMode;
pub use crate::{CliError, CliResult, Config}; pub use crate::{CliError, CliResult, Config};
pub use clap::{AppSettings, Arg, ArgMatches}; pub use clap::{AppSettings, Arg, ArgMatches};
@ -307,19 +308,17 @@ pub trait ArgMatchesExt {
self._value_of("target").map(|s| s.to_string()) self._value_of("target").map(|s| s.to_string())
} }
fn get_profile_kind( fn get_profile_name(
&self, &self,
config: &Config, config: &Config,
default: ProfileKind, default: &str,
profile_checking: ProfileChecking, profile_checking: ProfileChecking,
) -> CargoResult<ProfileKind> { ) -> CargoResult<InternedString> {
let specified_profile = match self._value_of("profile") { let specified_profile = match self._value_of("profile") {
None => None, None => None,
Some("dev") => Some(ProfileKind::Dev),
Some("release") => Some(ProfileKind::Release),
Some(name) => { Some(name) => {
TomlProfile::validate_name(name, "profile name")?; TomlProfile::validate_name(name, "profile name")?;
Some(ProfileKind::Custom(name.to_string())) Some(InternedString::new(name))
} }
}; };
@ -334,24 +333,28 @@ pub trait ArgMatchesExt {
if self._is_present("release") { if self._is_present("release") {
if !config.cli_unstable().unstable_options { if !config.cli_unstable().unstable_options {
Ok(ProfileKind::Release) Ok(InternedString::new("release"))
} else { } else {
match specified_profile { match specified_profile {
None | Some(ProfileKind::Release) => Ok(ProfileKind::Release), Some(name) if name != "release" => {
_ => anyhow::bail!("Conflicting usage of --profile and --release"), anyhow::bail!("Conflicting usage of --profile and --release")
}
_ => Ok(InternedString::new("release")),
} }
} }
} else if self._is_present("debug") { } else if self._is_present("debug") {
if !config.cli_unstable().unstable_options { if !config.cli_unstable().unstable_options {
Ok(ProfileKind::Dev) Ok(InternedString::new("dev"))
} else { } else {
match specified_profile { match specified_profile {
None | Some(ProfileKind::Dev) => Ok(ProfileKind::Dev), Some(name) if name != "dev" => {
_ => anyhow::bail!("Conflicting usage of --profile and --debug"), anyhow::bail!("Conflicting usage of --profile and --debug")
}
_ => Ok(InternedString::new("dev")),
} }
} }
} else { } else {
Ok(specified_profile.unwrap_or(default)) Ok(specified_profile.unwrap_or_else(|| InternedString::new(default)))
} }
} }
@ -433,8 +436,7 @@ pub trait ArgMatchesExt {
let mut build_config = BuildConfig::new(config, self.jobs()?, &self.target(), mode)?; let mut build_config = BuildConfig::new(config, self.jobs()?, &self.target(), mode)?;
build_config.message_format = message_format.unwrap_or(MessageFormat::Human); build_config.message_format = message_format.unwrap_or(MessageFormat::Human);
build_config.profile_kind = build_config.requested_profile = self.get_profile_name(config, "dev", profile_checking)?;
self.get_profile_kind(config, ProfileKind::Dev, profile_checking)?;
build_config.build_plan = self._is_present("build-plan"); build_config.build_plan = self._is_present("build-plan");
if build_config.build_plan { if build_config.build_plan {
config config

View File

@ -425,13 +425,11 @@ impl<'config> ValueDeserializer<'config> {
cv.definition().clone() cv.definition().clone()
} }
} }
(true, None) => env_def,
(false, Some(cv)) => cv.definition().clone(), (false, Some(cv)) => cv.definition().clone(),
(false, None) => { // Assume it is an environment, even if the key is not set.
return Err( // This can happen for intermediate tables, like
anyhow::format_err!("failed to find definition of `{}`", de.key).into(), // CARGO_FOO_BAR_* where `CARGO_FOO_BAR` is not set.
) (_, None) => env_def,
}
} }
}; };
Ok(ValueDeserializer { Ok(ValueDeserializer {

View File

@ -70,7 +70,6 @@ use serde::Deserialize;
use url::Url; use url::Url;
use self::ConfigValue as CV; use self::ConfigValue as CV;
use crate::core::profiles::ConfigProfiles;
use crate::core::shell::Verbosity; use crate::core::shell::Verbosity;
use crate::core::{nightly_features_allowed, CliUnstable, Shell, SourceId, Workspace}; use crate::core::{nightly_features_allowed, CliUnstable, Shell, SourceId, Workspace};
use crate::ops; use crate::ops;
@ -163,8 +162,6 @@ pub struct Config {
target_dir: Option<Filesystem>, target_dir: Option<Filesystem>,
/// Environment variables, separated to assist testing. /// Environment variables, separated to assist testing.
env: HashMap<String, String>, env: HashMap<String, String>,
/// Profiles loaded from config.
profiles: LazyCell<ConfigProfiles>,
/// Tracks which sources have been updated to avoid multiple updates. /// Tracks which sources have been updated to avoid multiple updates.
updated_sources: LazyCell<RefCell<HashSet<SourceId>>>, updated_sources: LazyCell<RefCell<HashSet<SourceId>>>,
/// Lock, if held, of the global package cache along with the number of /// Lock, if held, of the global package cache along with the number of
@ -238,7 +235,6 @@ impl Config {
creation_time: Instant::now(), creation_time: Instant::now(),
target_dir: None, target_dir: None,
env, env,
profiles: LazyCell::new(),
updated_sources: LazyCell::new(), updated_sources: LazyCell::new(),
package_cache_lock: RefCell::new(None), package_cache_lock: RefCell::new(None),
http_config: LazyCell::new(), http_config: LazyCell::new(),
@ -372,26 +368,6 @@ impl Config {
.map(AsRef::as_ref) .map(AsRef::as_ref)
} }
/// Gets profiles defined in config files.
pub fn profiles(&self) -> CargoResult<&ConfigProfiles> {
self.profiles.try_borrow_with(|| {
let ocp = self.get::<Option<ConfigProfiles>>("profile")?;
if let Some(config_profiles) = ocp {
// Warn if config profiles without CLI option.
if !self.cli_unstable().config_profile {
self.shell().warn(
"profiles in config files require `-Z config-profile` \
command-line option",
)?;
return Ok(ConfigProfiles::default());
}
Ok(config_profiles)
} else {
Ok(ConfigProfiles::default())
}
})
}
/// Which package sources have been updated, used to ensure it is only done once. /// Which package sources have been updated, used to ensure it is only done once.
pub fn updated_sources(&self) -> RefMut<'_, HashSet<SourceId>> { pub fn updated_sources(&self) -> RefMut<'_, HashSet<SourceId>> {
self.updated_sources self.updated_sources

View File

@ -16,7 +16,6 @@ use url::Url;
use crate::core::dependency::DepKind; use crate::core::dependency::DepKind;
use crate::core::manifest::{LibKind, ManifestMetadata, TargetSourcePath, Warnings}; use crate::core::manifest::{LibKind, ManifestMetadata, TargetSourcePath, Warnings};
use crate::core::profiles::Profiles;
use crate::core::{Dependency, InternedString, Manifest, PackageId, Summary, Target}; use crate::core::{Dependency, InternedString, Manifest, PackageId, Summary, Target};
use crate::core::{Edition, EitherManifest, Feature, Features, VirtualManifest}; use crate::core::{Edition, EitherManifest, Feature, Features, VirtualManifest};
use crate::core::{GitReference, PackageIdSpec, SourceId, WorkspaceConfig, WorkspaceRootConfig}; use crate::core::{GitReference, PackageIdSpec, SourceId, WorkspaceConfig, WorkspaceRootConfig};
@ -270,23 +269,19 @@ pub struct TomlManifest {
} }
#[derive(Deserialize, Serialize, Clone, Debug, Default)] #[derive(Deserialize, Serialize, Clone, Debug, Default)]
pub struct TomlProfiles(BTreeMap<String, TomlProfile>); pub struct TomlProfiles(BTreeMap<InternedString, TomlProfile>);
impl TomlProfiles { impl TomlProfiles {
pub fn get_all(&self) -> &BTreeMap<String, TomlProfile> { pub fn get_all(&self) -> &BTreeMap<InternedString, TomlProfile> {
&self.0 &self.0
} }
pub fn get(&self, name: &'static str) -> Option<&TomlProfile> { pub fn get(&self, name: &str) -> Option<&TomlProfile> {
self.0.get(&String::from(name)) self.0.get(name)
} }
pub fn validate(&self, features: &Features, warnings: &mut Vec<String>) -> CargoResult<()> { pub fn validate(&self, features: &Features, warnings: &mut Vec<String>) -> CargoResult<()> {
for (name, profile) in &self.0 { for (name, profile) in &self.0 {
if name == "debug" {
warnings.push("use `[profile.dev]` to configure debug builds".to_string());
}
profile.validate(name, features, warnings)?; profile.validate(name, features, warnings)?;
} }
Ok(()) Ok(())
@ -408,13 +403,10 @@ pub struct TomlProfile {
pub panic: Option<String>, pub panic: Option<String>,
pub overflow_checks: Option<bool>, pub overflow_checks: Option<bool>,
pub incremental: Option<bool>, pub incremental: Option<bool>,
// `overrides` has been renamed to `package`, this should be removed when
// stabilized.
pub overrides: Option<BTreeMap<ProfilePackageSpec, TomlProfile>>,
pub package: Option<BTreeMap<ProfilePackageSpec, TomlProfile>>, pub package: Option<BTreeMap<ProfilePackageSpec, TomlProfile>>,
pub build_override: Option<Box<TomlProfile>>, pub build_override: Option<Box<TomlProfile>>,
pub dir_name: Option<String>, pub dir_name: Option<InternedString>,
pub inherits: Option<String>, pub inherits: Option<InternedString>,
} }
#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
@ -458,21 +450,14 @@ impl TomlProfile {
features: &Features, features: &Features,
warnings: &mut Vec<String>, warnings: &mut Vec<String>,
) -> CargoResult<()> { ) -> CargoResult<()> {
if name == "debug" {
warnings.push("use `[profile.dev]` to configure debug builds".to_string());
}
if let Some(ref profile) = self.build_override { if let Some(ref profile) = self.build_override {
features.require(Feature::profile_overrides())?; features.require(Feature::profile_overrides())?;
profile.validate_override("build-override")?; profile.validate_override("build-override")?;
} }
if let Some(ref override_map) = self.overrides {
warnings.push(
"profile key `overrides` has been renamed to `package`, \
please update the manifest to the new key name"
.to_string(),
);
features.require(Feature::profile_overrides())?;
for profile in override_map.values() {
profile.validate_override("package")?;
}
}
if let Some(ref packages) = self.package { if let Some(ref packages) = self.package {
features.require(Feature::profile_overrides())?; features.require(Feature::profile_overrides())?;
for profile in packages.values() { for profile in packages.values() {
@ -570,7 +555,7 @@ impl TomlProfile {
} }
fn validate_override(&self, which: &str) -> CargoResult<()> { fn validate_override(&self, which: &str) -> CargoResult<()> {
if self.overrides.is_some() || self.package.is_some() { if self.package.is_some() {
bail!("package-specific profiles cannot be nested"); bail!("package-specific profiles cannot be nested");
} }
if self.build_override.is_some() { if self.build_override.is_some() {
@ -588,6 +573,7 @@ impl TomlProfile {
Ok(()) Ok(())
} }
/// Overwrite self's values with the given profile.
pub fn merge(&mut self, profile: &TomlProfile) { pub fn merge(&mut self, profile: &TomlProfile) {
if let Some(v) = &profile.opt_level { if let Some(v) = &profile.opt_level {
self.opt_level = Some(v.clone()); self.opt_level = Some(v.clone());
@ -625,16 +611,27 @@ impl TomlProfile {
self.incremental = Some(v); self.incremental = Some(v);
} }
if let Some(v) = &profile.overrides { if let Some(other_package) = &profile.package {
self.overrides = Some(v.clone()); match &mut self.package {
Some(self_package) => {
for (spec, other_pkg_profile) in other_package {
match self_package.get_mut(spec) {
Some(p) => p.merge(other_pkg_profile),
None => {
self_package.insert(spec.clone(), other_pkg_profile.clone());
}
}
}
}
None => self.package = Some(other_package.clone()),
}
} }
if let Some(v) = &profile.package { if let Some(other_bo) = &profile.build_override {
self.package = Some(v.clone()); match &mut self.build_override {
} Some(self_bo) => self_bo.merge(other_bo),
None => self.build_override = Some(other_bo.clone()),
if let Some(v) = &profile.build_override { }
self.build_override = Some(v.clone());
} }
if let Some(v) = &profile.inherits { if let Some(v) = &profile.inherits {
@ -1173,7 +1170,10 @@ impl TomlManifest {
`[workspace]`, only one can be specified" `[workspace]`, only one can be specified"
), ),
}; };
let profiles = Profiles::new(me.profile.as_ref(), config, &features, &mut warnings)?; let profiles = me.profile.clone();
if let Some(profiles) = &profiles {
profiles.validate(&features, &mut warnings)?;
}
let publish = match project.publish { let publish = match project.publish {
Some(VecStringOrBool::VecString(ref vecstring)) => Some(vecstring.clone()), Some(VecStringOrBool::VecString(ref vecstring)) => Some(vecstring.clone()),
Some(VecStringOrBool::Bool(false)) => Some(vec![]), Some(VecStringOrBool::Bool(false)) => Some(vec![]),
@ -1321,7 +1321,10 @@ impl TomlManifest {
}; };
(me.replace(&mut cx)?, me.patch(&mut cx)?) (me.replace(&mut cx)?, me.patch(&mut cx)?)
}; };
let profiles = Profiles::new(me.profile.as_ref(), config, &features, &mut warnings)?; let profiles = me.profile.clone();
if let Some(profiles) = &profiles {
profiles.validate(&features, &mut warnings)?;
}
let workspace_config = match me.workspace { let workspace_config = match me.workspace {
Some(ref config) => WorkspaceConfig::Root(WorkspaceRootConfig::new( Some(ref config) => WorkspaceConfig::Root(WorkspaceRootConfig::new(
root, root,

View File

@ -1,5 +1,11 @@
//! Tests for config settings. //! Tests for config settings.
use cargo::core::{enable_nightly_features, InternedString, Shell};
use cargo::util::config::{self, Config, SslVersionConfig, StringList};
use cargo::util::toml::{self, VecStringOrBool as VSOB};
use cargo::CargoResult;
use cargo_test_support::{normalized_lines_match, paths, project, t};
use serde::Deserialize;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::fs; use std::fs;
@ -7,13 +13,6 @@ use std::io;
use std::os; use std::os;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use cargo::core::{enable_nightly_features, Shell};
use cargo::util::config::{self, Config, SslVersionConfig, StringList};
use cargo::util::toml::{self, VecStringOrBool as VSOB};
use cargo::CargoResult;
use cargo_test_support::{normalized_lines_match, paths, project, t};
use serde::Deserialize;
/// Helper for constructing a `Config` object. /// Helper for constructing a `Config` object.
pub struct ConfigBuilder { pub struct ConfigBuilder {
env: HashMap<String, String>, env: HashMap<String, String>,
@ -424,8 +423,8 @@ lto = false
p, p,
toml::TomlProfile { toml::TomlProfile {
lto: Some(toml::StringOrBool::Bool(false)), lto: Some(toml::StringOrBool::Bool(false)),
dir_name: Some("without-lto".to_string()), dir_name: Some(InternedString::new("without-lto")),
inherits: Some("dev".to_string()), inherits: Some(InternedString::new("dev")),
..Default::default() ..Default::default()
} }
); );

View File

@ -1,5 +1,6 @@
//! Tests for profiles defined in config files. //! Tests for profiles defined in config files.
use cargo_test_support::paths::CargoPathExt;
use cargo_test_support::{basic_lib_manifest, paths, project}; use cargo_test_support::{basic_lib_manifest, paths, project};
#[cargo_test] #[cargo_test]
@ -19,13 +20,44 @@ fn profile_config_gated() {
p.cargo("build -v") p.cargo("build -v")
.with_stderr_contains( .with_stderr_contains(
"\ "\
[WARNING] profiles in config files require `-Z config-profile` command-line option [WARNING] config profiles require the `-Z config-profile` command-line option \
(found profile `dev` in [..]/foo/.cargo/config)
", ",
) )
.with_stderr_contains("[..]-C debuginfo=2[..]") .with_stderr_contains("[..]-C debuginfo=2[..]")
.run(); .run();
} }
#[cargo_test]
fn named_profile_gated() {
// Named profile in config requires enabling in Cargo.toml.
let p = project()
.file("src/lib.rs", "")
.file(
".cargo/config",
r#"
[profile.foo]
inherits = 'dev'
opt-level = 1
"#,
)
.build();
p.cargo("build --profile foo -Zunstable-options -Zconfig-profile")
.masquerade_as_nightly_cargo()
.with_stderr(
"\
[ERROR] config profile `foo` is not valid (defined in `[..]/foo/.cargo/config`)
Caused by:
feature `named-profiles` is required
consider adding `cargo-features = [\"named-profiles\"]` to the manifest
",
)
.with_status(101)
.run();
}
#[cargo_test] #[cargo_test]
fn profile_config_validate_warnings() { fn profile_config_validate_warnings() {
let p = project() let p = project()
@ -56,8 +88,6 @@ fn profile_config_validate_warnings() {
.masquerade_as_nightly_cargo() .masquerade_as_nightly_cargo()
.with_stderr_unordered( .with_stderr_unordered(
"\ "\
[WARNING] unused config key `profile.asdf` in `[..].cargo/config`
[WARNING] unused config key `profile.test` in `[..].cargo/config`
[WARNING] unused config key `profile.dev.bad-key` in `[..].cargo/config` [WARNING] unused config key `profile.dev.bad-key` in `[..].cargo/config`
[WARNING] unused config key `profile.dev.package.bar.bad-key-bar` in `[..].cargo/config` [WARNING] unused config key `profile.dev.package.bar.bad-key-bar` in `[..].cargo/config`
[WARNING] unused config key `profile.dev.build-override.bad-key-bo` in `[..].cargo/config` [WARNING] unused config key `profile.dev.build-override.bad-key-bo` in `[..].cargo/config`
@ -70,6 +100,7 @@ fn profile_config_validate_warnings() {
#[cargo_test] #[cargo_test]
fn profile_config_error_paths() { fn profile_config_error_paths() {
// Errors in config show where the error is located.
let p = project() let p = project()
.file("Cargo.toml", &basic_lib_manifest("foo")) .file("Cargo.toml", &basic_lib_manifest("foo"))
.file("src/lib.rs", "") .file("src/lib.rs", "")
@ -94,10 +125,10 @@ fn profile_config_error_paths() {
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
"\ "\
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml` [ERROR] error in [..]/foo/.cargo/config: \
could not load config key `profile.dev`: \
Caused by: error in [..]/home/.cargo/config: \
error in [..].cargo/config: `profile.dev.rpath` expected true/false, but found a string `profile.dev.rpath` expected true/false, but found a string
", ",
) )
.run(); .run();
@ -122,7 +153,7 @@ fn profile_config_validate_errors() {
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
"\ "\
[ERROR] config profile `profile.dev` is not valid [ERROR] config profile `dev` is not valid (defined in `[..]/foo/.cargo/config`)
Caused by: Caused by:
`panic` may not be specified in a `package` profile `panic` may not be specified in a `package` profile
@ -150,10 +181,10 @@ fn profile_config_syntax_errors() {
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
"\ "\
[ERROR] failed to parse manifest at [..] [ERROR] error in [..]/foo/.cargo/config: \
could not load config key `profile.dev`: \
Caused by: error in [..]/foo/.cargo/config: \
error in [..].cargo/config: `profile.dev.codegen-units` expected an integer, but found a string `profile.dev.codegen-units` expected an integer, but found a string
", ",
) )
.run(); .run();
@ -337,3 +368,123 @@ fn profile_config_mixed_types() {
.with_stderr_contains("[..]-C opt-level=3 [..]") .with_stderr_contains("[..]-C opt-level=3 [..]")
.run(); .run();
} }
#[cargo_test]
fn named_config_profile() {
// Exercises config named profies.
// foo -> middle -> bar -> dev
// middle exists in Cargo.toml, the others in .cargo/config
use super::config::ConfigBuilder;
use cargo::core::compiler::CompileMode;
use cargo::core::enable_nightly_features;
use cargo::core::features::Features;
use cargo::core::profiles::{Profiles, UnitFor};
use cargo::core::{InternedString, PackageId};
use cargo::util::toml::TomlProfiles;
use std::fs;
enable_nightly_features();
paths::root().join(".cargo").mkdir_p();
fs::write(
paths::root().join(".cargo/config"),
r#"
[profile.foo]
inherits = "middle"
codegen-units = 2
[profile.foo.build-override]
codegen-units = 6
[profile.foo.package.dep]
codegen-units = 7
[profile.middle]
inherits = "bar"
codegen-units = 3
[profile.bar]
inherits = "dev"
codegen-units = 4
debug = 1
"#,
)
.unwrap();
let config = ConfigBuilder::new().unstable_flag("config-profile").build();
let mut warnings = Vec::new();
let features = Features::new(&["named-profiles".to_string()], &mut warnings).unwrap();
assert_eq!(warnings.len(), 0);
let profile_name = InternedString::new("foo");
let toml = r#"
[profile.middle]
inherits = "bar"
codegen-units = 1
opt-level = 1
[profile.middle.package.dep]
overflow-checks = false
[profile.foo.build-override]
codegen-units = 5
debug-assertions = false
[profile.foo.package.dep]
codegen-units = 8
"#;
#[derive(serde::Deserialize)]
struct TomlManifest {
profile: Option<TomlProfiles>,
}
let manifest: TomlManifest = toml::from_str(toml).unwrap();
let profiles =
Profiles::new(manifest.profile.as_ref(), &config, profile_name, &features).unwrap();
let crates_io = cargo::core::source::SourceId::crates_io(&config).unwrap();
let a_pkg = PackageId::new("a", "0.1.0", crates_io).unwrap();
let dep_pkg = PackageId::new("dep", "0.1.0", crates_io).unwrap();
// normal package
let p = profiles.get_profile(a_pkg, true, UnitFor::new_normal(), CompileMode::Build);
assert_eq!(p.name, "foo");
assert_eq!(p.codegen_units, Some(2)); // "foo" from config
assert_eq!(p.opt_level, "1"); // "middle" from manifest
assert_eq!(p.debuginfo, Some(1)); // "bar" from config
assert_eq!(p.debug_assertions, true); // "dev" built-in (ignore build-override)
assert_eq!(p.overflow_checks, true); // "dev" built-in (ignore package override)
// build-override
let bo = profiles.get_profile(a_pkg, true, UnitFor::new_build(), CompileMode::Build);
assert_eq!(bo.name, "foo");
assert_eq!(bo.codegen_units, Some(6)); // "foo" build override from config
assert_eq!(bo.opt_level, "1"); // SAME as normal
assert_eq!(bo.debuginfo, Some(1)); // SAME as normal
assert_eq!(bo.debug_assertions, false); // "foo" build override from manifest
assert_eq!(bo.overflow_checks, true); // SAME as normal
// package overrides
let po = profiles.get_profile(dep_pkg, false, UnitFor::new_normal(), CompileMode::Build);
assert_eq!(po.name, "foo");
assert_eq!(po.codegen_units, Some(7)); // "foo" package override from config
assert_eq!(po.opt_level, "1"); // SAME as normal
assert_eq!(po.debuginfo, Some(1)); // SAME as normal
assert_eq!(po.debug_assertions, true); // SAME as normal
assert_eq!(po.overflow_checks, false); // "middle" package override from manifest
}
#[cargo_test]
fn named_env_profile() {
// Environment variables used to define a named profile.
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["named-profiles"]
[package]
name = "foo"
version = "0.1.0"
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("build -v -Zconfig-profile -Zunstable-options --profile=other")
.masquerade_as_nightly_cargo()
.env("CARGO_PROFILE_OTHER_CODEGEN_UNITS", "1")
.env("CARGO_PROFILE_OTHER_INHERITS", "dev")
.with_stderr_contains("[..]-C codegen-units=1 [..]")
.run();
}

View File

@ -27,10 +27,7 @@ fn inherits_on_release() {
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
"\ "\
[ERROR] failed to parse manifest at [..] [ERROR] `inherits` must not be specified in root profile `release`
Caused by:
An 'inherits' must not specified root profile 'release'
", ",
) )
.run(); .run();
@ -61,10 +58,9 @@ fn missing_inherits() {
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
"\ "\
[ERROR] failed to parse manifest at [..] [ERROR] profile `release-lto` is missing an `inherits` directive \
(`inherits` is required for all profiles except `dev` or `release`)
Caused by: ",
An 'inherits' directive is needed for all profiles that are not 'dev' or 'release'. Here it is missing from 'release-lto'",
) )
.run(); .run();
} }
@ -198,10 +194,8 @@ fn non_existent_inherits() {
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
"\ "\
[ERROR] failed to parse manifest at [..] [ERROR] profile `release-lto` inherits from `non-existent`, but that profile is not defined
",
Caused by:
Profile 'non-existent' not found in Cargo.toml",
) )
.run(); .run();
} }
@ -232,10 +226,8 @@ fn self_inherits() {
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
"\ "\
[ERROR] failed to parse manifest at [..] [ERROR] profile inheritance loop detected with profile `release-lto` inheriting `release-lto`
",
Caused by:
Inheritance loop of profiles cycles with profile 'release-lto'",
) )
.run(); .run();
} }
@ -270,10 +262,8 @@ fn inherits_loop() {
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
"\ "\
[ERROR] failed to parse manifest at [..] [ERROR] profile inheritance loop detected with profile `release-lto2` inheriting `release-lto`
",
Caused by:
Inheritance loop of profiles cycles with profile 'release-lto'",
) )
.run(); .run();
} }
@ -477,3 +467,32 @@ fn clean_custom_dirname() {
assert!(p.build_dir().join("debug").is_dir()); assert!(p.build_dir().join("debug").is_dir());
assert!(!p.build_dir().join("other").is_dir()); assert!(!p.build_dir().join("other").is_dir());
} }
#[cargo_test]
fn unknown_profile() {
let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["named-profiles"]
[package]
name = "foo"
version = "0.0.1"
"#,
)
.file("src/lib.rs", "")
.build();
p.cargo("build --profile alpha -Zunstable-options")
.masquerade_as_nightly_cargo()
.with_stderr("[ERROR] profile `alpha` is not defined")
.with_status(101)
.run();
// Clean has a separate code path, need to check it too.
p.cargo("clean --profile alpha -Zunstable-options")
.masquerade_as_nightly_cargo()
.with_stderr("[ERROR] profile `alpha` is not defined")
.with_status(101)
.run();
}

View File

@ -68,13 +68,16 @@ fn profile_override_warnings() {
.file("bar/src/lib.rs", "") .file("bar/src/lib.rs", "")
.build(); .build();
p.cargo("build").with_stderr_contains( p.cargo("build")
.with_stderr_contains(
"\ "\
[WARNING] version or URL in package profile spec `bar:1.2.3` does not match any of the packages: bar v0.5.0 ([..]) [WARNING] profile package spec `bar:1.2.3` in profile `dev` \
[WARNING] package profile spec `bart` did not match any packages has a version or URL that does not match any of the packages: \
bar v0.5.0 ([..]/foo/bar)
[WARNING] profile package spec `bart` in profile `dev` did not match any packages
<tab>Did you mean `bar`? <tab>Did you mean `bar`?
[WARNING] package profile spec `no-suggestion` did not match any packages [WARNING] profile package spec `no-suggestion` in profile `dev` did not match any packages
[COMPILING] [..] [COMPILING] [..]
", ",
) )
@ -96,10 +99,7 @@ fn profile_override_bad_settings() {
"rpath = true", "rpath = true",
"`rpath` may not be specified in a `package` profile", "`rpath` may not be specified in a `package` profile",
), ),
( ("package = {}", "package-specific profiles cannot be nested"),
"overrides = {}",
"package-specific profiles cannot be nested",
),
]; ];
for &(snippet, expected) in bad_values.iter() { for &(snippet, expected) in bad_values.iter() {
let p = project() let p = project()
@ -394,42 +394,6 @@ fn override_proc_macro() {
.run(); .run();
} }
#[cargo_test]
fn override_package_rename() {
// backwards-compatibility test
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[dependencies]
bar = {path = "bar"}
[profile.dev]
opt-level = 1
[profile.dev.overrides.bar]
opt-level = 3
"#,
)
.file("src/lib.rs", "")
.file("bar/Cargo.toml", &basic_lib_manifest("bar"))
.file("bar/src/lib.rs", "")
.build();
p.cargo("check")
.with_stderr("\
[WARNING] profile key `overrides` has been renamed to `package`, please update the manifest to the new key name
[CHECKING] bar [..]
[CHECKING] foo [..]
[FINISHED] [..]
")
.run();
}
#[cargo_test] #[cargo_test]
fn no_warning_ws() { fn no_warning_ws() {
// https://github.com/rust-lang/cargo/issues/7378, avoid warnings in a workspace. // https://github.com/rust-lang/cargo/issues/7378, avoid warnings in a workspace.