mirror of https://github.com/rwf2/Rocket.git
Add the [global] psuedo-environment for global configuration.
This commit is contained in:
parent
da7cb44671
commit
d91e3e0454
|
@ -1,8 +1,2 @@
|
||||||
[dev]
|
[global]
|
||||||
template_dir = "static"
|
|
||||||
|
|
||||||
[stage]
|
|
||||||
template_dir = "static"
|
|
||||||
|
|
||||||
[prod]
|
|
||||||
template_dir = "static"
|
template_dir = "static"
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub struct Config {
|
||||||
/// The environment that this configuration corresponds to.
|
/// The environment that this configuration corresponds to.
|
||||||
pub env: Environment,
|
pub env: Environment,
|
||||||
session_key: RwLock<Option<String>>,
|
session_key: RwLock<Option<String>>,
|
||||||
extra: HashMap<String, Value>,
|
extras: HashMap<String, Value>,
|
||||||
filename: String,
|
filename: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ impl Config {
|
||||||
port: 8000,
|
port: 8000,
|
||||||
log_level: LoggingLevel::Normal,
|
log_level: LoggingLevel::Normal,
|
||||||
session_key: RwLock::new(None),
|
session_key: RwLock::new(None),
|
||||||
extra: HashMap::new(),
|
extras: HashMap::new(),
|
||||||
env: env,
|
env: env,
|
||||||
filename: filename.to_string(),
|
filename: filename.to_string(),
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ impl Config {
|
||||||
port: 80,
|
port: 80,
|
||||||
log_level: LoggingLevel::Normal,
|
log_level: LoggingLevel::Normal,
|
||||||
session_key: RwLock::new(None),
|
session_key: RwLock::new(None),
|
||||||
extra: HashMap::new(),
|
extras: HashMap::new(),
|
||||||
env: env,
|
env: env,
|
||||||
filename: filename.to_string(),
|
filename: filename.to_string(),
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ impl Config {
|
||||||
port: 80,
|
port: 80,
|
||||||
log_level: LoggingLevel::Critical,
|
log_level: LoggingLevel::Critical,
|
||||||
session_key: RwLock::new(None),
|
session_key: RwLock::new(None),
|
||||||
extra: HashMap::new(),
|
extras: HashMap::new(),
|
||||||
env: env,
|
env: env,
|
||||||
filename: filename.to_string(),
|
filename: filename.to_string(),
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ impl Config {
|
||||||
"log level ('normal', 'critical', 'debug')"))
|
"log level ('normal', 'critical', 'debug')"))
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
self.extra.insert(name.into(), val.clone());
|
self.extras.insert(name.into(), val.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -130,26 +130,26 @@ impl Config {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn extras<'a>(&'a self) -> impl Iterator<Item=(&'a String, &'a Value)> {
|
pub fn extras<'a>(&'a self) -> impl Iterator<Item=(&'a String, &'a Value)> {
|
||||||
self.extra.iter()
|
self.extras.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_str<'a>(&'a self, name: &str) -> config::Result<&'a str> {
|
pub fn get_str<'a>(&'a self, name: &str) -> config::Result<&'a str> {
|
||||||
let value = self.extra.get(name).ok_or_else(|| ConfigError::NotFound)?;
|
let value = self.extras.get(name).ok_or_else(|| ConfigError::NotFound)?;
|
||||||
parse!(self, name, value, as_str, "a string")
|
parse!(self, name, value, as_str, "a string")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_int<'a>(&'a self, name: &str) -> config::Result<i64> {
|
pub fn get_int<'a>(&'a self, name: &str) -> config::Result<i64> {
|
||||||
let value = self.extra.get(name).ok_or_else(|| ConfigError::NotFound)?;
|
let value = self.extras.get(name).ok_or_else(|| ConfigError::NotFound)?;
|
||||||
parse!(self, name, value, as_integer, "an integer")
|
parse!(self, name, value, as_integer, "an integer")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_bool<'a>(&'a self, name: &str) -> config::Result<bool> {
|
pub fn get_bool<'a>(&'a self, name: &str) -> config::Result<bool> {
|
||||||
let value = self.extra.get(name).ok_or_else(|| ConfigError::NotFound)?;
|
let value = self.extras.get(name).ok_or_else(|| ConfigError::NotFound)?;
|
||||||
parse!(self, name, value, as_bool, "a boolean")
|
parse!(self, name, value, as_bool, "a boolean")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_float<'a>(&'a self, name: &str) -> config::Result<f64> {
|
pub fn get_float<'a>(&'a self, name: &str) -> config::Result<f64> {
|
||||||
let value = self.extra.get(name).ok_or_else(|| ConfigError::NotFound)?;
|
let value = self.extras.get(name).ok_or_else(|| ConfigError::NotFound)?;
|
||||||
parse!(self, name, value, as_float, "a float")
|
parse!(self, name, value, as_float, "a float")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,6 +191,12 @@ impl Config {
|
||||||
self.env = var;
|
self.env = var;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn extra(mut self, name: &str, value: &Value) -> Self {
|
||||||
|
self.extras.insert(name.into(), value.clone());
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Config {
|
impl fmt::Debug for Config {
|
||||||
|
@ -207,7 +213,7 @@ impl PartialEq for Config {
|
||||||
&& self.port == other.port
|
&& self.port == other.port
|
||||||
&& self.log_level == other.log_level
|
&& self.log_level == other.log_level
|
||||||
&& self.env == other.env
|
&& self.env == other.env
|
||||||
&& self.extra == other.extra
|
&& self.extras == other.extras
|
||||||
&& self.filename == other.filename
|
&& self.filename == other.filename
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,12 @@ impl Environment {
|
||||||
pub fn valid() -> &'static str {
|
pub fn valid() -> &'static str {
|
||||||
"development, staging, production"
|
"development, staging, production"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a list of all of the possible environments.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn all() -> [Environment; 3] {
|
||||||
|
[Development, Staging, Production]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Environment {
|
impl FromStr for Environment {
|
||||||
|
|
|
@ -58,9 +58,10 @@ impl ConfigError {
|
||||||
info_!("{}", reason);
|
info_!("{}", reason);
|
||||||
}
|
}
|
||||||
BadEntry(ref name, ref filename) => {
|
BadEntry(ref name, ref filename) => {
|
||||||
|
let valid_entries = format!("{}, and global", valid_envs);
|
||||||
error!("[{}] is not a known configuration environment", name);
|
error!("[{}] is not a known configuration environment", name);
|
||||||
info_!("in {}", White.paint(filename));
|
info_!("in {}", White.paint(filename));
|
||||||
info_!("valid environments are: {}", White.paint(valid_envs));
|
info_!("valid environments are: {}", White.paint(valid_entries));
|
||||||
}
|
}
|
||||||
BadEnv(ref name) => {
|
BadEnv(ref name) => {
|
||||||
error!("'{}' is not a valid ROCKET_ENV value", name);
|
error!("'{}' is not a valid ROCKET_ENV value", name);
|
||||||
|
|
|
@ -47,11 +47,12 @@
|
||||||
//! each environment. The file is optional. If it is not present, the default
|
//! each environment. The file is optional. If it is not present, the default
|
||||||
//! configuration parameters are used.
|
//! configuration parameters are used.
|
||||||
//!
|
//!
|
||||||
//! The file must be a series of tables, one for each environment, where each
|
//! The file must be a series of tables, at most one for each environment and a
|
||||||
//! table contains key-value pairs corresponding to configuration parameters for
|
//! "global" table, where each table contains key-value pairs corresponding to
|
||||||
//! that environment. If a configuration parameter is missing, the default value
|
//! configuration parameters for that environment. If a configuration parameter
|
||||||
//! is used. The following is a complete `Rocket.toml` file, where every
|
//! is missing, the default value is used. The following is a complete
|
||||||
//! standard configuration parameter is specified with the default value:
|
//! `Rocket.toml` file, where every standard configuration parameter is
|
||||||
|
//! specified with the default value:
|
||||||
//!
|
//!
|
||||||
//! ```toml
|
//! ```toml
|
||||||
//! [development]
|
//! [development]
|
||||||
|
@ -74,6 +75,23 @@
|
||||||
//! session_key = "adL5fFIPmZBrlyHk2YT4NLV3YCk2gFXz"
|
//! session_key = "adL5fFIPmZBrlyHk2YT4NLV3YCk2gFXz"
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
//! The "global" pseudo-environment can be used to set and/or override
|
||||||
|
//! configuration parameters globally. A parameter defined in a `[global]` table
|
||||||
|
//! sets, or overrides if already present, that parameter in every environment.
|
||||||
|
//! For example, given the following `Rocket.toml` file, the value of `address`
|
||||||
|
//! will be `"1.2.3.4"` in every environment:
|
||||||
|
//!
|
||||||
|
//! ```toml
|
||||||
|
//! [global]
|
||||||
|
//! address = "1.2.3.4"
|
||||||
|
//!
|
||||||
|
//! [devolopment]
|
||||||
|
//! address = "localhost"
|
||||||
|
//!
|
||||||
|
//! [production]
|
||||||
|
//! address = "0.0.0.0"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
//! ## Retrieving Configuration Parameters
|
//! ## Retrieving Configuration Parameters
|
||||||
//!
|
//!
|
||||||
//! Configuration parameters for the currently active configuration environment
|
//! Configuration parameters for the currently active configuration environment
|
||||||
|
@ -127,6 +145,8 @@ static mut CONFIG: Option<RocketConfig> = None;
|
||||||
|
|
||||||
const CONFIG_FILENAME: &'static str = "Rocket.toml";
|
const CONFIG_FILENAME: &'static str = "Rocket.toml";
|
||||||
|
|
||||||
|
const GLOBAL_ENV_NAME: &'static str = "global";
|
||||||
|
|
||||||
/// Wraps `std::result` with the error type of
|
/// Wraps `std::result` with the error type of
|
||||||
/// [ConfigError](enum.ConfigError.html).
|
/// [ConfigError](enum.ConfigError.html).
|
||||||
pub type Result<T> = ::std::result::Result<T, ConfigError>;
|
pub type Result<T> = ::std::result::Result<T, ConfigError>;
|
||||||
|
@ -198,16 +218,14 @@ impl RocketConfig {
|
||||||
}).collect()
|
}).collect()
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
// Create a config with the defaults, but the set the env to the active
|
// Create a config with the defaults; set the env to the active one.
|
||||||
let mut config = RocketConfig::active_default(filename)?;
|
let mut config = RocketConfig::active_default(filename)?;
|
||||||
|
|
||||||
|
// Store all of the global overrides, if any, for later use.
|
||||||
|
let mut global = None;
|
||||||
|
|
||||||
// Parse the values from the TOML file.
|
// Parse the values from the TOML file.
|
||||||
for (entry, value) in toml {
|
for (entry, value) in toml {
|
||||||
// Parse the environment from the table entry name.
|
|
||||||
let env = entry.as_str().parse().map_err(|_| {
|
|
||||||
ConfigError::BadEntry(entry.clone(), filename.into())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Each environment must be a table.
|
// Each environment must be a table.
|
||||||
let kv_pairs = match value.as_table() {
|
let kv_pairs = match value.as_table() {
|
||||||
Some(table) => table,
|
Some(table) => table,
|
||||||
|
@ -216,9 +234,25 @@ impl RocketConfig {
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if entry.as_str() == GLOBAL_ENV_NAME {
|
||||||
|
global = Some(kv_pairs.clone());
|
||||||
|
} else {
|
||||||
|
// Parse the environment from the table entry name.
|
||||||
|
let env = entry.as_str().parse().map_err(|_| {
|
||||||
|
ConfigError::BadEntry(entry.clone(), filename.into())
|
||||||
|
})?;
|
||||||
|
|
||||||
// Set the environment configuration from the kv pairs.
|
// Set the environment configuration from the kv pairs.
|
||||||
config.set(env, &kv_pairs)?;
|
config.set(env, &kv_pairs)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override all of the environments with the global values.
|
||||||
|
if let Some(ref global_kv_pairs) = global {
|
||||||
|
for env in &Environment::all() {
|
||||||
|
config.set(*env, global_kv_pairs)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
@ -320,7 +354,7 @@ mod test {
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use super::{RocketConfig, ConfigError};
|
use super::{RocketConfig, ConfigError, GLOBAL_ENV_NAME};
|
||||||
use super::environment::{Environment, CONFIG_ENV};
|
use super::environment::{Environment, CONFIG_ENV};
|
||||||
use super::Environment::*;
|
use super::Environment::*;
|
||||||
use super::config::Config;
|
use super::config::Config;
|
||||||
|
@ -678,4 +712,42 @@ mod test {
|
||||||
session_key = "abcv" = other
|
session_key = "abcv" = other
|
||||||
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
|
"#.to_string(), TEST_CONFIG_FILENAME).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_global_overrides() {
|
||||||
|
// Take the lock so changing the environment doesn't cause races.
|
||||||
|
let _env_lock = ENV_LOCK.lock().unwrap();
|
||||||
|
|
||||||
|
// Test first that we can override each environment.
|
||||||
|
for env in &Environment::all() {
|
||||||
|
env::set_var(CONFIG_ENV, env.to_string());
|
||||||
|
|
||||||
|
check_config!(RocketConfig::parse(format!(r#"
|
||||||
|
[{}]
|
||||||
|
address = "7.6.5.4"
|
||||||
|
"#, GLOBAL_ENV_NAME), TEST_CONFIG_FILENAME), {
|
||||||
|
default_config(*env).address(
|
||||||
|
"7.6.5.4".into()
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
check_config!(RocketConfig::parse(format!(r#"
|
||||||
|
[{}]
|
||||||
|
database = "mysql"
|
||||||
|
"#, GLOBAL_ENV_NAME), TEST_CONFIG_FILENAME), {
|
||||||
|
default_config(*env).extra("database",
|
||||||
|
&Value::String("mysql".into())
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
check_config!(RocketConfig::parse(format!(r#"
|
||||||
|
[{}]
|
||||||
|
port = 3980
|
||||||
|
"#, GLOBAL_ENV_NAME), TEST_CONFIG_FILENAME), {
|
||||||
|
default_config(*env).port(
|
||||||
|
3980
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue