Skip to content

Commit 9f09778

Browse files
committed
Auto merge of #5506 - ehuss:config-profile, r=alexcrichton
Config Profiles (RFC 2282 Part 2) Notes: - `-Z config-profile` CLI option is required to use. - Config values no longer reject mixed base types (integer, string, boolean) in order to support the mixed types in profiles.
2 parents cddf9ad + 84a80d8 commit 9f09778

File tree

9 files changed

+594
-129
lines changed

9 files changed

+594
-129
lines changed

src/bin/cargo/cli.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Available unstable (nightly-only) flags:
2121
-Z no-index-update -- Do not update the registry, avoids a network request for benchmarking
2222
-Z offline -- Offline mode that does not perform network requests
2323
-Z unstable-options -- Allow the usage of unstable options such as --registry
24+
-Z config-profile -- Read profiles from .cargo/config files
2425
2526
Run with 'cargo -Z [FLAG] [SUBCOMMAND]'"
2627
);

src/cargo/core/features.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ pub struct CliUnstable {
309309
pub minimal_versions: bool,
310310
pub package_features: bool,
311311
pub advanced_env: bool,
312+
pub config_profile: bool,
312313
}
313314

314315
impl CliUnstable {
@@ -344,6 +345,7 @@ impl CliUnstable {
344345
"minimal-versions" => self.minimal_versions = true,
345346
"package-features" => self.package_features = true,
346347
"advanced-env" => self.advanced_env = true,
348+
"config-profile" => self.config_profile = true,
347349
_ => bail!("unknown `-Z` flag specified: {}", k),
348350
}
349351

src/cargo/core/profiles.rs

Lines changed: 129 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ use std::{cmp, fmt, hash};
33

44
use core::compiler::CompileMode;
55
use core::interning::InternedString;
6-
use core::{PackageId, PackageIdSpec, PackageSet, Shell};
6+
use core::{Features, PackageId, PackageIdSpec, PackageSet, Shell};
7+
use util::errors::CargoResultExt;
78
use util::lev_distance::lev_distance;
8-
use util::toml::{ProfilePackageSpec, StringOrBool, TomlProfile, U32OrBool};
9-
use util::CargoResult;
9+
use util::toml::{ProfilePackageSpec, StringOrBool, TomlProfile, TomlProfiles, U32OrBool};
10+
use util::{CargoResult, Config};
1011

1112
/// Collection of all user profiles.
1213
#[derive(Clone, Debug)]
@@ -20,34 +21,45 @@ pub struct Profiles {
2021

2122
impl Profiles {
2223
pub fn new(
23-
dev: Option<TomlProfile>,
24-
release: Option<TomlProfile>,
25-
test: Option<TomlProfile>,
26-
bench: Option<TomlProfile>,
27-
doc: Option<TomlProfile>,
28-
) -> Profiles {
29-
Profiles {
24+
profiles: Option<&TomlProfiles>,
25+
config: &Config,
26+
features: &Features,
27+
warnings: &mut Vec<String>,
28+
) -> CargoResult<Profiles> {
29+
if let Some(profiles) = profiles {
30+
profiles.validate(features, warnings)?;
31+
}
32+
33+
let config_profiles = config.profiles()?;
34+
config_profiles.validate(features, warnings)?;
35+
36+
Ok(Profiles {
3037
dev: ProfileMaker {
3138
default: Profile::default_dev(),
32-
toml: dev,
39+
toml: profiles.and_then(|p| p.dev.clone()),
40+
config: config_profiles.dev.clone(),
3341
},
3442
release: ProfileMaker {
3543
default: Profile::default_release(),
36-
toml: release,
44+
toml: profiles.and_then(|p| p.release.clone()),
45+
config: config_profiles.release.clone(),
3746
},
3847
test: ProfileMaker {
3948
default: Profile::default_test(),
40-
toml: test,
49+
toml: profiles.and_then(|p| p.test.clone()),
50+
config: None,
4151
},
4252
bench: ProfileMaker {
4353
default: Profile::default_bench(),
44-
toml: bench,
54+
toml: profiles.and_then(|p| p.bench.clone()),
55+
config: None,
4556
},
4657
doc: ProfileMaker {
4758
default: Profile::default_doc(),
48-
toml: doc,
59+
toml: profiles.and_then(|p| p.doc.clone()),
60+
config: None,
4961
},
50-
}
62+
})
5163
}
5264

5365
/// Retrieve the profile for a target.
@@ -86,7 +98,7 @@ impl Profiles {
8698
CompileMode::Bench => &self.bench,
8799
CompileMode::Doc { .. } => &self.doc,
88100
};
89-
let mut profile = maker.profile_for(Some(pkg_id), is_member, profile_for);
101+
let mut profile = maker.get_profile(Some(pkg_id), is_member, profile_for);
90102
// `panic` should not be set for tests/benches, or any of their
91103
// dependencies.
92104
if profile_for == ProfileFor::TestDependency || mode.is_any_test() {
@@ -112,9 +124,9 @@ impl Profiles {
112124
/// select for the package that was actually built.
113125
pub fn base_profile(&self, release: bool) -> Profile {
114126
if release {
115-
self.release.profile_for(None, true, ProfileFor::Any)
127+
self.release.get_profile(None, true, ProfileFor::Any)
116128
} else {
117-
self.dev.profile_for(None, true, ProfileFor::Any)
129+
self.dev.get_profile(None, true, ProfileFor::Any)
118130
}
119131
}
120132

@@ -132,6 +144,7 @@ impl Profiles {
132144
/// An object used for handling the profile override hierarchy.
133145
///
134146
/// The precedence of profiles are (first one wins):
147+
/// - Profiles in .cargo/config files (using same order as below).
135148
/// - [profile.dev.overrides.name] - A named package.
136149
/// - [profile.dev.overrides."*"] - This cannot apply to workspace members.
137150
/// - [profile.dev.build-override] - This can only apply to `build.rs` scripts
@@ -140,60 +153,45 @@ impl Profiles {
140153
/// - Default (hard-coded) values.
141154
#[derive(Debug, Clone)]
142155
struct ProfileMaker {
156+
/// The starting, hard-coded defaults for the profile.
143157
default: Profile,
158+
/// The profile from the `Cargo.toml` manifest.
144159
toml: Option<TomlProfile>,
160+
/// Profile loaded from `.cargo/config` files.
161+
config: Option<TomlProfile>,
145162
}
146163

147164
impl ProfileMaker {
148-
fn profile_for(
165+
fn get_profile(
149166
&self,
150167
pkg_id: Option<&PackageId>,
151168
is_member: bool,
152169
profile_for: ProfileFor,
153170
) -> Profile {
154171
let mut profile = self.default;
155172
if let Some(ref toml) = self.toml {
156-
merge_profile(&mut profile, toml);
157-
if profile_for == ProfileFor::CustomBuild {
158-
if let Some(ref build_override) = toml.build_override {
159-
merge_profile(&mut profile, build_override);
160-
}
161-
}
162-
if let Some(ref overrides) = toml.overrides {
163-
if !is_member {
164-
if let Some(all) = overrides.get(&ProfilePackageSpec::All) {
165-
merge_profile(&mut profile, all);
166-
}
167-
}
168-
if let Some(pkg_id) = pkg_id {
169-
let mut matches = overrides.iter().filter_map(
170-
|(key, spec_profile)| match key {
171-
&ProfilePackageSpec::All => None,
172-
&ProfilePackageSpec::Spec(ref s) => if s.matches(pkg_id) {
173-
Some(spec_profile)
174-
} else {
175-
None
176-
},
177-
},
178-
);
179-
if let Some(spec_profile) = matches.next() {
180-
merge_profile(&mut profile, spec_profile);
181-
// `validate_packages` should ensure that there are
182-
// no additional matches.
183-
assert!(
184-
matches.next().is_none(),
185-
"package `{}` matched multiple profile overrides",
186-
pkg_id
187-
);
188-
}
189-
}
190-
}
173+
merge_toml(pkg_id, is_member, profile_for, &mut profile, toml);
174+
}
175+
if let Some(ref toml) = self.config {
176+
merge_toml(pkg_id, is_member, profile_for, &mut profile, toml);
191177
}
192178
profile
193179
}
194180

195181
fn validate_packages(&self, shell: &mut Shell, packages: &PackageSet) -> CargoResult<()> {
196-
let toml = match self.toml {
182+
self.validate_packages_toml(shell, packages, &self.toml, true)?;
183+
self.validate_packages_toml(shell, packages, &self.config, false)?;
184+
Ok(())
185+
}
186+
187+
fn validate_packages_toml(
188+
&self,
189+
shell: &mut Shell,
190+
packages: &PackageSet,
191+
toml: &Option<TomlProfile>,
192+
warn_unmatched: bool,
193+
) -> CargoResult<()> {
194+
let toml = match *toml {
197195
Some(ref toml) => toml,
198196
None => return Ok(()),
199197
};
@@ -206,9 +204,9 @@ impl ProfileMaker {
206204
for pkg_id in packages.package_ids() {
207205
let matches: Vec<&PackageIdSpec> = overrides
208206
.keys()
209-
.filter_map(|key| match key {
210-
&ProfilePackageSpec::All => None,
211-
&ProfilePackageSpec::Spec(ref spec) => if spec.matches(pkg_id) {
207+
.filter_map(|key| match *key {
208+
ProfilePackageSpec::All => None,
209+
ProfilePackageSpec::Spec(ref spec) => if spec.matches(pkg_id) {
212210
Some(spec)
213211
} else {
214212
None
@@ -237,9 +235,12 @@ impl ProfileMaker {
237235
}
238236
}
239237

238+
if !warn_unmatched {
239+
return Ok(());
240+
}
240241
// Verify every override matches at least one package.
241242
let missing_specs = overrides.keys().filter_map(|key| {
242-
if let &ProfilePackageSpec::Spec(ref spec) = key {
243+
if let ProfilePackageSpec::Spec(ref spec) = *key {
243244
if !found.contains(spec) {
244245
return Some(spec);
245246
}
@@ -258,7 +259,7 @@ impl ProfileMaker {
258259
}
259260
})
260261
.collect();
261-
if name_matches.len() == 0 {
262+
if name_matches.is_empty() {
262263
let suggestion = packages
263264
.package_ids()
264265
.map(|p| (lev_distance(spec.name(), &p.name()), p.name()))
@@ -289,6 +290,50 @@ impl ProfileMaker {
289290
}
290291
}
291292

293+
fn merge_toml(
294+
pkg_id: Option<&PackageId>,
295+
is_member: bool,
296+
profile_for: ProfileFor,
297+
profile: &mut Profile,
298+
toml: &TomlProfile,
299+
) {
300+
merge_profile(profile, toml);
301+
if profile_for == ProfileFor::CustomBuild {
302+
if let Some(ref build_override) = toml.build_override {
303+
merge_profile(profile, build_override);
304+
}
305+
}
306+
if let Some(ref overrides) = toml.overrides {
307+
if !is_member {
308+
if let Some(all) = overrides.get(&ProfilePackageSpec::All) {
309+
merge_profile(profile, all);
310+
}
311+
}
312+
if let Some(pkg_id) = pkg_id {
313+
let mut matches = overrides
314+
.iter()
315+
.filter_map(|(key, spec_profile)| match *key {
316+
ProfilePackageSpec::All => None,
317+
ProfilePackageSpec::Spec(ref s) => if s.matches(pkg_id) {
318+
Some(spec_profile)
319+
} else {
320+
None
321+
},
322+
});
323+
if let Some(spec_profile) = matches.next() {
324+
merge_profile(profile, spec_profile);
325+
// `validate_packages` should ensure that there are
326+
// no additional matches.
327+
assert!(
328+
matches.next().is_none(),
329+
"package `{}` matched multiple profile overrides",
330+
pkg_id
331+
);
332+
}
333+
}
334+
}
335+
}
336+
292337
fn merge_profile(profile: &mut Profile, toml: &TomlProfile) {
293338
if let Some(ref opt_level) = toml.opt_level {
294339
profile.opt_level = InternedString::new(&opt_level.0);
@@ -483,3 +528,26 @@ impl ProfileFor {
483528
&ALL
484529
}
485530
}
531+
532+
/// Profiles loaded from .cargo/config files.
533+
#[derive(Clone, Debug, Deserialize, Default)]
534+
pub struct ConfigProfiles {
535+
dev: Option<TomlProfile>,
536+
release: Option<TomlProfile>,
537+
}
538+
539+
impl ConfigProfiles {
540+
pub fn validate(&self, features: &Features, warnings: &mut Vec<String>) -> CargoResult<()> {
541+
if let Some(ref profile) = self.dev {
542+
profile
543+
.validate("dev", features, warnings)
544+
.chain_err(|| format_err!("config profile `profile.dev` is not valid"))?;
545+
}
546+
if let Some(ref profile) = self.release {
547+
profile
548+
.validate("release", features, warnings)
549+
.chain_err(|| format_err!("config profile `profile.release` is not valid"))?;
550+
}
551+
Ok(())
552+
}
553+
}

0 commit comments

Comments
 (0)