Consolidate build key configuration

Add a typed structure which lists all `build` key configuration
throughout Cargo.
This commit is contained in:
Alex Crichton 2019-09-27 14:19:48 -07:00
parent 09d9165d27
commit d7d8ca1e12
11 changed files with 115 additions and 55 deletions

View File

@ -62,15 +62,16 @@ impl BuildConfig {
requested_target: &Option<String>,
mode: CompileMode,
) -> CargoResult<BuildConfig> {
let cfg = config.build_config()?;
let requested_kind = match requested_target {
Some(s) => CompileKind::Target(CompileTarget::new(s)?),
None => match config.get_string("build.target")? {
Some(cfg) => {
let value = if cfg.val.ends_with(".json") {
let path = cfg.definition.root(config).join(&cfg.val);
None => match &cfg.target {
Some(val) => {
let value = if val.raw_value().ends_with(".json") {
let path = val.clone().resolve_path(config);
path.to_str().expect("must be utf-8 in toml").to_string()
} else {
cfg.val
val.raw_value().to_string()
};
CompileKind::Target(CompileTarget::new(&value)?)
}
@ -88,8 +89,7 @@ impl BuildConfig {
its environment, ignoring the `-j` parameter",
)?;
}
let cfg_jobs: Option<u32> = config.get("build.jobs")?;
let jobs = jobs.or(cfg_jobs).unwrap_or(::num_cpus::get() as u32);
let jobs = jobs.or(cfg.jobs).unwrap_or(::num_cpus::get() as u32);
Ok(BuildConfig {
requested_kind,

View File

@ -7,6 +7,7 @@ use std::str::{self, FromStr};
use crate::core::compiler::CompileKind;
use crate::core::TargetKind;
use crate::util::{CargoResult, CargoResultExt, Config, ProcessBuilder, Rustc};
use crate::util::config::StringList;
use cargo_platform::{Cfg, CfgExpr};
/// Information about the platform target gleaned from querying rustc.
@ -427,9 +428,8 @@ fn env_args(
CompileKind::Target(target) => target.short_name(),
};
let key = format!("target.{}.{}", target, name);
if let Some(args) = config.get_list_or_split_string(&key)? {
let args = args.val.into_iter();
rustflags.extend(args);
if let Some(args) = config.get::<Option<StringList>>(&key)? {
rustflags.extend(args.as_slice().iter().cloned());
}
// ...including target.'cfg(...)'.rustflags
if let Some(target_cfg) = target_cfg {
@ -450,9 +450,8 @@ fn env_args(
for n in cfgs {
let key = format!("target.{}.{}", n, name);
if let Some(args) = config.get_list_or_split_string(&key)? {
let args = args.val.into_iter();
rustflags.extend(args);
if let Some(args) = config.get::<Option<StringList>>(&key)? {
rustflags.extend(args.as_slice().iter().cloned());
}
}
}
@ -463,10 +462,14 @@ fn env_args(
}
// Then the `build.rustflags` value.
let key = format!("build.{}", name);
if let Some(args) = config.get_list_or_split_string(&key)? {
let args = args.val.into_iter();
return Ok(args.collect());
let build = config.build_config()?;
let list = if name == "rustflags" {
&build.rustflags
} else {
&build.rustdocflags
};
if let Some(list) = list {
return Ok(list.as_slice().to_vec())
}
Ok(Vec::new())

View File

@ -99,10 +99,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
}
};
let pipelining = bcx
.config
.get::<Option<bool>>("build.pipelining")?
.unwrap_or(true);
let pipelining = bcx.config.build_config()?.pipelining.unwrap_or(true);
Ok(Self {
bcx,

View File

@ -81,10 +81,10 @@ pub fn output_depinfo<'a, 'b>(cx: &mut Context<'a, 'b>, unit: &Unit<'a>) -> Carg
let mut visited = HashSet::new();
let success = add_deps_for_unit(&mut deps, cx, unit, &mut visited).is_ok();
let basedir_string;
let basedir = match bcx.config.get_path("build.dep-info-basedir")? {
let basedir = match bcx.config.build_config()?.dep_info_basedir.clone() {
Some(value) => {
basedir_string = value
.val
.resolve_path(bcx.config)
.as_os_str()
.to_str()
.ok_or_else(|| internal("build.dep-info-basedir path not utf-8"))?

View File

@ -38,7 +38,7 @@ impl Profiles {
let incremental = match env::var_os("CARGO_INCREMENTAL") {
Some(v) => Some(v == "1"),
None => config.get::<Option<bool>>("build.incremental")?,
None => config.build_config()?.incremental,
};
if !features.is_enabled(Feature::named_profiles()) {

View File

@ -420,7 +420,7 @@ pub fn configure_http_handle(config: &Config, handle: &mut Easy) -> CargoResult<
handle.proxy(&proxy)?;
}
if let Some(cainfo) = http.cainfo.clone() {
let cainfo = cainfo.resolve(config);
let cainfo = cainfo.resolve_path(config);
handle.cainfo(&cainfo)?;
}
if let Some(check) = http.check_revoke {

View File

@ -97,6 +97,7 @@ pub struct Config {
/// Cached configuration parsed by Cargo
http_config: LazyCell<CargoHttpConfig>,
net_config: LazyCell<CargoNetConfig>,
build_config: LazyCell<CargoBuildConfig>,
}
impl Config {
@ -157,6 +158,7 @@ impl Config {
package_cache_lock: RefCell::new(None),
http_config: LazyCell::new(),
net_config: LazyCell::new(),
build_config: LazyCell::new(),
}
}
@ -338,12 +340,12 @@ impl Config {
}
pub fn target_dir(&self) -> CargoResult<Option<Filesystem>> {
if let Some(ref dir) = self.target_dir {
if let Some(dir) = &self.target_dir {
Ok(Some(dir.clone()))
} else if let Some(dir) = env::var_os("CARGO_TARGET_DIR") {
Ok(Some(Filesystem::new(self.cwd.join(dir))))
} else if let Some(val) = self.get_path("build.target-dir")? {
let val = self.cwd.join(val.val);
} else if let Some(val) = &self.build_config()?.target_dir {
let val = val.resolve_path(self);
Ok(Some(Filesystem::new(val)))
} else {
Ok(None)
@ -469,7 +471,7 @@ impl Config {
pub fn get_path(&self, key: &str) -> CargoResult<OptValue<PathBuf>> {
self.get::<Option<Value<ConfigRelativePath>>>(key).map(|v| {
v.map(|v| Value {
val: v.val.resolve(self),
val: v.val.resolve_program(self),
definition: v.definition,
})
})
@ -513,27 +515,13 @@ impl Config {
}
}
pub fn get_list_or_split_string(&self, key: &str) -> CargoResult<OptValue<Vec<String>>> {
#[derive(Deserialize)]
#[serde(untagged)]
enum Target {
String(String),
List(Vec<String>),
}
match self.get::<Option<Value<Target>>>(key)? {
fn get_list_or_split_string(&self, key: &str) -> CargoResult<OptValue<Vec<String>>> {
match self.get::<Option<Value<StringList>>>(key)? {
None => Ok(None),
Some(Value {
val: Target::String(s),
definition,
}) => Ok(Some(Value {
val: s.split(' ').map(str::to_string).collect(),
definition,
Some(val) => Ok(Some(Value {
val: val.val.list,
definition: val.definition,
})),
Some(Value {
val: Target::List(val),
definition,
}) => Ok(Some(Value { val, definition })),
}
}
@ -927,6 +915,11 @@ impl Config {
.try_borrow_with(|| Ok(self.get::<CargoNetConfig>("net")?))
}
pub fn build_config(&self) -> CargoResult<&CargoBuildConfig> {
self.build_config
.try_borrow_with(|| Ok(self.get::<CargoBuildConfig>("build")?))
}
pub fn crates_io_source_id<F>(&self, f: F) -> CargoResult<SourceId>
where
F: FnMut() -> CargoResult<SourceId>,
@ -1463,3 +1456,46 @@ pub struct CargoNetConfig {
#[serde(rename = "git-fetch-with-cli")]
pub git_fetch_with_cli: Option<bool>,
}
#[derive(Debug, Deserialize)]
pub struct CargoBuildConfig {
pub pipelining: Option<bool>,
#[serde(rename = "dep-info-basedir")]
pub dep_info_basedir: Option<ConfigRelativePath>,
#[serde(rename = "target-dir")]
pub target_dir: Option<ConfigRelativePath>,
pub incremental: Option<bool>,
pub target: Option<ConfigRelativePath>,
pub jobs: Option<u32>,
pub rustflags: Option<StringList>,
pub rustdocflags: Option<StringList>,
}
#[derive(Debug)]
pub struct StringList {
list: Vec<String>,
}
impl StringList {
pub fn as_slice(&self) -> &[String] {
&self.list
}
}
impl<'de> serde::de::Deserialize<'de> for StringList {
fn deserialize<D: serde::de::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
#[derive(Deserialize)]
#[serde(untagged)]
enum Target {
String(String),
List(Vec<String>),
}
Ok(match Target::deserialize(d)? {
Target::String(s) => StringList {
list: s.split_whitespace().map(str::to_string).collect(),
},
Target::List(list) => StringList { list },
})
}
}

View File

@ -10,7 +10,26 @@ use std::path::PathBuf;
pub struct ConfigRelativePath(Value<String>);
impl ConfigRelativePath {
pub fn resolve(self, config: &Config) -> PathBuf {
/// Returns the raw underlying configuration value for this key.
pub fn raw_value(&self) -> &str {
&self.0.val
}
/// Resolves this configuration-relative path to an absolute path.
///
/// This will always return an absolute path where it's relative to the
/// location for configuration for this value.
pub fn resolve_path(&self, config: &Config) -> PathBuf {
self.0.definition.root(config).join(&self.0.val)
}
/// Resolves this configuration-relative path to either an absolute path or
/// something appropriate to execute from `PATH`.
///
/// Values which don't look like a filesystem path (don't contain `/` or
/// `\`) will be returned as-is, and everything else will fall through to an
/// absolute path.
pub fn resolve_program(self, config: &Config) -> PathBuf {
config.string_to_path(self.0.val, &self.0.definition)
}
}

View File

@ -394,5 +394,5 @@ pub fn display_causes(error: &Error) -> String {
.iter_chain()
.map(|e| e.to_string())
.collect::<Vec<_>>()
.join("\nCaused by:\n ")
.join("\n\nCaused by:\n ")
}

View File

@ -560,10 +560,13 @@ fn config_bad_toml() {
config.get::<i32>("foo").unwrap_err(),
"\
could not load Cargo configuration
Caused by:
could not parse TOML configuration in `[..]/.cargo/config`
Caused by:
could not parse input as TOML
Caused by:
expected an equals, found eof at line 1 column 5",
);
@ -735,35 +738,35 @@ abs = '{}'
config
.get::<config::ConfigRelativePath>("p1")
.unwrap()
.resolve(&config),
.resolve_path(&config),
paths::root().join("foo/bar")
);
assert_eq!(
config
.get::<config::ConfigRelativePath>("p2")
.unwrap()
.resolve(&config),
.resolve_path(&config),
paths::root().join("../abc")
);
assert_eq!(
config
.get::<config::ConfigRelativePath>("p3")
.unwrap()
.resolve(&config),
.resolve_path(&config),
paths::root().join("d/e")
);
assert_eq!(
config
.get::<config::ConfigRelativePath>("abs")
.unwrap()
.resolve(&config),
.resolve_path(&config),
paths::home()
);
assert_eq!(
config
.get::<config::ConfigRelativePath>("epath")
.unwrap()
.resolve(&config),
.resolve_path(&config),
paths::root().join("a/b")
);
}

View File

@ -1061,8 +1061,10 @@ fn new_warning_with_corrupt_ws() {
[WARNING] compiling this new crate may not work due to invalid workspace configuration
failed to parse manifest at `[..]foo/Cargo.toml`
Caused by:
could not parse input as TOML
Caused by:
expected an equals, found eof at line 1 column 5
Created binary (application) `bar` package