From 834c91ae9d092ff6d060d7afe705dddadfb686f4 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Mon, 12 Nov 2018 02:17:55 -0800 Subject: [PATCH] Remove the need for a current working directory. This commit includes several breaking changes: * `Config{new,development,staging,production}` constructors return a `Config` instead of a `Result`. * `Config.root()` returns an `Option<&Path>` instead of `&Path`. * `ConfigError::BadCWD` was removed. * `Config` no longer exposes a `config_path` field. Resolves #809. --- core/lib/src/config/builder.rs | 42 ++--- core/lib/src/config/config.rs | 264 +++++++++++++---------------- core/lib/src/config/environment.rs | 17 +- core/lib/src/config/error.rs | 17 +- core/lib/src/config/mod.rs | 72 +++----- core/lib/src/request/request.rs | 2 +- core/lib/src/request/tests.rs | 2 +- core/lib/src/router/collider.rs | 4 +- core/lib/src/router/mod.rs | 4 +- 9 files changed, 182 insertions(+), 242 deletions(-) diff --git a/core/lib/src/config/builder.rs b/core/lib/src/config/builder.rs index ce46dfd8..536e773c 100644 --- a/core/lib/src/config/builder.rs +++ b/core/lib/src/config/builder.rs @@ -26,21 +26,16 @@ pub struct ConfigBuilder { pub limits: Limits, /// Any extra parameters that aren't part of Rocket's config. pub extras: HashMap, - /// The root directory of this config. - pub root: PathBuf, + /// The root directory of this config, if any. + pub root: Option, } impl ConfigBuilder { /// Create a new `ConfigBuilder` instance using the default parameters from - /// the given `environment`. The root configuration directory is set to the - /// current working directory. + /// the given `environment`. /// /// This method is typically called indirectly via [`Config::build()`]. /// - /// # Panics - /// - /// Panics if the current directory cannot be retrieved. - /// /// # Example /// /// ```rust @@ -55,10 +50,7 @@ impl ConfigBuilder { /// # assert!(config.is_ok()); /// ``` pub fn new(environment: Environment) -> ConfigBuilder { - let config = Config::new(environment) - .expect("ConfigBuilder::new(): couldn't get current directory."); - - let root_dir = PathBuf::from(config.root()); + let config = Config::new(environment); ConfigBuilder { environment: config.environment, address: config.address, @@ -70,7 +62,7 @@ impl ConfigBuilder { tls: None, limits: config.limits, extras: config.extras, - root: root_dir, + root: None, } } @@ -263,10 +255,10 @@ impl ConfigBuilder { /// .root("/my_app/dir") /// .unwrap(); /// - /// assert_eq!(config.root(), Path::new("/my_app/dir")); + /// assert_eq!(config.root().unwrap(), Path::new("/my_app/dir")); /// ``` pub fn root>(mut self, path: P) -> Self { - self.root = path.as_ref().to_path_buf(); + self.root = Some(path.as_ref().to_path_buf()); self } @@ -298,9 +290,7 @@ impl ConfigBuilder { /// /// # Errors /// - /// If the current working directory cannot be retrieved, returns a `BadCWD` - /// error. If the address or secret key fail to parse, returns a `BadType` - /// error. + /// If the address or secret key fail to parse, returns a `BadType` error. /// /// # Example /// @@ -323,16 +313,19 @@ impl ConfigBuilder { /// assert!(config.is_err()); /// ``` pub fn finalize(self) -> Result { - let mut config = Config::new(self.environment)?; + let mut config = Config::new(self.environment); config.set_address(self.address)?; config.set_port(self.port); config.set_workers(self.workers); config.set_keep_alive(self.keep_alive); config.set_log_level(self.log_level); config.set_extras(self.extras); - config.set_root(self.root); config.set_limits(self.limits); + if let Some(root) = self.root { + config.set_root(root); + } + if let Some((certs_path, key_path)) = self.tls { config.set_tls(&certs_path, &key_path)?; } @@ -348,8 +341,8 @@ impl ConfigBuilder { /// /// # Panics /// - /// Panics if the current working directory cannot be retrieved or if the - /// supplied address, secret key, or TLS configuration fail to parse. + /// Panics if the supplied address, secret key, or TLS configuration fail to + /// parse. /// /// # Example /// @@ -371,9 +364,8 @@ impl ConfigBuilder { /// /// # Panics /// - /// Panics if the current working directory cannot be retrieved or if the - /// supplied address, secret key, or TLS configuration fail to parse. If a - /// panic occurs, the error message `msg` is printed. + /// Panics if the supplied address, secret key, or TLS configuration fail to + /// parse. If a panic occurs, the error message `msg` is printed. /// /// # Example /// diff --git a/core/lib/src/config/config.rs b/core/lib/src/config/config.rs index 5fba61ce..8ea4440b 100644 --- a/core/lib/src/config/config.rs +++ b/core/lib/src/config/config.rs @@ -3,7 +3,6 @@ use std::net::ToSocketAddrs; use std::path::{Path, PathBuf}; use std::convert::AsRef; use std::fmt; -use std::env; use super::custom_values::*; use {num_cpus, base64}; @@ -57,8 +56,10 @@ pub struct Config { pub limits: Limits, /// Extra parameters that aren't part of Rocket's core config. pub extras: HashMap, - /// The path to the configuration file this config belongs to. - pub config_path: PathBuf, + /// The path to the configuration file this config was loaded from, if any. + crate config_file_path: Option, + /// The path root-relative files will be rooted from. + crate root_path: Option, } macro_rules! config_from_raw { @@ -76,12 +77,7 @@ macro_rules! config_from_raw { impl Config { /// Returns a builder for `Config` structure where the default parameters - /// are set to those of `env`. The root configuration directory is set to - /// the current working directory. - /// - /// # Panics - /// - /// Panics if the current directory cannot be retrieved. + /// are set to those of `env`. /// /// # Example /// @@ -99,25 +95,18 @@ impl Config { ConfigBuilder::new(env) } - /// Returns a `Config` with the parameters for the environment `env`. The - /// root configuration directory is set to the current working directory. - /// - /// # Errors - /// - /// If the current directory cannot be retrieved, a `BadCWD` error is - /// returned. + /// Returns a `Config` with the parameters for the environment `env`. /// /// # Example /// /// ```rust /// use rocket::config::{Config, Environment}; /// - /// let mut my_config = Config::new(Environment::Production).expect("cwd"); + /// let mut my_config = Config::new(Environment::Production); /// my_config.set_port(1001); /// ``` - pub fn new(env: Environment) -> Result { - let cwd = env::current_dir().map_err(|_| ConfigError::BadCWD)?; - Config::default(env, cwd.as_path().join("Rocket.custom.toml")) + pub fn new(env: Environment) -> Config { + Config::default(env) } /// Returns a `Config` with the default parameters of the active environment @@ -126,16 +115,14 @@ impl Config { /// If `ROCKET_ENV` is not set, the returned `Config` uses development /// environment parameters when the application was compiled in `debug` mode /// and production environment parameters when the application was compiled - /// in `release` mode. The root configuration directory is set to the - /// current working directory. + /// in `release` mode. /// /// This is equivalent to `Config::new(Environment::active()?)`. /// /// # Errors /// - /// If the current directory cannot be retrieved, a `BadCWD` error is - /// returned. Returns a `BadEnv` error if `ROCKET_ENV` is set and contains - /// an invalid or unknown environment name. + /// Returns a `BadEnv` error if `ROCKET_ENV` is set and contains an invalid + /// or unknown environment name. /// /// # Example /// @@ -146,95 +133,94 @@ impl Config { /// my_config.set_port(1001); /// ``` pub fn active() -> Result { - Config::new(Environment::active()?) + Ok(Config::new(Environment::active()?)) } /// Returns a `Config` with the default parameters of the development - /// environment. The root configuration directory is set to the current - /// working directory. - /// - /// # Errors - /// - /// If the current directory cannot be retrieved, a `BadCWD` error is - /// returned. + /// environment. /// /// # Example /// /// ```rust /// use rocket::config::{Config, Environment}; /// - /// let mut my_config = Config::development().unwrap(); + /// let mut my_config = Config::development(); /// my_config.set_port(1001); /// ``` - pub fn development() -> Result { + pub fn development() -> Config { Config::new(Environment::Development) } /// Returns a `Config` with the default parameters of the staging - /// environment. The root configuration directory is set to the current - /// working directory. - /// - /// # Errors - /// - /// If the current directory cannot be retrieved, a `BadCWD` error is - /// returned. + /// environment. /// /// # Example /// /// ```rust /// use rocket::config::{Config, Environment}; /// - /// let mut my_config = Config::staging().expect("cwd"); + /// let mut my_config = Config::staging(); /// my_config.set_port(1001); /// ``` - pub fn staging() -> Result { + pub fn staging() -> Config { Config::new(Environment::Staging) } /// Returns a `Config` with the default parameters of the production - /// environment. The root configuration directory is set to the current - /// working directory. - /// - /// # Errors - /// - /// If the current directory cannot be retrieved, a `BadCWD` error is - /// returned. + /// environment. /// /// # Example /// /// ```rust /// use rocket::config::{Config, Environment}; /// - /// let mut my_config = Config::production().expect("cwd"); + /// let mut my_config = Config::production(); /// my_config.set_port(1001); /// ``` - pub fn production() -> Result { + pub fn production() -> Config { Config::new(Environment::Production) } /// Returns the default configuration for the environment `env` given that - /// the configuration was stored at `config_path`. If `config_path` is not - /// an absolute path, an `Err` of `ConfigError::BadFilePath` is returned. + /// the configuration was stored at `config_file_path`. + /// + /// # Error + /// + /// Return a `BadFilePath` error if `path` does not have a parent. /// /// # Panics /// /// Panics if randomness cannot be retrieved from the OS. - crate fn default

(env: Environment, path: P) -> Result + crate fn default_from

(env: Environment, path: P) -> Result where P: AsRef { - let config_path = path.as_ref().to_path_buf(); - if config_path.parent().is_none() { - return Err(ConfigError::BadFilePath(config_path, - "Configuration files must be rooted in a directory.")); + let mut config = Config::default(env); + + let config_file_path = path.as_ref().to_path_buf(); + if let Some(parent) = config_file_path.parent() { + config.set_root(parent); + } else { + let msg = "Configuration files must be rooted in a directory."; + return Err(ConfigError::BadFilePath(config_file_path.clone(), msg)); } + config.config_file_path = Some(config_file_path); + Ok(config) + } + + /// Returns the default configuration for the environment `env`. + /// + /// # Panics + /// + /// Panics if randomness cannot be retrieved from the OS. + crate fn default(env: Environment) -> Config { // Note: This may truncate if num_cpus::get() / 2 > u16::max. That's okay. let default_workers = (num_cpus::get() * 2) as u16; // Use a generated secret key by default. let key = SecretKey::Generated(Key::generate()); - Ok(match env { + match env { Development => { Config { environment: Development, @@ -247,7 +233,8 @@ impl Config { tls: None, limits: Limits::default(), extras: HashMap::new(), - config_path, + config_file_path: None, + root_path: None, } } Staging => { @@ -262,7 +249,8 @@ impl Config { tls: None, limits: Limits::default(), extras: HashMap::new(), - config_path, + config_file_path: None, + root_path: None, } } Production => { @@ -277,10 +265,11 @@ impl Config { tls: None, limits: Limits::default(), extras: HashMap::new(), - config_path, + config_file_path: None, + root_path: None, } } - }) + } } /// Constructs a `BadType` error given the entry `name`, the invalid `val` @@ -291,7 +280,7 @@ impl Config { actual: &'static str, expect: &'static str) -> ConfigError { let id = format!("{}.{}", self.environment, name); - ConfigError::BadType(id, expect, actual, self.config_path.clone()) + ConfigError::BadType(id, expect, actual, self.config_file_path.clone()) } /// Sets the configuration `val` for the `name` entry. If the `name` is one @@ -336,22 +325,16 @@ impl Config { /// # use std::path::Path; /// use rocket::config::{Config, Environment}; /// - /// # use rocket::config::ConfigError; - /// # fn config_test() -> Result<(), ConfigError> { - /// let mut config = Config::new(Environment::Staging)?; - /// config.set_root("/tmp/my_app"); + /// let mut config = Config::new(Environment::Staging); + /// config.set_root("/var/my_app"); /// - /// assert_eq!(config.root(), Path::new("/tmp/my_app")); - /// # Ok(()) - /// # } + /// # #[cfg(not(windows))] + /// assert_eq!(config.root().unwrap(), Path::new("/var/my_app")); + /// # #[cfg(windows)] + /// assert_eq!(config.root().unwrap(), Path::new("C:\\var\\my_app")); /// ``` pub fn set_root>(&mut self, path: P) { - let new_path = match self.config_path.file_name() { - Some(file) => path.as_ref().join(file), - None => path.as_ref().join("Rocket.custom.toml") - }; - - self.config_path = new_path + self.root_path = Some(path.as_ref().into()); } /// Sets the address of `self` to `address`. @@ -366,14 +349,10 @@ impl Config { /// ```rust /// use rocket::config::{Config, Environment}; /// - /// # use rocket::config::ConfigError; - /// # fn config_test() -> Result<(), ConfigError> { - /// let mut config = Config::new(Environment::Staging)?; + /// let mut config = Config::new(Environment::Staging); /// assert!(config.set_address("localhost").is_ok()); /// assert!(config.set_address("::").is_ok()); /// assert!(config.set_address("?").is_err()); - /// # Ok(()) - /// # } /// ``` pub fn set_address>(&mut self, address: A) -> Result<()> { let address = address.into(); @@ -392,12 +371,9 @@ impl Config { /// ```rust /// use rocket::config::{Config, Environment}; /// - /// # use rocket::config::ConfigError; - /// # fn config_test() -> Result<(), ConfigError> { - /// let mut config = Config::new(Environment::Staging)?; + /// let mut config = Config::new(Environment::Staging); /// config.set_port(1024); - /// # Ok(()) - /// # } + /// assert_eq!(config.port, 1024); /// ``` #[inline] pub fn set_port(&mut self, port: u16) { @@ -411,12 +387,9 @@ impl Config { /// ```rust /// use rocket::config::{Config, Environment}; /// - /// # use rocket::config::ConfigError; - /// # fn config_test() -> Result<(), ConfigError> { - /// let mut config = Config::new(Environment::Staging)?; + /// let mut config = Config::new(Environment::Staging); /// config.set_workers(64); - /// # Ok(()) - /// # } + /// assert_eq!(config.workers, 64); /// ``` #[inline] pub fn set_workers(&mut self, workers: u16) { @@ -431,17 +404,15 @@ impl Config { /// ```rust /// use rocket::config::Config; /// - /// # use rocket::config::ConfigError; - /// # fn config_test() -> Result<(), ConfigError> { - /// let mut config = Config::development()?; + /// let mut config = Config::development(); /// /// // Set keep-alive timeout to 10 seconds. /// config.set_keep_alive(10); + /// assert_eq!(config.keep_alive, Some(10)); /// /// // Disable keep-alive. /// config.set_keep_alive(0); - /// # Ok(()) - /// # } + /// assert_eq!(config.keep_alive, None); /// ``` #[inline] pub fn set_keep_alive(&mut self, timeout: u32) { @@ -465,14 +436,10 @@ impl Config { /// ```rust /// use rocket::config::{Config, Environment}; /// - /// # use rocket::config::ConfigError; - /// # fn config_test() -> Result<(), ConfigError> { - /// let mut config = Config::new(Environment::Staging)?; + /// let mut config = Config::new(Environment::Staging); /// let key = "8Xui8SN4mI+7egV/9dlfYYLGQJeEx4+DwmSQLwDVXJg="; /// assert!(config.set_secret_key(key).is_ok()); /// assert!(config.set_secret_key("hello? anyone there?").is_err()); - /// # Ok(()) - /// # } /// ``` pub fn set_secret_key>(&mut self, key: K) -> Result<()> { let key = key.into(); @@ -499,12 +466,9 @@ impl Config { /// ```rust /// use rocket::config::{Config, LoggingLevel, Environment}; /// - /// # use rocket::config::ConfigError; - /// # fn config_test() -> Result<(), ConfigError> { - /// let mut config = Config::new(Environment::Staging)?; + /// let mut config = Config::new(Environment::Staging); /// config.set_log_level(LoggingLevel::Critical); - /// # Ok(()) - /// # } + /// assert_eq!(config.log_level, LoggingLevel::Critical); /// ``` #[inline] pub fn set_log_level(&mut self, log_level: LoggingLevel) { @@ -518,12 +482,8 @@ impl Config { /// ```rust /// use rocket::config::{Config, Limits}; /// - /// # use rocket::config::ConfigError; - /// # fn config_test() -> Result<(), ConfigError> { - /// let mut config = Config::development()?; + /// let mut config = Config::development(); /// config.set_limits(Limits::default().limit("json", 4 * (1 << 20))); - /// # Ok(()) - /// # } /// ``` #[inline] pub fn set_limits(&mut self, limits: Limits) { @@ -550,7 +510,7 @@ impl Config { /// /// # use rocket::config::ConfigError; /// # fn config_test() -> Result<(), ConfigError> { - /// let mut config = Config::development()?; + /// let mut config = Config::development(); /// config.set_tls("/etc/ssl/my_certs.pem", "/etc/ssl/priv.key")?; /// # Ok(()) /// # } @@ -605,9 +565,7 @@ impl Config { /// use std::collections::HashMap; /// use rocket::config::{Config, Environment}; /// - /// # use rocket::config::ConfigError; - /// # fn config_test() -> Result<(), ConfigError> { - /// let mut config = Config::new(Environment::Staging)?; + /// let mut config = Config::new(Environment::Staging); /// /// // Create the `extras` map. /// let mut extras = HashMap::new(); @@ -615,8 +573,6 @@ impl Config { /// extras.insert("templates".to_string(), "my_dir".into()); /// /// config.set_extras(extras); - /// # Ok(()) - /// # } /// ``` #[inline] pub fn set_extras(&mut self, extras: HashMap) { @@ -632,9 +588,7 @@ impl Config { /// use std::collections::HashMap; /// use rocket::config::{Config, Environment}; /// - /// # use rocket::config::ConfigError; - /// # fn config_test() -> Result<(), ConfigError> { - /// let mut config = Config::new(Environment::Staging)?; + /// let mut config = Config::new(Environment::Staging); /// assert_eq!(config.extras().count(), 0); /// /// // Add a couple of extras to the config. @@ -644,8 +598,6 @@ impl Config { /// config.set_extras(extras); /// /// assert_eq!(config.extras().count(), 2); - /// # Ok(()) - /// # } /// ``` #[inline] pub fn extras<'a>(&'a self) -> impl Iterator { @@ -889,9 +841,13 @@ impl Config { .ok_or_else(|| self.bad_type(name, val.type_str(), "a datetime")) } - /// Returns the path at which the configuration file for `self` is stored. - /// For instance, if the configuration file is at `/tmp/Rocket.toml`, the - /// path `/tmp` is returned. + /// Returns the root path of the configuration, if one is known. + /// + /// For configurations loaded from a `Rocket.toml` file, this will be the + /// directory in which the file is stored. For instance, if the + /// configuration file is at `/tmp/Rocket.toml`, the path `/tmp` is + /// returned. For other configurations, this will be the path set via + /// [`Config::set_root()`] or [`ConfigBuilder::root()`]. /// /// # Example /// @@ -899,35 +855,47 @@ impl Config { /// use std::env::current_dir; /// use rocket::config::{Config, Environment}; /// - /// let config = Config::new(Environment::Staging) - /// .expect("can retrieve current directory"); + /// let mut config = Config::new(Environment::Staging); + /// assert_eq!(config.root(), None); /// - /// assert_eq!(config.root(), current_dir().unwrap()); + /// let cwd = current_dir().expect("have cwd"); + /// config.set_root(&cwd); + /// assert_eq!(config.root().unwrap(), cwd); /// ``` - pub fn root(&self) -> &Path { - match self.config_path.parent() { - Some(parent) => parent, - None => panic!("root(): path {:?} has no parent", self.config_path) - } + pub fn root(&self) -> Option<&Path> { + self.root_path.as_ref().map(|p| p.as_ref()) } - /// If `path` is a relative path, `path` is appended to the - /// [`Config::root()`] at which the configuration file for `self` is stored - /// and the new path is returned. If `path` is absolute, `path` is returned - /// unaltered. + /// Returns `path` relative to this configuration. + /// + /// The path that is returned depends on whether: + /// + /// 1. Whether `path` is absolute or relative. + /// 2. Whether there is a [`Config::root()`] configured. + /// 3. Whether there is a current directory. + /// + /// If `path` is absolute, it is returned unaltered. Otherwise, if `path` is + /// relative and there is a root configured, the root is prepended to `path` + /// and the newlt concatenated path is returned. Otherwise, if there is a + /// current directory, it is preprended to `path` and the newly concatenated + /// path is returned. Finally, if all else fails, the path is simply + /// returned. /// /// # Example /// /// ```rust - /// use std::env::current_dir; /// use std::path::Path; + /// use std::env::current_dir; + /// /// use rocket::config::{Config, Environment}; /// - /// let config = Config::new(Environment::Staging) - /// .expect("can retrieve current directory"); + /// let mut config = Config::new(Environment::Staging); /// - /// assert_eq!(config.root(), current_dir().unwrap()); - /// assert_eq!(config.root_relative("abc"), config.root().join("abc")); + /// let cwd = current_dir().expect("have cwd"); + /// config.set_root(&cwd); + /// assert_eq!(config.root().unwrap(), cwd); + /// + /// assert_eq!(config.root_relative("abc"), cwd.join("abc")); /// # #[cfg(not(windows))] /// assert_eq!(config.root_relative("/abc"), Path::new("/abc")); /// # #[cfg(windows)] @@ -937,8 +905,12 @@ impl Config { let path = path.as_ref(); if path.is_absolute() { path.into() + } else if let Some(root) = self.root() { + root.join(path) + } else if let Ok(cwd) = ::std::env::current_dir() { + cwd.join(path) } else { - self.root().join(path) + path.into() } } } diff --git a/core/lib/src/config/environment.rs b/core/lib/src/config/environment.rs index 53b05f32..b582d258 100644 --- a/core/lib/src/config/environment.rs +++ b/core/lib/src/config/environment.rs @@ -20,6 +20,12 @@ pub enum Environment { } impl Environment { + /// List of all of the possible environments. + crate const ALL: [Environment; 3] = [Development, Staging, Production]; + + /// String of all valid environments. + crate const VALID: &'static str = "development, staging, production"; + /// Retrieves the "active" environment as determined by the `ROCKET_ENV` /// environment variable. If `ROCKET_ENV` is not set, returns `Development` /// when the application was compiled in `debug` mode and `Production` when @@ -39,17 +45,6 @@ impl Environment { } } - /// Returns a string with a comma-separated list of valid environments. - crate fn valid() -> &'static str { - "development, staging, production" - } - - /// Returns a list of all of the possible environments. - #[inline] - crate fn all() -> [Environment; 3] { - [Development, Staging, Production] - } - /// Returns `true` if `self` is `Environment::Development`. /// /// # Example diff --git a/core/lib/src/config/error.rs b/core/lib/src/config/error.rs index 8cc4d26c..ef1db672 100644 --- a/core/lib/src/config/error.rs +++ b/core/lib/src/config/error.rs @@ -10,8 +10,6 @@ use yansi::Color::White; /// The type of a configuration error. #[derive(Debug)] pub enum ConfigError { - /// The current working directory could not be determined. - BadCWD, /// The configuration file was not found. NotFound, /// There was an I/O error while reading the configuration file. @@ -35,7 +33,7 @@ pub enum ConfigError { /// A config key was specified with a value of the wrong type. /// /// Parameters: (entry_name, expected_type, actual_type, filename) - BadType(String, &'static str, &'static str, PathBuf), + BadType(String, &'static str, &'static str, Option), /// There was a TOML parsing error. /// /// Parameters: (toml_source_string, filename, error_description, line/col) @@ -57,9 +55,8 @@ pub enum ConfigError { impl ConfigError { /// Prints this configuration error with Rocket formatting. pub fn pretty_print(&self) { - let valid_envs = Environment::valid(); + let valid_envs = Environment::VALID; match *self { - BadCWD => error!("couldn't get current working directory"), NotFound => error!("config file was not found"), IoError => error!("failed reading the config file: IO error"), Io(ref error, param) => { @@ -82,7 +79,10 @@ impl ConfigError { } BadType(ref name, expected, actual, ref filename) => { error!("{} key could not be parsed", White.paint(name)); - info_!("in {:?}", White.paint(filename)); + if let Some(filename) = filename { + info_!("in {:?}", White.paint(filename)); + } + info_!("expected value to be {}, but found {}", White.paint(expected), White.paint(actual)); } @@ -133,7 +133,6 @@ impl ConfigError { impl fmt::Display for ConfigError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - BadCWD => write!(f, "couldn't get current working directory"), NotFound => write!(f, "config file was not found"), IoError => write!(f, "I/O error while reading the config file"), Io(ref e, p) => write!(f, "I/O error while setting '{}': {}", p, e), @@ -158,7 +157,6 @@ impl fmt::Display for ConfigError { impl Error for ConfigError { fn description(&self) -> &str { match *self { - BadCWD => "the current working directory could not be determined", NotFound => "config file was not found", IoError => "there was an I/O error while reading the config file", Io(..) => "an I/O error occured while setting a configuration parameter", @@ -177,7 +175,6 @@ impl Error for ConfigError { impl PartialEq for ConfigError { fn eq(&self, other: &ConfigError) -> bool { match (self, other) { - (&BadCWD, &BadCWD) => true, (&NotFound, &NotFound) => true, (&IoError, &IoError) => true, (&Io(_, p1), &Io(_, p2)) => p1 == p2, @@ -193,7 +190,7 @@ impl PartialEq for ConfigError { k1 == k2 && v1 == v2 } (&Missing(ref k1), &Missing(ref k2)) => k1 == k2, - (&BadCWD, _) | (&NotFound, _) | (&IoError, _) | (&Io(..), _) + (&NotFound, _) | (&IoError, _) | (&Io(..), _) | (&BadFilePath(..), _) | (&BadEnv(..), _) | (&ParseError(..), _) | (&UnknownKey(..), _) | (&BadEntry(..), _) | (&BadType(..), _) | (&BadEnvVal(..), _) | (&Missing(..), _) => false diff --git a/core/lib/src/config/mod.rs b/core/lib/src/config/mod.rs index ed86aec9..a5a3c603 100644 --- a/core/lib/src/config/mod.rs +++ b/core/lib/src/config/mod.rs @@ -229,29 +229,6 @@ pub struct RocketConfig { } impl RocketConfig { - /// Create a new configuration using the passed in `config` for all - /// environments. The Rocket.toml file is ignored, as are environment - /// variables. - /// - /// # Panics - /// - /// If the current working directory can't be retrieved, this function - /// panics. - pub fn new(config: Config) -> RocketConfig { - let f = config.config_path.clone(); - let active_env = config.environment; - - // None of these unwraps should fail since the filename is coming from - // an existing config. - let mut configs = HashMap::new(); - configs.insert(Development, Config::default(Development, &f).unwrap()); - configs.insert(Staging, Config::default(Staging, &f).unwrap()); - configs.insert(Production, Config::default(Production, &f).unwrap()); - configs.insert(active_env, config); - - RocketConfig { active_env, config: configs } - } - /// Read the configuration from the `Rocket.toml` file. The file is search /// for recursively up the tree, starting from the CWD. pub fn read() -> Result { @@ -271,11 +248,17 @@ impl RocketConfig { /// Return the default configuration for all environments and marks the /// active environment (via the CONFIG_ENV variable) as active. - pub fn active_default>(filename: P) -> Result { + pub fn active_default_from(filename: Option<&Path>) -> Result { let mut defaults = HashMap::new(); - defaults.insert(Development, Config::default(Development, &filename)?); - defaults.insert(Staging, Config::default(Staging, &filename)?); - defaults.insert(Production, Config::default(Production, &filename)?); + 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()?, @@ -287,12 +270,18 @@ impl RocketConfig { Ok(config) } + /// Return the default configuration for all environments and marks the + /// active environment (via the CONFIG_ENV variable) as active. + pub fn active_default() -> Result { + RocketConfig::active_default_from(None) + } + /// Iteratively search for `CONFIG_FILENAME` starting at the current working /// directory and working up through its parents. Returns the path to the /// file or an Error::NoKey if the file couldn't be found. If the current /// working directory can't be determined, return `BadCWD`. fn find() -> Result { - let cwd = env::current_dir().map_err(|_| ConfigError::BadCWD)?; + let cwd = env::current_dir().map_err(|_| ConfigError::NotFound)?; let mut current = cwd.as_path(); loop { @@ -365,7 +354,7 @@ impl RocketConfig { Err(e) => return Err(ConfigError::BadEnvVal(key, val, e)) }; - for env in &Environment::all() { + for env in &Environment::ALL { match self.get_mut(*env).set_raw(&key, &toml_val) { Err(ConfigError::BadType(_, exp, actual, _)) => { let e = format!("expected {}, but found {}", exp, actual); @@ -397,7 +386,7 @@ impl RocketConfig { }; // 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_from(Some(filename.as_ref()))?; // Store all of the global overrides, if any, for later use. let mut global = None; @@ -408,7 +397,7 @@ impl RocketConfig { let kv_pairs = match value.as_table() { Some(table) => table, None => return Err(ConfigError::BadType( - entry, "a table", value.type_str(), path.clone() + entry, "a table", value.type_str(), Some(path.clone()) )) }; @@ -428,7 +417,7 @@ impl RocketConfig { // Override all of the environments with the global values. if let Some(ref global_kv_pairs) = global { - for env in &Environment::all() { + for env in &Environment::ALL { config.set_from_table(*env, global_kv_pairs)?; } } @@ -467,16 +456,11 @@ crate fn init() -> Config { | ParseError(..) | BadEntry(..) | BadEnv(..) | BadType(..) | Io(..) | BadFilePath(..) | BadEnvVal(..) | UnknownKey(..) | Missing(..) => bail(e), - IoError | BadCWD => warn!("Failed reading Rocket.toml. Using defaults."), + IoError => warn!("Failed reading Rocket.toml. Using defaults."), NotFound => { /* try using the default below */ } } - let default_path = match env::current_dir() { - Ok(path) => path.join(&format!(".{}.{}", "default", CONFIG_FILENAME)), - Err(_) => bail(ConfigError::BadCWD) - }; - - RocketConfig::active_default(&default_path).unwrap_or_else(|e| bail(e)) + RocketConfig::active_default().unwrap_or_else(|e| bail(e)) }); // FIXME: Should probably store all of the config. @@ -522,7 +506,7 @@ mod test { } fn active_default() -> Result { - RocketConfig::active_default(TEST_CONFIG_FILENAME) + RocketConfig::active_default() } fn default_config(env: Environment) -> ConfigBuilder { @@ -1073,7 +1057,7 @@ mod test { let _env_lock = ENV_LOCK.lock().unwrap(); // Test first that we can override each environment. - for env in &Environment::all() { + for env in &Environment::ALL { env::set_var(CONFIG_ENV, env.to_string()); check_config!(RocketConfig::parse(format!(r#" @@ -1127,14 +1111,14 @@ mod test { let rconfig = active_default().unwrap(); // 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()); let rconfig = active_default().unwrap(); check_value(&*key.to_lowercase(), val, rconfig.active()); } // And non-active configs. - for env in &Environment::all() { + for env in &Environment::ALL { check_value(&*key.to_lowercase(), val, rconfig.get(*env)); } } @@ -1172,7 +1156,7 @@ mod test { check_value(&*key.to_lowercase(), val, r.active()); // And non-active configs. - for env in &Environment::all() { + for env in &Environment::ALL { check_value(&*key.to_lowercase(), val, r.get(*env)); } } diff --git a/core/lib/src/request/request.rs b/core/lib/src/request/request.rs index 84cbb783..07821e2f 100644 --- a/core/lib/src/request/request.rs +++ b/core/lib/src/request/request.rs @@ -697,7 +697,7 @@ impl<'r> Request<'r> { impl<'r> Request<'r> { // Only used by doc-tests! Needs to be `pub` because doc-test are external. pub fn example(method: Method, uri: &str, f: F) { - let rocket = Rocket::custom(Config::development().unwrap()); + let rocket = Rocket::custom(Config::development()); let uri = Origin::parse(uri).expect("invalid URI in example"); let mut request = Request::new(&rocket, method, uri); f(&mut request); diff --git a/core/lib/src/request/tests.rs b/core/lib/src/request/tests.rs index 3b997556..af86787e 100644 --- a/core/lib/src/request/tests.rs +++ b/core/lib/src/request/tests.rs @@ -20,7 +20,7 @@ macro_rules! assert_headers { $(expected.entry($key).or_insert(vec![]).append(&mut vec![$($value),+]);)+ // Dispatch the request and check that the headers are what we expect. - let config = Config::development().unwrap(); + let config = Config::development(); let r = Rocket::custom(config); let req = Request::from_hyp(&r, h_method, h_headers, h_uri, h_addr).unwrap(); let actual_headers = req.headers(); diff --git a/core/lib/src/router/collider.rs b/core/lib/src/router/collider.rs index 340e0fd6..f9847d8d 100644 --- a/core/lib/src/router/collider.rs +++ b/core/lib/src/router/collider.rs @@ -401,7 +401,7 @@ mod tests { fn req_route_mt_collide(m: Method, mt1: S1, mt2: S2) -> bool where S1: Into>, S2: Into> { - let rocket = Rocket::custom(Config::development().unwrap()); + let rocket = Rocket::custom(Config::development()); let mut req = Request::new(&rocket, m, Origin::dummy()); if let Some(mt_str) = mt1.into() { if m.supports_payload() { @@ -468,7 +468,7 @@ mod tests { } fn req_route_path_match(a: &'static str, b: &'static str) -> bool { - let rocket = Rocket::custom(Config::development().unwrap()); + let rocket = Rocket::custom(Config::development()); let req = Request::new(&rocket, Get, Origin::parse(a).expect("valid URI")); let route = Route::ranked(0, Get, b.to_string(), dummy_handler); route.matches(&req) diff --git a/core/lib/src/router/mod.rs b/core/lib/src/router/mod.rs index 250563bc..d73eee43 100644 --- a/core/lib/src/router/mod.rs +++ b/core/lib/src/router/mod.rs @@ -228,7 +228,7 @@ mod test { } fn route<'a>(router: &'a Router, method: Method, uri: &str) -> Option<&'a Route> { - let rocket = Rocket::custom(Config::development().unwrap()); + let rocket = Rocket::custom(Config::development()); let request = Request::new(&rocket, method, Origin::parse(uri).unwrap()); let matches = router.route(&request); if matches.len() > 0 { @@ -239,7 +239,7 @@ mod test { } fn matches<'a>(router: &'a Router, method: Method, uri: &str) -> Vec<&'a Route> { - let rocket = Rocket::custom(Config::development().unwrap()); + let rocket = Rocket::custom(Config::development()); let request = Request::new(&rocket, method, Origin::parse(uri).unwrap()); router.route(&request) }