Add 'Config::read()' and 'Config::read_from()'.

The former method allows constructing a 'Config' in the exact manner
Rocket does internally: reading the active environment's properties from
'Rocket.toml' and overriding values from environment variables. The
'read_from()' property does the same except it allows a custom config
file path.

This PR also improves the internal structure of the configuration code.
This commit is contained in:
Sergio Benitez 2020-06-06 23:22:04 -07:00
parent ea9865ec42
commit a4301c0a9a
4 changed files with 232 additions and 193 deletions

View File

@ -6,7 +6,7 @@ use std::fmt;
use crate::config::Environment::*; use crate::config::Environment::*;
use crate::config::{Result, ConfigBuilder, Environment, ConfigError, LoggingLevel}; use crate::config::{Result, ConfigBuilder, Environment, ConfigError, LoggingLevel};
use crate::config::{Table, Value, Array, Datetime}; use crate::config::{FullConfig, Table, Value, Array, Datetime};
use crate::http::private::Key; use crate::http::private::Key;
use super::custom_values::*; use super::custom_values::*;
@ -75,8 +75,60 @@ macro_rules! config_from_raw {
} }
impl Config { impl Config {
/// Reads configuration values from the nearest `Rocket.toml`, searching for
/// a file by that name upwards from the current working directory to its
/// parents, as well as from environment variables named `ROCKET_{PARAM}` as
/// specified in the [`config`](crate::config) module documentation. Returns
/// the active configuration.
///
/// Specifically, this method:
///
/// 1. Locates the nearest `Rocket.toml` configuration file.
/// 2. Retrieves the active environment according to
/// [`Environment::active()`].
/// 3. Parses and validates the configuration file in its entirety,
/// extracting the values from the active environment.
/// 4. Overrides parameters with values set in `ROCKET_{PARAM}`
/// environment variables.
///
/// Any error encountered while performing these steps is returned.
///
/// # Example
///
/// ```rust
/// use rocket::config::Config;
///
/// # if false {
/// let config = Config::read().unwrap();
/// # }
/// ```
pub fn read() -> Result<Config> {
Self::read_from(&FullConfig::find()?)
}
/// This method is exactly like [`Config::read()`] except it uses the file
/// at `path` as the configuration file instead of searching for the nearest
/// `Rocket.toml`. The file must have the same format as `Rocket.toml`.
///
/// See [`Config::read()`] for more.
///
/// # Example
///
/// ```rust
/// use rocket::config::Config;
///
/// # if false {
/// let config = Config::read_from("/var/my-config.toml").unwrap();
/// # }
/// ```
pub fn read_from<P: AsRef<Path>>(path: P) -> Result<Config> {
FullConfig::read_from(path.as_ref()).map(FullConfig::take_active)
}
/// Returns a builder for `Config` structure where the default parameters /// Returns a builder for `Config` structure where the default parameters
/// are set to those of `env`. /// are set to those of `env`. This _does not_ read any configuration
/// parameters from any source. See [`config`](crate::config) for a list of
/// defaults.
/// ///
/// # Example /// # Example
/// ///
@ -95,7 +147,12 @@ impl Config {
} }
/// Returns a `Config` with the default parameters for the environment /// Returns a `Config` with the default parameters for the environment
/// `env`. See [`config`](crate::config) for a list of defaults. /// `env`. This _does not_ read any configuration parameters from any
/// source. See [`config`](crate::config) for a list of defaults.
///
/// # Panics
///
/// Panics if randomness cannot be retrieved from the OS.
/// ///
/// # Example /// # Example
/// ///
@ -106,11 +163,12 @@ impl Config {
/// my_config.set_port(1001); /// my_config.set_port(1001);
/// ``` /// ```
pub fn new(env: Environment) -> Config { pub fn new(env: Environment) -> Config {
Config::default(env) Config::default(env).expect("failed to read randomness from the OS")
} }
/// Returns a `Config` with the default parameters of the active environment /// Returns a `Config` with the default parameters of the active environment
/// as determined by the `ROCKET_ENV` environment variable. /// as determined by the `ROCKET_ENV` environment variable. This _does not_
/// read any configuration parameters from any source.
/// ///
/// If `ROCKET_ENV` is not set, the returned `Config` uses development /// If `ROCKET_ENV` is not set, the returned `Config` uses development
/// environment parameters when the application was compiled in `debug` mode /// environment parameters when the application was compiled in `debug` mode
@ -182,19 +240,17 @@ impl Config {
} }
/// Returns the default configuration for the environment `env` given that /// Returns the default configuration for the environment `env` given that
/// the configuration was stored at `config_file_path`. /// the configuration was stored at `path`. This doesn't read the file at
/// `path`; it simply uses `path` to set the config path property in the
/// returned `Config`.
/// ///
/// # Error /// # Error
/// ///
/// Return a `BadFilePath` error if `path` does not have a parent. /// Return a `BadFilePath` error if `path` does not have a parent.
///
/// # Panics
///
/// Panics if randomness cannot be retrieved from the OS.
pub(crate) fn default_from<P>(env: Environment, path: P) -> Result<Config> pub(crate) fn default_from<P>(env: Environment, path: P) -> Result<Config>
where P: AsRef<Path> where P: AsRef<Path>
{ {
let mut config = Config::default(env); let mut config = Config::default(env)?;
let config_file_path = path.as_ref().to_path_buf(); let config_file_path = path.as_ref().to_path_buf();
if let Some(parent) = config_file_path.parent() { if let Some(parent) = config_file_path.parent() {
@ -209,18 +265,15 @@ impl Config {
} }
/// Returns the default configuration for the environment `env`. /// Returns the default configuration for the environment `env`.
/// pub(crate) fn default(env: Environment) -> Result<Config> {
/// # Panics
///
/// Panics if randomness cannot be retrieved from the OS.
pub(crate) fn default(env: Environment) -> Config {
// Note: This may truncate if num_cpus::get() / 2 > u16::max. That's okay. // Note: This may truncate if num_cpus::get() / 2 > u16::max. That's okay.
let default_workers = (num_cpus::get() * 2) as u16; let default_workers = (num_cpus::get() * 2) as u16;
// Use a generated secret key by default. // Use a generated secret key by default.
let key = SecretKey::Generated(Key::generate()); let new_key = Key::try_generate().ok_or(ConfigError::RandFailure)?;
let key = SecretKey::Generated(new_key);
match env { Ok(match env {
Development => { Development => {
Config { Config {
environment: Development, environment: Development,
@ -269,7 +322,7 @@ impl Config {
root_path: None, root_path: None,
} }
} }
} })
} }
/// Constructs a `BadType` error given the entry `name`, the invalid `val` /// Constructs a `BadType` error given the entry `name`, the invalid `val`

View File

@ -14,6 +14,8 @@ pub enum ConfigError {
NotFound, NotFound,
/// There was an I/O error while reading the configuration file. /// There was an I/O error while reading the configuration file.
IoError, IoError,
/// There was an error retrieving randomness from the OS.
RandFailure,
/// There was an I/O error while setting a configuration parameter. /// There was an I/O error while setting a configuration parameter.
/// ///
/// Parameters: (io_error, config_param_name) /// Parameters: (io_error, config_param_name)
@ -59,6 +61,7 @@ impl ConfigError {
match *self { match *self {
NotFound => error!("config file was not found"), NotFound => error!("config file was not found"),
IoError => error!("failed reading the config file: IO error"), IoError => error!("failed reading the config file: IO error"),
RandFailure => error!("failed to read randomness from the OS"),
Io(ref error, param) => { Io(ref error, param) => {
error!("I/O error while setting {}:", Paint::default(param).bold()); error!("I/O error while setting {}:", Paint::default(param).bold());
info_!("{}", error); info_!("{}", error);
@ -135,6 +138,7 @@ impl fmt::Display for ConfigError {
match *self { match *self {
NotFound => write!(f, "config file was not found"), NotFound => write!(f, "config file was not found"),
IoError => write!(f, "I/O error while reading the config file"), IoError => write!(f, "I/O error while reading the config file"),
RandFailure => write!(f, "randomness could not be retrieved from the OS"),
Io(ref e, p) => write!(f, "I/O error while setting '{}': {}", p, e), Io(ref e, p) => write!(f, "I/O error while setting '{}': {}", p, e),
BadFilePath(ref p, _) => write!(f, "{:?} is not a valid config path", p), BadFilePath(ref p, _) => write!(f, "{:?} is not a valid config path", p),
BadEnv(ref e) => write!(f, "{:?} is not a valid `ROCKET_ENV` value", e), BadEnv(ref e) => write!(f, "{:?} is not a valid `ROCKET_ENV` value", e),
@ -159,6 +163,7 @@ impl Error for ConfigError {
match *self { match *self {
NotFound => "config file was not found", NotFound => "config file was not found",
IoError => "there was an I/O error while reading the config file", IoError => "there was an I/O error while reading the config file",
RandFailure => "randomness could not be retrieved from the OS",
Io(..) => "an I/O error occured while setting a configuration parameter", Io(..) => "an I/O error occured while setting a configuration parameter",
BadFilePath(..) => "the config file path is invalid", BadFilePath(..) => "the config file path is invalid",
BadEntry(..) => "an environment specified as `[environment]` is invalid", BadEntry(..) => "an environment specified as `[environment]` is invalid",
@ -177,6 +182,7 @@ impl PartialEq for ConfigError {
match (self, other) { match (self, other) {
(&NotFound, &NotFound) => true, (&NotFound, &NotFound) => true,
(&IoError, &IoError) => true, (&IoError, &IoError) => true,
(&RandFailure, &RandFailure) => true,
(&Io(_, p1), &Io(_, p2)) => p1 == p2, (&Io(_, p1), &Io(_, p2)) => p1 == p2,
(&BadFilePath(ref p1, _), &BadFilePath(ref p2, _)) => p1 == p2, (&BadFilePath(ref p1, _), &BadFilePath(ref p2, _)) => p1 == p2,
(&BadEnv(ref e1), &BadEnv(ref e2)) => e1 == e2, (&BadEnv(ref e1), &BadEnv(ref e2)) => e1 == e2,
@ -190,7 +196,7 @@ impl PartialEq for ConfigError {
k1 == k2 && v1 == v2 k1 == k2 && v1 == v2
} }
(&Missing(ref k1), &Missing(ref k2)) => k1 == k2, (&Missing(ref k1), &Missing(ref k2)) => k1 == k2,
(&NotFound, _) | (&IoError, _) | (&Io(..), _) (&NotFound, _) | (&IoError, _) | (&RandFailure, _) | (&Io(..), _)
| (&BadFilePath(..), _) | (&BadEnv(..), _) | (&ParseError(..), _) | (&BadFilePath(..), _) | (&BadEnv(..), _) | (&ParseError(..), _)
| (&UnknownKey(..), _) | (&BadEntry(..), _) | (&BadType(..), _) | (&UnknownKey(..), _) | (&BadEntry(..), _) | (&BadType(..), _)
| (&BadEnvVal(..), _) | (&Missing(..), _) => false | (&BadEnvVal(..), _) | (&Missing(..), _) => false

View File

@ -192,7 +192,6 @@ use std::fs::{self, File};
use std::collections::HashMap; use std::collections::HashMap;
use std::io::Read; use std::io::Read;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process;
use std::env; use std::env;
use toml; use toml;
@ -206,7 +205,6 @@ pub use self::builder::ConfigBuilder;
pub use crate::logger::LoggingLevel; pub use crate::logger::LoggingLevel;
pub(crate) use self::toml_ext::LoggedValue; pub(crate) use self::toml_ext::LoggedValue;
use crate::logger;
use self::Environment::*; use self::Environment::*;
use self::environment::CONFIG_ENV; use self::environment::CONFIG_ENV;
use crate::logger::COLORS_ENV; use crate::logger::COLORS_ENV;
@ -216,64 +214,60 @@ use crate::http::uncased::uncased_eq;
const CONFIG_FILENAME: &str = "Rocket.toml"; const CONFIG_FILENAME: &str = "Rocket.toml";
const GLOBAL_ENV_NAME: &str = "global"; const GLOBAL_ENV_NAME: &str = "global";
const ENV_VAR_PREFIX: &str = "ROCKET_"; const ENV_VAR_PREFIX: &str = "ROCKET_";
const PREHANDLED_VARS: [&str; 3] = ["ROCKET_CODEGEN_DEBUG", CONFIG_ENV, COLORS_ENV];
const CODEGEN_DEBUG_ENV: &str = "ROCKET_CODEGEN_DEBUG";
const PREHANDLED_VARS: [&str; 3] = [CODEGEN_DEBUG_ENV, CONFIG_ENV, COLORS_ENV];
/// Wraps `std::result` with the error type of [`ConfigError`]. /// Wraps `std::result` with the error type of [`ConfigError`].
pub type Result<T> = std::result::Result<T, ConfigError>; pub type Result<T> = std::result::Result<T, ConfigError>;
#[doc(hidden)] /// Stores a "full" config, which is all `Config`s for every environment.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct RocketConfig { pub(crate) struct FullConfig {
pub active_env: Environment, pub active_env: Environment,
config: HashMap<Environment, Config>, config: HashMap<Environment, Config>,
} }
impl RocketConfig { impl FullConfig {
/// Read the configuration from the `Rocket.toml` file. The file is search /// Read the configuration from the `Rocket.toml` file. The file is searched
/// for recursively up the tree, starting from the CWD. /// for recursively up the tree, starting from the CWD.
pub fn read() -> Result<RocketConfig> { pub fn read_from(path: &Path) -> Result<FullConfig> {
// Find the config file, starting from the `cwd` and working backwards.
let file = RocketConfig::find()?;
// Try to open the config file for reading. // Try to open the config file for reading.
let mut handle = File::open(&file).map_err(|_| ConfigError::IoError)?; let mut handle = File::open(path).map_err(|_| ConfigError::IoError)?;
// Read the configure file to a string for parsing. // Read the configure file to a string for parsing.
let mut contents = String::new(); let mut contents = String::new();
handle.read_to_string(&mut contents).map_err(|_| ConfigError::IoError)?; handle.read_to_string(&mut contents).map_err(|_| ConfigError::IoError)?;
// Parse the config and return the result. // Parse the config and return the result.
RocketConfig::parse(contents, &file) let mut config = FullConfig::parse(contents, path)?;
}
/// Return the default configuration for all environments and marks the // Override any config values with those from the environment.
/// active environment (via the CONFIG_ENV variable) as active.
pub fn active_default_from(filename: Option<&Path>) -> Result<RocketConfig> {
let mut defaults = HashMap::new();
if let Some(path) = filename {
defaults.insert(Development, Config::default_from(Development, &path)?);
defaults.insert(Staging, Config::default_from(Staging, &path)?);
defaults.insert(Production, Config::default_from(Production, &path)?);
} else {
defaults.insert(Development, Config::default(Development));
defaults.insert(Staging, Config::default(Staging));
defaults.insert(Production, Config::default(Production));
}
let mut config = RocketConfig {
active_env: Environment::active()?,
config: defaults,
};
// Override any variables from the environment.
config.override_from_env()?; config.override_from_env()?;
Ok(config) Ok(config)
} }
/// Return the default configuration for all environments and marks the /// Return the default configuration for all environments and marks the
/// active environment (via the CONFIG_ENV variable) as active. /// active environment (from `CONFIG_ENV`) as active. This doesn't read
pub fn active_default() -> Result<RocketConfig> { /// `filename`, nor any other config values from any source; it simply uses
RocketConfig::active_default_from(None) /// `filename` to set up the config path property in the returned `Config`.
pub fn active_default<'a, P: Into<Option<&'a Path>>>(filename: P) -> Result<FullConfig> {
let mut defaults = HashMap::new();
if let Some(path) = filename.into() {
defaults.insert(Development, Config::default_from(Development, &path)?);
defaults.insert(Staging, Config::default_from(Staging, &path)?);
defaults.insert(Production, Config::default_from(Production, &path)?);
} else {
defaults.insert(Development, Config::default(Development)?);
defaults.insert(Staging, Config::default(Staging)?);
defaults.insert(Production, Config::default(Production)?);
}
Ok(FullConfig {
active_env: Environment::active()?,
config: defaults,
})
} }
/// Iteratively search for `CONFIG_FILENAME` starting at the current working /// Iteratively search for `CONFIG_FILENAME` starting at the current working
@ -320,6 +314,7 @@ impl RocketConfig {
} }
/// Retrieves the `Config` for the environment `env`. /// Retrieves the `Config` for the environment `env`.
#[cfg(test)]
pub fn get(&self, env: Environment) -> &Config { pub fn get(&self, env: Environment) -> &Config {
match self.config.get(&env) { match self.config.get(&env) {
Some(config) => config, Some(config) => config,
@ -328,11 +323,16 @@ impl RocketConfig {
} }
/// Retrieves the `Config` for the active environment. /// Retrieves the `Config` for the active environment.
#[inline] #[cfg(test)]
pub fn active(&self) -> &Config { pub fn active(&self) -> &Config {
self.get(self.active_env) self.get(self.active_env)
} }
/// Retrieves the `Config` for the active environment.
pub fn take_active(mut self) -> Config {
self.config.remove(&self.active_env).expect("missing active config")
}
// Override all environments with values from env variables if present. // Override all environments with values from env variables if present.
fn override_from_env(&mut self) -> Result<()> { fn override_from_env(&mut self) -> Result<()> {
for (key, val) in env::vars() { for (key, val) in env::vars() {
@ -371,10 +371,13 @@ impl RocketConfig {
/// Parses the configuration from the Rocket.toml file. Also overrides any /// Parses the configuration from the Rocket.toml file. Also overrides any
/// values there with values from the environment. /// values there with values from the environment.
fn parse<P: AsRef<Path>>(src: String, filename: P) -> Result<RocketConfig> { fn parse<S, P>(src: S, filename: P) -> Result<FullConfig>
where S: Into<String>, P: AsRef<Path>
{
use self::ConfigError::ParseError; use self::ConfigError::ParseError;
// Parse the source as TOML, if possible. // Parse the source as TOML, if possible.
let src = src.into();
let path = filename.as_ref().to_path_buf(); let path = filename.as_ref().to_path_buf();
let table = match src.parse::<toml::Value>() { let table = match src.parse::<toml::Value>() {
Ok(toml::Value::Table(table)) => table, Ok(toml::Value::Table(table)) => table,
@ -386,7 +389,7 @@ impl RocketConfig {
}; };
// Create a config with the defaults; set the env to the active one. // Create a config with the defaults; set the env to the active one.
let mut config = RocketConfig::active_default_from(Some(filename.as_ref()))?; let mut config = FullConfig::active_default(filename.as_ref())?;
// Store all of the global overrides, if any, for later use. // Store all of the global overrides, if any, for later use.
let mut global = None; let mut global = None;
@ -422,57 +425,16 @@ impl RocketConfig {
} }
} }
// Override any variables from the environment.
config.override_from_env()?;
Ok(config) Ok(config)
} }
} }
/// Returns the active configuration and whether this call initialized the
/// configuration. The configuration can only be initialized once.
///
/// Initializes the global RocketConfig by reading the Rocket config file from
/// the current directory or any of its parents. Returns the active
/// configuration, which is determined by the config env variable. If there as a
/// problem parsing the configuration, the error is printed and the program is
/// aborted. If there an I/O issue reading the config file, a warning is printed
/// and the default configuration is used. If there is no config file, the
/// default configuration is used.
///
/// # Panics
///
/// If there is a problem, prints a nice error message and bails.
pub(crate) fn init() -> Config {
let bail = |e: ConfigError| -> ! {
logger::init(LoggingLevel::Debug);
e.pretty_print();
process::exit(1)
};
use self::ConfigError::*;
let config = RocketConfig::read().unwrap_or_else(|e| {
match e {
| ParseError(..) | BadEntry(..) | BadEnv(..) | BadType(..) | Io(..)
| BadFilePath(..) | BadEnvVal(..) | UnknownKey(..)
| Missing(..) => bail(e),
IoError => warn!("Failed reading Rocket.toml. Using defaults."),
NotFound => { /* try using the default below */ }
}
RocketConfig::active_default().unwrap_or_else(|e| bail(e))
});
// FIXME: Should probably store all of the config.
config.active().clone()
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use std::env; use std::env;
use std::sync::Mutex; use std::sync::Mutex;
use super::{RocketConfig, Config, ConfigError, ConfigBuilder}; use super::{FullConfig, Config, ConfigError, ConfigBuilder};
use super::{Environment, GLOBAL_ENV_NAME}; use super::{Environment, GLOBAL_ENV_NAME};
use super::environment::CONFIG_ENV; use super::environment::CONFIG_ENV;
use super::Environment::*; use super::Environment::*;
@ -505,8 +467,10 @@ mod test {
); );
} }
fn active_default() -> Result<RocketConfig> { fn active_default() -> Result<FullConfig> {
RocketConfig::active_default() let mut config = FullConfig::active_default(None)?;
config.override_from_env()?;
Ok(config)
} }
fn default_config(env: Environment) -> ConfigBuilder { fn default_config(env: Environment) -> ConfigBuilder {
@ -560,7 +524,7 @@ mod test {
let toml_table = format!("[{}]\n", env); let toml_table = format!("[{}]\n", env);
let e_str = env.to_string(); let e_str = env.to_string();
let err = ConfigError::BadEntry(e_str, TEST_CONFIG_FILENAME.into()); let err = ConfigError::BadEntry(e_str, TEST_CONFIG_FILENAME.into());
assert!(RocketConfig::parse(toml_table, TEST_CONFIG_FILENAME) assert!(FullConfig::parse(toml_table, TEST_CONFIG_FILENAME)
.err().map_or(false, |e| e == err)); .err().map_or(false, |e| e == err));
} }
} }
@ -596,21 +560,21 @@ mod test {
expected.environment = Development; expected.environment = Development;
let dev_config = ["[dev]", config_str].join("\n"); let dev_config = ["[dev]", config_str].join("\n");
let parsed = RocketConfig::parse(dev_config, TEST_CONFIG_FILENAME); let parsed = FullConfig::parse(dev_config, TEST_CONFIG_FILENAME);
check_config!(Development, parsed, expected.clone()); check_config!(Development, parsed, expected.clone());
check_config!(Staging, parsed, default_config(Staging)); check_config!(Staging, parsed, default_config(Staging));
check_config!(Production, parsed, default_config(Production)); check_config!(Production, parsed, default_config(Production));
expected.environment = Staging; expected.environment = Staging;
let stage_config = ["[stage]", config_str].join("\n"); let stage_config = ["[stage]", config_str].join("\n");
let parsed = RocketConfig::parse(stage_config, TEST_CONFIG_FILENAME); let parsed = FullConfig::parse(stage_config, TEST_CONFIG_FILENAME);
check_config!(Staging, parsed, expected.clone()); check_config!(Staging, parsed, expected.clone());
check_config!(Development, parsed, default_config(Development)); check_config!(Development, parsed, default_config(Development));
check_config!(Production, parsed, default_config(Production)); check_config!(Production, parsed, default_config(Production));
expected.environment = Production; expected.environment = Production;
let prod_config = ["[prod]", config_str].join("\n"); let prod_config = ["[prod]", config_str].join("\n");
let parsed = RocketConfig::parse(prod_config, TEST_CONFIG_FILENAME); let parsed = FullConfig::parse(prod_config, TEST_CONFIG_FILENAME);
check_config!(Production, parsed, expected); check_config!(Production, parsed, expected);
check_config!(Development, parsed, default_config(Development)); check_config!(Development, parsed, default_config(Development));
check_config!(Staging, parsed, default_config(Staging)); check_config!(Staging, parsed, default_config(Staging));
@ -622,35 +586,35 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::set_var(CONFIG_ENV, "dev"); env::set_var(CONFIG_ENV, "dev");
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[development] [development]
address = "localhost" address = "localhost"
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Development).address("localhost") default_config(Development).address("localhost")
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[development] [development]
address = "127.0.0.1" address = "127.0.0.1"
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Development).address("127.0.0.1") default_config(Development).address("127.0.0.1")
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[development] [development]
address = "::" address = "::"
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Development).address("::") default_config(Development).address("::")
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[dev] [dev]
address = "2001:db8::370:7334" address = "2001:db8::370:7334"
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Development).address("2001:db8::370:7334") default_config(Development).address("2001:db8::370:7334")
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[dev] [dev]
address = "0.0.0.0" address = "0.0.0.0"
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
@ -664,22 +628,22 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV); env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[development] [development]
address = 0000 address = 0000
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[development] [development]
address = true address = true
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[development] [development]
address = "........" address = "........"
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[staging] [staging]
address = "1.2.3.4:100" address = "1.2.3.4:100"
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
@ -693,24 +657,24 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::set_var(CONFIG_ENV, "dev"); env::set_var(CONFIG_ENV, "dev");
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[staging] [staging]
tls = { certs = "some/path.pem", key = "some/key.pem" } tls = { certs = "some/path.pem", key = "some/key.pem" }
"#.to_string(), TEST_CONFIG_FILENAME).is_ok()); "#.to_string(), TEST_CONFIG_FILENAME).is_ok());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[staging.tls] [staging.tls]
certs = "some/path.pem" certs = "some/path.pem"
key = "some/key.pem" key = "some/key.pem"
"#.to_string(), TEST_CONFIG_FILENAME).is_ok()); "#.to_string(), TEST_CONFIG_FILENAME).is_ok());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[global.tls] [global.tls]
certs = "some/path.pem" certs = "some/path.pem"
key = "some/key.pem" key = "some/key.pem"
"#.to_string(), TEST_CONFIG_FILENAME).is_ok()); "#.to_string(), TEST_CONFIG_FILENAME).is_ok());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[global] [global]
tls = { certs = "some/path.pem", key = "some/key.pem" } tls = { certs = "some/path.pem", key = "some/key.pem" }
"#.to_string(), TEST_CONFIG_FILENAME).is_ok()); "#.to_string(), TEST_CONFIG_FILENAME).is_ok());
@ -722,22 +686,22 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV); env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[development] [development]
tls = "hello" tls = "hello"
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[development] [development]
tls = { certs = "some/path.pem" } tls = { certs = "some/path.pem" }
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[development] [development]
tls = { certs = "some/path.pem", key = "some/key.pem", extra = "bah" } tls = { certs = "some/path.pem", key = "some/key.pem", extra = "bah" }
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[staging] [staging]
tls = { cert = "some/path.pem", key = "some/key.pem" } tls = { cert = "some/path.pem", key = "some/key.pem" }
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
@ -749,21 +713,21 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::set_var(CONFIG_ENV, "stage"); env::set_var(CONFIG_ENV, "stage");
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
port = 100 port = 100
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).port(100) default_config(Staging).port(100)
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
port = 6000 port = 6000
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).port(6000) default_config(Staging).port(6000)
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
port = 65535 port = 65535
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
@ -777,27 +741,27 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV); env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[development] [development]
port = true port = true
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[production] [production]
port = "hello" port = "hello"
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[staging] [staging]
port = -1 port = -1
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[staging] [staging]
port = 65536 port = 65536
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[staging] [staging]
port = 105836 port = 105836
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
@ -809,21 +773,21 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::set_var(CONFIG_ENV, "stage"); env::set_var(CONFIG_ENV, "stage");
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
workers = 1 workers = 1
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).workers(1) default_config(Staging).workers(1)
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
workers = 300 workers = 300
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).workers(300) default_config(Staging).workers(300)
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
workers = 65535 workers = 65535
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
@ -837,27 +801,27 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV); env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[development] [development]
workers = true workers = true
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[production] [production]
workers = "hello" workers = "hello"
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[staging] [staging]
workers = -1 workers = -1
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[staging] [staging]
workers = 65536 workers = 65536
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[staging] [staging]
workers = 105836 workers = 105836
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
@ -869,28 +833,28 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::set_var(CONFIG_ENV, "stage"); env::set_var(CONFIG_ENV, "stage");
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
keep_alive = 10 keep_alive = 10
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).keep_alive(10) default_config(Staging).keep_alive(10)
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
keep_alive = 0 keep_alive = 0
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).keep_alive(0) default_config(Staging).keep_alive(0)
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
keep_alive = 348 keep_alive = 348
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).keep_alive(348) default_config(Staging).keep_alive(348)
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
keep_alive = 0 keep_alive = 0
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
@ -904,22 +868,22 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV); env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[dev] [dev]
keep_alive = true keep_alive = true
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[dev] [dev]
keep_alive = -10 keep_alive = -10
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[dev] [dev]
keep_alive = "Some(10)" keep_alive = "Some(10)"
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[dev] [dev]
keep_alive = 4294967296 keep_alive = 4294967296
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
@ -931,7 +895,7 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::set_var(CONFIG_ENV, "stage"); env::set_var(CONFIG_ENV, "stage");
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
log = "normal" log = "normal"
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
@ -939,21 +903,21 @@ mod test {
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
log = "debug" log = "debug"
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).log_level(LoggingLevel::Debug) default_config(Staging).log_level(LoggingLevel::Debug)
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
log = "critical" log = "critical"
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
default_config(Staging).log_level(LoggingLevel::Critical) default_config(Staging).log_level(LoggingLevel::Critical)
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
log = "off" log = "off"
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
@ -967,17 +931,17 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV); env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[dev] [dev]
log = false log = false
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[development] [development]
log = 0 log = 0
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[prod] [prod]
log = "no" log = "no"
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
@ -989,7 +953,7 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::set_var(CONFIG_ENV, "stage"); env::set_var(CONFIG_ENV, "stage");
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
secret_key = "TpUiXK2d/v5DFxJnWL12suJKPExKR8h9zd/o+E7SU+0=" secret_key = "TpUiXK2d/v5DFxJnWL12suJKPExKR8h9zd/o+E7SU+0="
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
@ -998,7 +962,7 @@ mod test {
) )
}); });
check_config!(RocketConfig::parse(r#" check_config!(FullConfig::parse(r#"
[stage] [stage]
secret_key = "jTyprDberFUiUFsJ3vcb1XKsYHWNBRvWAnXTlbTgGFU=" secret_key = "jTyprDberFUiUFsJ3vcb1XKsYHWNBRvWAnXTlbTgGFU="
"#.to_string(), TEST_CONFIG_FILENAME), { "#.to_string(), TEST_CONFIG_FILENAME), {
@ -1014,17 +978,17 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV); env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[dev] [dev]
secret_key = true secret_key = true
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[dev] [dev]
secret_key = 1283724897238945234897 secret_key = 1283724897238945234897
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[dev] [dev]
secret_key = "abcv" secret_key = "abcv"
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
@ -1036,16 +1000,16 @@ mod test {
let _env_lock = ENV_LOCK.lock().unwrap(); let _env_lock = ENV_LOCK.lock().unwrap();
env::remove_var(CONFIG_ENV); env::remove_var(CONFIG_ENV);
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[dev [dev
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[dev] [dev]
1. = 2 1. = 2
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
assert!(RocketConfig::parse(r#" assert!(FullConfig::parse(r#"
[dev] [dev]
secret_key = "abcv" = other secret_key = "abcv" = other
"#.to_string(), TEST_CONFIG_FILENAME).is_err()); "#.to_string(), TEST_CONFIG_FILENAME).is_err());
@ -1060,21 +1024,21 @@ mod test {
for env in &Environment::ALL { for env in &Environment::ALL {
env::set_var(CONFIG_ENV, env.to_string()); env::set_var(CONFIG_ENV, env.to_string());
check_config!(RocketConfig::parse(format!(r#" check_config!(FullConfig::parse(format!(r#"
[{}] [{}]
address = "::1" address = "::1"
"#, GLOBAL_ENV_NAME), TEST_CONFIG_FILENAME), { "#, GLOBAL_ENV_NAME), TEST_CONFIG_FILENAME), {
default_config(*env).address("::1") default_config(*env).address("::1")
}); });
check_config!(RocketConfig::parse(format!(r#" check_config!(FullConfig::parse(format!(r#"
[{}] [{}]
database = "mysql" database = "mysql"
"#, GLOBAL_ENV_NAME), TEST_CONFIG_FILENAME), { "#, GLOBAL_ENV_NAME), TEST_CONFIG_FILENAME), {
default_config(*env).extra("database", "mysql") default_config(*env).extra("database", "mysql")
}); });
check_config!(RocketConfig::parse(format!(r#" check_config!(FullConfig::parse(format!(r#"
[{}] [{}]
port = 3980 port = 3980
"#, GLOBAL_ENV_NAME), TEST_CONFIG_FILENAME), { "#, GLOBAL_ENV_NAME), TEST_CONFIG_FILENAME), {
@ -1083,6 +1047,19 @@ mod test {
} }
} }
macro_rules! check_value {
($key:expr, $val:expr, $config:expr) => (
match $key {
"log" => assert_eq!($config.log_level, $val.parse().unwrap()),
"port" => assert_eq!($config.port, $val.parse().unwrap()),
"address" => assert_eq!($config.address, $val),
"extra_extra" => assert_eq!($config.get_bool($key).unwrap(), true),
"workers" => assert_eq!($config.workers, $val.parse().unwrap()),
_ => panic!("Unexpected key: {}", $key)
}
)
}
#[test] #[test]
fn test_env_override() { fn test_env_override() {
// Take the lock so changing the environment doesn't cause races. // Take the lock so changing the environment doesn't cause races.
@ -1093,33 +1070,22 @@ mod test {
("address", "1.2.3.4"), ("EXTRA_EXTRA", "true"), ("workers", "3") ("address", "1.2.3.4"), ("EXTRA_EXTRA", "true"), ("workers", "3")
]; ];
let check_value = |key: &str, val: &str, config: &Config| {
match key {
"log" => assert_eq!(config.log_level, val.parse().unwrap()),
"port" => assert_eq!(config.port, val.parse().unwrap()),
"address" => assert_eq!(config.address, val),
"extra_extra" => assert_eq!(config.get_bool(key).unwrap(), true),
"workers" => assert_eq!(config.workers, val.parse().unwrap()),
_ => panic!("Unexpected key: {}", key)
}
};
// Check that setting the environment variable actually changes the // Check that setting the environment variable actually changes the
// config for the default active and nonactive environments. // config for the default active and nonactive environments.
for &(key, val) in &pairs { for &(key, val) in &pairs {
env::set_var(format!("ROCKET_{}", key), val); env::set_var(format!("ROCKET_{}", key), val);
let rconfig = active_default().unwrap();
// Check that it overrides the active config. // Check that it overrides the active config.
for env in &Environment::ALL { for env in &Environment::ALL {
env::set_var(CONFIG_ENV, env.to_string()); env::set_var(CONFIG_ENV, env.to_string());
let rconfig = active_default().unwrap(); let rconfig = active_default().unwrap();
check_value(&*key.to_lowercase(), val, rconfig.active()); check_value!(&*key.to_lowercase(), val, rconfig.active());
} }
// And non-active configs. // And non-active configs.
let rconfig = active_default().unwrap();
for env in &Environment::ALL { for env in &Environment::ALL {
check_value(&*key.to_lowercase(), val, rconfig.get(*env)); check_value!(&*key.to_lowercase(), val, rconfig.get(*env));
} }
} }
@ -1145,19 +1111,20 @@ mod test {
port = 7810 port = 7810
workers = 21 workers = 21
log = "normal" log = "normal"
"#.to_string(); "#;
// Check that setting the environment variable actually changes the // Check that setting the environment variable actually changes the
// config for the default active environments. // config for the default active environments.
for &(key, val) in &pairs { for &(key, val) in &pairs {
env::set_var(format!("ROCKET_{}", key), val); env::set_var(format!("ROCKET_{}", key), val);
let r = RocketConfig::parse(toml.clone(), TEST_CONFIG_FILENAME).unwrap(); let mut r = FullConfig::parse(toml, TEST_CONFIG_FILENAME).unwrap();
check_value(&*key.to_lowercase(), val, r.active()); r.override_from_env().unwrap();
check_value!(&*key.to_lowercase(), val, r.active());
// And non-active configs. // And non-active configs.
for env in &Environment::ALL { for env in &Environment::ALL {
check_value(&*key.to_lowercase(), val, r.get(*env)); check_value!(&*key.to_lowercase(), val, r.get(*env));
} }
} }

View File

@ -12,7 +12,7 @@ use state::Container;
use crate::{logger, handler}; use crate::{logger, handler};
use crate::ext::ReadExt; use crate::ext::ReadExt;
use crate::config::{self, Config, LoggedValue}; use crate::config::{Config, FullConfig, ConfigError, LoggedValue};
use crate::request::{Request, FormItems}; use crate::request::{Request, FormItems};
use crate::data::Data; use crate::data::Data;
use crate::response::{Body, Response}; use crate::response::{Body, Response};
@ -344,16 +344,17 @@ impl Rocket {
/// Create a new `Rocket` application using the configuration information in /// Create a new `Rocket` application using the configuration information in
/// `Rocket.toml`. If the file does not exist or if there is an I/O error /// `Rocket.toml`. If the file does not exist or if there is an I/O error
/// reading the file, the defaults are used. See the [`config`] /// reading the file, the defaults are used. See the
/// documentation for more information on defaults. /// [`config`](crate::config) documentation for more information on
/// defaults.
/// ///
/// This method is typically called through the /// This method is typically called through the
/// [`rocket::ignite()`](crate::ignite) alias. /// [`rocket::ignite()`](crate::ignite) alias.
/// ///
/// # Panics /// # Panics
/// ///
/// If there is an error parsing the `Rocket.toml` file, this functions /// If there is an error reading configuration sources, this function prints
/// prints a nice error message and then exits the process. /// a nice error message and then exits the process.
/// ///
/// # Examples /// # Examples
/// ///
@ -362,10 +363,22 @@ impl Rocket {
/// rocket::ignite() /// rocket::ignite()
/// # }; /// # };
/// ``` /// ```
#[inline]
pub fn ignite() -> Rocket { pub fn ignite() -> Rocket {
// Note: init() will exit the process under config errors. Config::read()
Rocket::configured(config::init()) .or_else(|e| match e {
ConfigError::IoError => {
warn!("Failed to read 'Rocket.toml'. Using defaults.");
Ok(FullConfig::active_default(None)?.take_active())
}
ConfigError::NotFound => Ok(FullConfig::active_default(None)?.take_active()),
_ => Err(e)
})
.map(Rocket::configured)
.unwrap_or_else(|e: ConfigError| {
logger::init(logger::LoggingLevel::Debug);
e.pretty_print();
std::process::exit(1)
})
} }
/// Creates a new `Rocket` application using the supplied custom /// Creates a new `Rocket` application using the supplied custom