Skip to content

Commit

Permalink
Use new config API.
Browse files Browse the repository at this point in the history
Also, require "override" feature if used in a config.
  • Loading branch information
ehuss committed May 31, 2018
1 parent 2f7b522 commit 84a80d8
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 188 deletions.
116 changes: 31 additions & 85 deletions src/cargo/core/profiles.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::collections::{HashMap, HashSet};
use std::sync::atomic;
use std::collections::HashSet;
use std::{cmp, fmt, hash};

use core::compiler::CompileMode;
use core::interning::InternedString;
use core::{Features, PackageId, PackageIdSpec, PackageSet, Shell};
use util::errors::CargoResultExt;
use util::lev_distance::lev_distance;
use util::toml::{ProfilePackageSpec, StringOrBool, TomlProfile, TomlProfiles, U32OrBool};
use util::{CargoResult, Config, ConfigValue};
use util::{CargoResult, Config};

/// Collection of all user profiles.
#[derive(Clone, Debug)]
Expand All @@ -29,18 +29,20 @@ impl Profiles {
if let Some(profiles) = profiles {
profiles.validate(features, warnings)?;
}
Profiles::validate_config(config, warnings)?;

let config_profiles = config.profiles()?;
config_profiles.validate(features, warnings)?;

Ok(Profiles {
dev: ProfileMaker {
default: Profile::default_dev(),
toml: profiles.and_then(|p| p.dev.clone()),
config: TomlProfile::from_config(config, "dev", warnings)?,
config: config_profiles.dev.clone(),
},
release: ProfileMaker {
default: Profile::default_release(),
toml: profiles.and_then(|p| p.release.clone()),
config: TomlProfile::from_config(config, "release", warnings)?,
config: config_profiles.release.clone(),
},
test: ProfileMaker {
default: Profile::default_test(),
Expand Down Expand Up @@ -137,71 +139,6 @@ impl Profiles {
self.doc.validate_packages(shell, packages)?;
Ok(())
}

fn validate_config(config: &Config, warnings: &mut Vec<String>) -> CargoResult<()> {
static VALIDATE_ONCE: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;

if VALIDATE_ONCE.swap(true, atomic::Ordering::SeqCst) {
return Ok(());
}

// cv: Value<HashMap<String, CV>>
if let Some(cv) = config.get_table("profile")? {
// Warn if config profiles without CLI option.
if !config.cli_unstable().config_profile {
warnings.push(format!(
"profile in config `{}` requires `-Z config-profile` command-line option",
cv.definition
));
// Ignore the rest.
return Ok(());
}
// Warn about unsupported profile names.
for (key, profile_cv) in cv.val.iter() {
if key != "dev" && key != "release" {
warnings.push(format!(
"profile `{}` in config `{}` is not supported",
key,
profile_cv.definition_path().display()
));
}
}
// Warn about incorrect key names.
for profile_cv in cv.val.values() {
if let ConfigValue::Table(ref profile, _) = *profile_cv {
validate_profile_keys(profile, warnings);
if let Some(&ConfigValue::Table(ref bo_profile, _)) =
profile.get("build-override")
{
validate_profile_keys(bo_profile, warnings);
}
if let Some(&ConfigValue::Table(ref os, _)) = profile.get("overrides") {
for o_profile_cv in os.values() {
if let ConfigValue::Table(ref o_profile, _) = *o_profile_cv {
validate_profile_keys(o_profile, warnings);
}
}
}
}
}
}
return Ok(());

fn validate_profile_keys(
profile: &HashMap<String, ConfigValue>,
warnings: &mut Vec<String>,
) {
for (key, value_cv) in profile.iter() {
if !TOML_PROFILE_KEYS.iter().any(|k| k == key) {
warnings.push(format!(
"unused profile key `{}` in config `{}`",
key,
value_cv.definition_path().display()
));
}
}
}
}
}

/// An object used for handling the profile override hierarchy.
Expand Down Expand Up @@ -449,20 +386,6 @@ pub struct Profile {
pub panic: Option<InternedString>,
}

const TOML_PROFILE_KEYS: [&str; 11] = [
"opt-level",
"lto",
"codegen-units",
"debug",
"debug-assertions",
"rpath",
"panic",
"overflow-checks",
"incremental",
"overrides",
"build-override",
];

impl Default for Profile {
fn default() -> Profile {
Profile {
Expand Down Expand Up @@ -605,3 +528,26 @@ impl ProfileFor {
&ALL
}
}

/// Profiles loaded from .cargo/config files.
#[derive(Clone, Debug, Deserialize, Default)]
pub struct ConfigProfiles {
dev: Option<TomlProfile>,
release: Option<TomlProfile>,
}

impl ConfigProfiles {
pub fn validate(&self, features: &Features, warnings: &mut Vec<String>) -> CargoResult<()> {
if let Some(ref profile) = self.dev {
profile
.validate("dev", features, warnings)
.chain_err(|| format_err!("config profile `profile.dev` is not valid"))?;
}
if let Some(ref profile) = self.release {
profile
.validate("release", features, warnings)
.chain_err(|| format_err!("config profile `profile.release` is not valid"))?;
}
Ok(())
}
}
26 changes: 25 additions & 1 deletion src/cargo/util/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use lazycell::LazyCell;
use serde::{de, de::IntoDeserializer, Serialize, Serializer};
use toml;

use core::profiles::ConfigProfiles;
use core::shell::Verbosity;
use core::{CliUnstable, Shell, SourceId, Workspace};
use ops;
Expand Down Expand Up @@ -77,6 +78,8 @@ pub struct Config {
target_dir: Option<Filesystem>,
/// Environment variables, separated to assist testing.
env: HashMap<String, String>,
/// Profiles loaded from config.
profiles: LazyCell<ConfigProfiles>,
}

impl Config {
Expand Down Expand Up @@ -132,6 +135,7 @@ impl Config {
creation_time: Instant::now(),
target_dir: None,
env,
profiles: LazyCell::new(),
}
}

Expand Down Expand Up @@ -246,6 +250,25 @@ impl Config {
.map(AsRef::as_ref)
}

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

pub fn values(&self) -> CargoResult<&HashMap<String, ConfigValue>> {
self.values.try_borrow_with(|| self.load_values())
}
Expand Down Expand Up @@ -1380,7 +1403,7 @@ impl ConfigValue {
}
}

pub fn into_toml(self) -> toml::Value {
fn into_toml(self) -> toml::Value {
match self {
CV::Boolean(s, _) => toml::Value::Boolean(s),
CV::String(s, _) => toml::Value::String(s),
Expand Down Expand Up @@ -1425,6 +1448,7 @@ impl ConfigValue {
};
}
}
// Allow switching types except for tables or arrays.
(expected @ &mut CV::List(_, _), found)
| (expected @ &mut CV::Table(_, _), found)
| (expected, found @ CV::List(_, _))
Expand Down
72 changes: 9 additions & 63 deletions src/cargo/util/toml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::str;

use failure::Error;
use semver::{self, VersionReq};
use serde::de::{self, Deserialize};
use serde::ser;
Expand All @@ -22,7 +21,7 @@ use core::{GitReference, PackageIdSpec, SourceId, WorkspaceConfig, WorkspaceRoot
use sources::CRATES_IO;
use util::errors::{CargoError, CargoResult, CargoResultExt};
use util::paths;
use util::{self, Config, ConfigValue, ToUrl};
use util::{self, Config, ToUrl};

mod targets;
use self::targets::targets;
Expand Down Expand Up @@ -248,19 +247,19 @@ pub struct TomlProfiles {
impl TomlProfiles {
pub fn validate(&self, features: &Features, warnings: &mut Vec<String>) -> CargoResult<()> {
if let Some(ref test) = self.test {
test.validate("test", Some(features), warnings)?;
test.validate("test", features, warnings)?;
}
if let Some(ref doc) = self.doc {
doc.validate("doc", Some(features), warnings)?;
doc.validate("doc", features, warnings)?;
}
if let Some(ref bench) = self.bench {
bench.validate("bench", Some(features), warnings)?;
bench.validate("bench", features, warnings)?;
}
if let Some(ref dev) = self.dev {
dev.validate("dev", Some(features), warnings)?;
dev.validate("dev", features, warnings)?;
}
if let Some(ref release) = self.release {
release.validate("release", Some(features), warnings)?;
release.validate("release", features, warnings)?;
}
Ok(())
}
Expand Down Expand Up @@ -420,71 +419,18 @@ impl<'de> de::Deserialize<'de> for ProfilePackageSpec {
}

impl TomlProfile {
pub fn from_config(
config: &Config,
name: &str,
warnings: &mut Vec<String>,
) -> CargoResult<Option<TomlProfile>> {
if !config.cli_unstable().config_profile {
return Ok(None);
}
if let Some(util::config::Value { val, .. }) =
config.get_table(&format!("profile.{}", name))?
{
let cv = ConfigValue::Table(val.clone(), PathBuf::new());
let toml = cv.into_toml();
let profile: TomlProfile =
Deserialize::deserialize(toml).chain_err(|| error_path(&val))?;
profile
.validate(name, None, warnings)
.chain_err(|| error_path(&val))?;
return Ok(Some(profile));
}
return Ok(None);

fn error_path(table: &HashMap<String, ConfigValue>) -> Error {
let mut paths = HashSet::new();
error_path_rec(table, &mut paths);
if paths.len() == 1 {
format_err!(
"error in config profile `{}`",
paths.into_iter().next().unwrap()
)
} else {
let mut ps = paths.into_iter().collect::<Vec<_>>();
ps.sort(); // to help with testing
format_err!(
"error in config profile, possible locations: {}",
ps.join(", ")
)
}
}
fn error_path_rec(table: &HashMap<String, ConfigValue>, paths: &mut HashSet<String>) {
for cv in table.values() {
paths.insert(cv.definition_path().display().to_string());
if let &ConfigValue::Table(ref t, _) = cv {
error_path_rec(t, paths);
}
}
}
}

pub fn validate(
&self,
name: &str,
features: Option<&Features>,
features: &Features,
warnings: &mut Vec<String>,
) -> CargoResult<()> {
if let Some(ref profile) = self.build_override {
if let Some(features) = features {
features.require(Feature::profile_overrides())?;
}
features.require(Feature::profile_overrides())?;
profile.validate_override()?;
}
if let Some(ref override_map) = self.overrides {
if let Some(features) = features {
features.require(Feature::profile_overrides())?;
}
features.require(Feature::profile_overrides())?;
for profile in override_map.values() {
profile.validate_override()?;
}
Expand Down
Loading

0 comments on commit 84a80d8

Please sign in to comment.