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

View File

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

View File

@ -99,10 +99,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
} }
}; };
let pipelining = bcx let pipelining = bcx.config.build_config()?.pipelining.unwrap_or(true);
.config
.get::<Option<bool>>("build.pipelining")?
.unwrap_or(true);
Ok(Self { Ok(Self {
bcx, 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 mut visited = HashSet::new();
let success = add_deps_for_unit(&mut deps, cx, unit, &mut visited).is_ok(); let success = add_deps_for_unit(&mut deps, cx, unit, &mut visited).is_ok();
let basedir_string; 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) => { Some(value) => {
basedir_string = value basedir_string = value
.val .resolve_path(bcx.config)
.as_os_str() .as_os_str()
.to_str() .to_str()
.ok_or_else(|| internal("build.dep-info-basedir path not utf-8"))? .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") { let incremental = match env::var_os("CARGO_INCREMENTAL") {
Some(v) => Some(v == "1"), Some(v) => Some(v == "1"),
None => config.get::<Option<bool>>("build.incremental")?, None => config.build_config()?.incremental,
}; };
if !features.is_enabled(Feature::named_profiles()) { 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)?; handle.proxy(&proxy)?;
} }
if let Some(cainfo) = http.cainfo.clone() { if let Some(cainfo) = http.cainfo.clone() {
let cainfo = cainfo.resolve(config); let cainfo = cainfo.resolve_path(config);
handle.cainfo(&cainfo)?; handle.cainfo(&cainfo)?;
} }
if let Some(check) = http.check_revoke { if let Some(check) = http.check_revoke {

View File

@ -97,6 +97,7 @@ pub struct Config {
/// Cached configuration parsed by Cargo /// Cached configuration parsed by Cargo
http_config: LazyCell<CargoHttpConfig>, http_config: LazyCell<CargoHttpConfig>,
net_config: LazyCell<CargoNetConfig>, net_config: LazyCell<CargoNetConfig>,
build_config: LazyCell<CargoBuildConfig>,
} }
impl Config { impl Config {
@ -157,6 +158,7 @@ impl Config {
package_cache_lock: RefCell::new(None), package_cache_lock: RefCell::new(None),
http_config: LazyCell::new(), http_config: LazyCell::new(),
net_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>> { 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())) Ok(Some(dir.clone()))
} else if let Some(dir) = env::var_os("CARGO_TARGET_DIR") { } else if let Some(dir) = env::var_os("CARGO_TARGET_DIR") {
Ok(Some(Filesystem::new(self.cwd.join(dir)))) Ok(Some(Filesystem::new(self.cwd.join(dir))))
} else if let Some(val) = self.get_path("build.target-dir")? { } else if let Some(val) = &self.build_config()?.target_dir {
let val = self.cwd.join(val.val); let val = val.resolve_path(self);
Ok(Some(Filesystem::new(val))) Ok(Some(Filesystem::new(val)))
} else { } else {
Ok(None) Ok(None)
@ -469,7 +471,7 @@ impl Config {
pub fn get_path(&self, key: &str) -> CargoResult<OptValue<PathBuf>> { pub fn get_path(&self, key: &str) -> CargoResult<OptValue<PathBuf>> {
self.get::<Option<Value<ConfigRelativePath>>>(key).map(|v| { self.get::<Option<Value<ConfigRelativePath>>>(key).map(|v| {
v.map(|v| Value { v.map(|v| Value {
val: v.val.resolve(self), val: v.val.resolve_program(self),
definition: v.definition, definition: v.definition,
}) })
}) })
@ -513,27 +515,13 @@ impl Config {
} }
} }
pub fn get_list_or_split_string(&self, key: &str) -> CargoResult<OptValue<Vec<String>>> { fn get_list_or_split_string(&self, key: &str) -> CargoResult<OptValue<Vec<String>>> {
#[derive(Deserialize)] match self.get::<Option<Value<StringList>>>(key)? {
#[serde(untagged)]
enum Target {
String(String),
List(Vec<String>),
}
match self.get::<Option<Value<Target>>>(key)? {
None => Ok(None), None => Ok(None),
Some(Value { Some(val) => Ok(Some(Value {
val: Target::String(s), val: val.val.list,
definition, definition: val.definition,
}) => Ok(Some(Value {
val: s.split(' ').map(str::to_string).collect(),
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")?)) .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> pub fn crates_io_source_id<F>(&self, f: F) -> CargoResult<SourceId>
where where
F: FnMut() -> CargoResult<SourceId>, F: FnMut() -> CargoResult<SourceId>,
@ -1463,3 +1456,46 @@ pub struct CargoNetConfig {
#[serde(rename = "git-fetch-with-cli")] #[serde(rename = "git-fetch-with-cli")]
pub git_fetch_with_cli: Option<bool>, 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>); pub struct ConfigRelativePath(Value<String>);
impl ConfigRelativePath { 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) 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() .iter_chain()
.map(|e| e.to_string()) .map(|e| e.to_string())
.collect::<Vec<_>>() .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(), config.get::<i32>("foo").unwrap_err(),
"\ "\
could not load Cargo configuration could not load Cargo configuration
Caused by: Caused by:
could not parse TOML configuration in `[..]/.cargo/config` could not parse TOML configuration in `[..]/.cargo/config`
Caused by: Caused by:
could not parse input as TOML could not parse input as TOML
Caused by: Caused by:
expected an equals, found eof at line 1 column 5", expected an equals, found eof at line 1 column 5",
); );
@ -735,35 +738,35 @@ abs = '{}'
config config
.get::<config::ConfigRelativePath>("p1") .get::<config::ConfigRelativePath>("p1")
.unwrap() .unwrap()
.resolve(&config), .resolve_path(&config),
paths::root().join("foo/bar") paths::root().join("foo/bar")
); );
assert_eq!( assert_eq!(
config config
.get::<config::ConfigRelativePath>("p2") .get::<config::ConfigRelativePath>("p2")
.unwrap() .unwrap()
.resolve(&config), .resolve_path(&config),
paths::root().join("../abc") paths::root().join("../abc")
); );
assert_eq!( assert_eq!(
config config
.get::<config::ConfigRelativePath>("p3") .get::<config::ConfigRelativePath>("p3")
.unwrap() .unwrap()
.resolve(&config), .resolve_path(&config),
paths::root().join("d/e") paths::root().join("d/e")
); );
assert_eq!( assert_eq!(
config config
.get::<config::ConfigRelativePath>("abs") .get::<config::ConfigRelativePath>("abs")
.unwrap() .unwrap()
.resolve(&config), .resolve_path(&config),
paths::home() paths::home()
); );
assert_eq!( assert_eq!(
config config
.get::<config::ConfigRelativePath>("epath") .get::<config::ConfigRelativePath>("epath")
.unwrap() .unwrap()
.resolve(&config), .resolve_path(&config),
paths::root().join("a/b") 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 [WARNING] compiling this new crate may not work due to invalid workspace configuration
failed to parse manifest at `[..]foo/Cargo.toml` failed to parse manifest at `[..]foo/Cargo.toml`
Caused by: Caused by:
could not parse input as TOML could not parse input as TOML
Caused by: Caused by:
expected an equals, found eof at line 1 column 5 expected an equals, found eof at line 1 column 5
Created binary (application) `bar` package Created binary (application) `bar` package