use std::io::prelude::*;
use std::mem;
use std::path::{Path, PathBuf};
+use std::str::FromStr;
use rustc_serialize::{Encodable,Encoder};
use toml;
use core::shell::{Verbosity, ColorConfig};
use core::{MultiShell, Package};
-use util::{CargoResult, ChainError, Rustc, internal, human, paths};
+use util::{CargoResult, CargoError, ChainError, Rustc, internal, human, paths};
use util::toml as cargo_toml;
Ok(Some(val.clone()))
}
+ fn get_env<V: FromStr>(&self, key: &str) -> CargoResult<Option<Value<V>>>
+ where Box<CargoError>: From<V::Err>
+ {
+ let key = key.replace(".", "_")
+ .replace("-", "_")
+ .chars()
+ .flat_map(|c| c.to_uppercase())
+ .collect::<String>();
+ match env::var(&format!("CARGO_{}", key)) {
+ Ok(value) => {
+ Ok(Some(Value {
+ val: try!(value.parse()),
+ definition: Definition::Environment,
+ }))
+ }
+ Err(..) => Ok(None),
+ }
+ }
+
pub fn get_string(&self, key: &str) -> CargoResult<Option<Value<String>>> {
+ if let Some(v) = try!(self.get_env(key)) {
+ return Ok(Some(v))
+ }
match try!(self.get(key)) {
Some(CV::String(i, path)) => {
Ok(Some(Value {
}
pub fn get_i64(&self, key: &str) -> CargoResult<Option<Value<i64>>> {
+ if let Some(v) = try!(self.get_env(key)) {
+ return Ok(Some(v))
+ }
match try!(self.get(key)) {
Some(CV::Integer(i, path)) => {
Ok(Some(Value {
pub enum Definition {
Path(PathBuf),
+ Environment,
}
impl fmt::Debug for ConfigValue {
}
impl Definition {
- pub fn root<'a>(&'a self, _config: &'a Config) -> &'a Path {
+ pub fn root<'a>(&'a self, config: &'a Config) -> &'a Path {
match *self {
Definition::Path(ref p) => p.parent().unwrap().parent().unwrap(),
+ Definition::Environment => config.cwd(),
}
}
}
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Definition::Path(ref p) => p.display().fmt(f),
+ Definition::Environment => "the environment".fmt(f),
}
}
}
use std::ffi;
use std::fmt;
use std::io;
+use std::num;
use std::process::{Output, ExitStatus};
use std::str;
+use std::string;
use curl;
use git2;
toml::DecodeError,
ffi::NulError,
term::Error,
+ num::ParseIntError,
+}
+
+impl From<string::ParseError> for Box<CargoError> {
+ fn from(t: string::ParseError) -> Box<CargoError> {
+ match t {}
+ }
}
impl<E: CargoError> From<Human<E>> for Box<CargoError> {
impl CargoError for url::ParseError {}
impl CargoError for ffi::NulError {}
impl CargoError for term::Error {}
+impl CargoError for num::ParseIntError {}
// =============================================================================
// Construction helpers
# Environment Variables
-Cargo recognizes a few global [environment variables][env] to configure itself.
-Settings specified via config files take precedence over those specified via
+Cargo can also be configured through environment variables in addition to the
+TOML syntax above. For each configuration key above of the form `foo.bar` the
+environment variable `CARGO_FOO_BAR` can also be used to define the value. For
+example the `build.jobs` key can also be defined by `CARGO_BUILD_JOBS`.
+
+Environment variables will take precedent over TOML configuration, and currently
+only integer, boolean, and string keys are supported to be defined by
environment variables.
+In addition to the system above, Cargo recognizes a few other specific
+[environment variables][env].
+
[env]: environment-variables.html
--- /dev/null
+use support::{project, execs};
+use hamcrest::assert_that;
+
+fn setup() {
+}
+
+test!(read_env_vars_for_config {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [package]
+ name = "foo"
+ authors = []
+ version = "0.0.0"
+ build = "build.rs"
+ "#)
+ .file("src/lib.rs", "")
+ .file("build.rs", r#"
+ use std::env;
+ fn main() {
+ assert_eq!(env::var("NUM_JOBS").unwrap(), "100");
+ }
+ "#);
+
+ assert_that(p.cargo_process("build").env("CARGO_BUILD_JOBS", "100"),
+ execs().with_status(0));
+});