From 8badc73c4b49495b0bf0f331ad0594947712e214 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Sun, 11 Jun 2017 02:20:57 -0700 Subject: [PATCH] Update toml to 0.4. Add Config::get_datetime. --- lib/Cargo.toml | 2 +- lib/src/config/builder.rs | 27 ++++++++++++++++++++++++++- lib/src/config/config.rs | 36 ++++++++++++++++++++++++++++++++---- lib/src/config/error.rs | 21 ++++++++++----------- lib/src/config/mod.rs | 36 ++++++++++++------------------------ 5 files changed, 81 insertions(+), 41 deletions(-) diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 9f48fbd3..a756ad19 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -21,7 +21,7 @@ tls = ["rustls", "hyper-rustls"] yansi = "0.3" log = "0.3" url = "1" -toml = { version = "0.2", default-features = false } +toml = "0.4" num_cpus = "1" state = "0.2.2" time = "0.1" diff --git a/lib/src/config/builder.rs b/lib/src/config/builder.rs index 7ecc68a7..52ac12fc 100644 --- a/lib/src/config/builder.rs +++ b/lib/src/config/builder.rs @@ -319,7 +319,7 @@ impl ConfigBuilder { /// # Panics /// /// Panics if the current working directory cannot be retrieved or if the - /// supplied address or secret key fail to parse. + /// supplied address, secret key, or TLS configuration fail to parse. /// /// # Example /// @@ -336,4 +336,29 @@ impl ConfigBuilder { pub fn unwrap(self) -> Config { self.finalize().expect("ConfigBuilder::unwrap() failed") } + + /// + /// Returns the `Config` structure that was being built by this builder. + /// + /// # 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. + /// + /// # Example + /// + /// ```rust + /// use rocket::config::{Config, Environment}; + /// + /// let config = Config::build(Environment::Staging) + /// .address("127.0.0.1") + /// .expect("the configuration is bad!"); + /// + /// assert_eq!(config.address.as_str(), "127.0.0.1"); + /// ``` + #[inline(always)] + pub fn expect(self, msg: &str) -> Config { + self.finalize().expect(msg) + } } diff --git a/lib/src/config/config.rs b/lib/src/config/config.rs index b7591739..6e289672 100644 --- a/lib/src/config/config.rs +++ b/lib/src/config/config.rs @@ -8,7 +8,8 @@ use std::env; use super::custom_values::*; use {num_cpus, base64}; use config::Environment::*; -use config::{Result, Table, Value, ConfigBuilder, Environment, ConfigError}; +use config::{Result, ConfigBuilder, Environment, ConfigError}; +use config::{Table, Value, Array, Datetime}; use logger::LoggingLevel; use http::Key; @@ -662,9 +663,9 @@ impl Config { /// /// assert!(config.get_slice("numbers").is_ok()); /// ``` - pub fn get_slice(&self, name: &str) -> Result<&[Value]> { + pub fn get_slice(&self, name: &str) -> Result<&Array> { let val = self.extras.get(name).ok_or_else(|| ConfigError::NotFound)?; - val.as_slice().ok_or_else(|| self.bad_type(name, val.type_str(), "a slice")) + val.as_array().ok_or_else(|| self.bad_type(name, val.type_str(), "an array")) } /// Attempts to retrieve the extra named `name` as a table. @@ -695,6 +696,32 @@ impl Config { val.as_table().ok_or_else(|| self.bad_type(name, val.type_str(), "a table")) } + /// Attempts to retrieve the extra named `name` as a datetime value. + /// + /// # Errors + /// + /// If an extra with `name` doesn't exist, returns an `Err` of `NotFound`. + /// If an extra with `name` _does_ exist but is not a datetime, returns a + /// `BadType` error. + /// + /// # Example + /// + /// ```rust + /// use rocket::config::{Config, Environment, Value, Datetime}; + /// + /// let date = "1979-05-27T00:32:00-07:00".parse::().unwrap(); + /// + /// let config = Config::build(Environment::Staging) + /// .extra("my_date", Value::Datetime(date.clone())) + /// .unwrap(); + /// + /// assert_eq!(config.get_datetime("my_date"), Ok(&date)); + /// ``` + pub fn get_datetime(&self, name: &str) -> Result<&Datetime> { + let v = self.extras.get(name).ok_or_else(|| ConfigError::NotFound)?; + v.as_datetime().ok_or_else(|| self.bad_type(name, v.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. @@ -721,7 +748,8 @@ impl Config { impl fmt::Debug for Config { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Config[{}] {{ address: {}, port: {}, workers: {}, log: {:?}", - self.environment, self.address, self.port, self.workers, self.log_level)?; + self.environment, self.address, self.port, self.workers, + self.log_level)?; for (key, value) in self.extras() { write!(f, ", {}: {}", key, value)?; diff --git a/lib/src/config/error.rs b/lib/src/config/error.rs index 17d64ed1..51bc31c1 100644 --- a/lib/src/config/error.rs +++ b/lib/src/config/error.rs @@ -47,8 +47,8 @@ pub enum ConfigError { BadType(String, &'static str, &'static str, PathBuf), /// There was a TOML parsing error. /// - /// Parameters: (toml_source_string, filename, error_list) - ParseError(String, PathBuf, Vec), + /// Parameters: (toml_source_string, filename, error_description, line/col) + ParseError(String, PathBuf, String, Option<(usize, usize)>), /// There was a TOML parsing error in a config environment variable. /// /// Parameters: (env_key, env_value, error) @@ -87,15 +87,14 @@ impl ConfigError { info_!("expected value to be {}, but found {}", White.paint(expected), White.paint(actual)); } - ParseError(ref source, ref filename, ref errors) => { - for error in errors { - let (lo, hi) = error.byte_range; - let (line, col) = error.start; - let error_source = &source[lo..hi]; - - error!("config file failed to parse due to invalid TOML"); - info_!("at {:?}:{}:{}", White.paint(filename), line + 1, col + 1); - trace_!("{:?} - {}", error_source, White.paint(&error.desc)); + ParseError(_, ref filename, ref desc, line_col) => { + error!("config file failed to parse due to invalid TOML"); + info_!("{}", desc); + if let Some((line, col)) = line_col { + info_!("at {:?}:{}:{}", White.paint(filename), + White.paint(line + 1), White.paint(col + 1)); + } else { + info_!("in {:?}", White.paint(filename)); } } BadEnvVal(ref key, ref value, ref error) => { diff --git a/lib/src/config/mod.rs b/lib/src/config/mod.rs index ae1148ba..0dc1d975 100644 --- a/lib/src/config/mod.rs +++ b/lib/src/config/mod.rs @@ -203,7 +203,7 @@ use std::env; use toml; pub use self::custom_values::Limits; -pub use toml::{Array, Table, Value}; +pub use toml::value::{Array, Table, Value, Datetime}; pub use self::error::{ConfigError, ParsingError}; pub use self::environment::Environment; pub use self::config::Config; @@ -391,30 +391,18 @@ impl RocketConfig { /// Parses the configuration from the Rocket.toml file. Also overrides any /// values there with values from the environment. fn parse>(src: String, filename: P) -> Result { - // Get a PathBuf version of the filename. - let path = filename.as_ref().to_path_buf(); + use self::ConfigError::ParseError; // Parse the source as TOML, if possible. - let mut parser = toml::Parser::new(&src); - let toml = parser.parse().ok_or_else(|| { - let source = src.clone(); - let errors = parser.errors.iter() - .map(|error| { - // workaround for poor error messages `toml` - let debug_desc = format!("{:?}", error.desc); - // strip the leading " and trailing " from debug formatting - let desc = debug_desc[1..debug_desc.len() - 1].to_string(); - - ParsingError { - byte_range: (error.lo, error.hi), - start: parser.to_linecol(error.lo), - end: parser.to_linecol(error.hi), - desc: desc - } - }); - - ConfigError::ParseError(source, path.clone(), errors.collect()) - })?; + let path = filename.as_ref().to_path_buf(); + let table = match src.parse::() { + Ok(toml::Value::Table(table)) => table, + Ok(value) => { + let err = format!("expected a table, found {}", value.type_str()); + return Err(ConfigError::ParseError(src, path, err, Some((1, 1)))); + } + Err(e) => return Err(ParseError(src, path, e.to_string(), e.line_col())) + }; // Create a config with the defaults; set the env to the active one. let mut config = RocketConfig::active_default(filename)?; @@ -423,7 +411,7 @@ impl RocketConfig { let mut global = None; // Parse the values from the TOML file. - for (entry, value) in toml { + for (entry, value) in table { // Each environment must be a table. let kv_pairs = match value.as_table() { Some(table) => table,