diff --git a/src/lib.rs b/src/lib.rs index cff0de9..2e294ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,30 +2,23 @@ extern crate log; use failure::{bail, Fallible}; +use serde::de::DeserializeOwned; +use serde::Serialize; use std::collections::HashMap; -use std::str::FromStr; -use serde::{Serialize}; use std::fmt::Debug; -use std::path::{Path, PathBuf}; use std::fs::File; use std::io::Read; -use serde::de::DeserializeOwned; +use std::path::{Path, PathBuf}; +use std::str::FromStr; pub const LOG_LEVELS: [&str; 5] = ["error", "warn", "info", "debug", "trace"]; /// 3rd-party libraries that produce log spam - we set these to a fixed higher level /// to allow using e.g. TRACE without drowning our custom messages -pub const SPAMMY_LIBS: [&str; 6] = [ - "tokio_reactor", - "hyper", - "reqwest", - "mio", - "want", - "rumqtt", -]; +pub const SPAMMY_LIBS: [&str; 6] = ["tokio_reactor", "hyper", "reqwest", "mio", "want", "rumqtt"]; /// Implement this for the main config struct -pub trait BoilerplateCfg { +pub trait AppConfig: Sized + Serialize + DeserializeOwned + Debug + Default { type Init; /// Get log level @@ -50,67 +43,64 @@ pub trait BoilerplateCfg { /// Configure the config object using args. /// Logging has already been inited and configured. fn configure<'a>(self, _clap: &clap::ArgMatches<'a>) -> Fallible; -} - -pub trait Boilerplate : BoilerplateCfg + Sized { - fn init(name: &str, cfg_file_name: &str, version : Option) -> Fallible; -} - -fn read_file>(path: P) -> Fallible { - let path = path.as_ref(); - let mut file = File::open(path)?; - - let mut buf = String::new(); - file.read_to_string(&mut buf)?; - Ok(buf) -} -impl Boilerplate for CFG { /// Initialize the app - fn init(name: &str, cfg_file_name: &str, version : Option) -> Fallible - { - let version : String = version.unwrap_or_else(|| env!("CARGO_PKG_VERSION").into()); - let clap = - clap::App::new(name) - .arg(clap::Arg::with_name("config") - .short("c").long("config") + fn init(name: &str, cfg_file_name: &str, version: Option) -> Fallible { + let version: String = version.unwrap_or_else(|| env!("CARGO_PKG_VERSION").into()); + let clap = clap::App::new(name) + .arg( + clap::Arg::with_name("config") + .short("c") + .long("config") .value_name("FILE") .help("Sets a custom config file (JSON5)") - .takes_value(true)) - - .arg(clap::Arg::with_name("dump-config") + .takes_value(true), + ) + .arg( + clap::Arg::with_name("dump-config") .long("dump-config") .takes_value(false) - .help("Print the loaded config struct")) - - .arg(clap::Arg::with_name("default-config") + .help("Print the loaded config struct"), + ) + .arg( + clap::Arg::with_name("default-config") .long("default-config") .takes_value(false) - .help("Print the default config JSON for reference (or to be piped to a file)")) - - .arg(clap::Arg::with_name("verbose") - .short("v").long("verbose").multiple(true) - .help("Increase logging verbosity (repeat to increase)")) - - .arg(clap::Arg::with_name("log-level") + .help("Print the default config JSON for reference (or to be piped to a file)"), + ) + .arg( + clap::Arg::with_name("verbose") + .short("v") + .long("verbose") + .multiple(true) + .help("Increase logging verbosity (repeat to increase)"), + ) + .arg( + clap::Arg::with_name("log-level") .long("log") - .takes_value(true).value_name("LEVEL") + .takes_value(true) + .value_name("LEVEL") .validator(|s| { - if LOG_LEVELS.contains(&s.as_str()) { return Ok(()); } + if LOG_LEVELS.contains(&s.as_str()) { + return Ok(()); + } Err(format!("Bad log level: {}", s)) }) - .help("Set logging verbosity (error,warning,info,debug,trace)")); + .help("Set logging verbosity (error,warning,info,debug,trace)"), + ); let clap = Self::add_args(clap); // this must be done after `add_args` or all hell breaks loose around lifetimes - let clap = clap - .version(version.as_str()); + let clap = clap.version(version.as_str()); let argv = clap.get_matches(); if argv.is_present("default-config") { - println!("{}", serde_json::to_string_pretty(&CFG::default()).unwrap()); + println!( + "{}", + serde_json::to_string_pretty(&Self::default()).unwrap() + ); std::process::exit(0); } @@ -121,15 +111,18 @@ impl Boil let filepath = PathBuf::from_str(cfg_file)?; - let config: CFG = if filepath.is_file() { + let config: Self = if filepath.is_file() { println!("Load config from \"{}\"", cfg_file); let buf = read_file(filepath)?; json5::from_str(&buf)? } else { - println!("Config file \"{}\" does not exist, using defaults.", cfg_file); + println!( + "Config file \"{}\" does not exist, using defaults.", + cfg_file + ); - CFG::default() + Self::default() }; let mut level = config.logging().as_str(); @@ -156,10 +149,7 @@ impl Boil /* Verbosity increased */ if argv.is_present("verbose") { // bump verbosity if -v's are present - let pos = LOG_LEVELS - .iter() - .position(|x| x == &level) - .unwrap(); + let pos = LOG_LEVELS.iter().position(|x| x == &level).unwrap(); level = match LOG_LEVELS .iter() @@ -208,3 +198,12 @@ impl Boil config.configure(&argv) } } + +fn read_file>(path: P) -> Fallible { + let path = path.as_ref(); + let mut file = File::open(path)?; + + let mut buf = String::new(); + file.read_to_string(&mut buf)?; + Ok(buf) +}