2016-01-20 19:46:42 +00:00
use std ::path ::PathBuf ;
pub use clap ::App ;
use clap ::{ Arg , ArgMatches } ;
use log ;
use log ::LogLevelFilter ;
use configuration ::Configuration ;
2016-01-21 17:43:03 +00:00
use error ::RuntimeError ;
use error ::RuntimeErrorKind ;
2016-01-20 19:46:42 +00:00
use logger ::ImagLogger ;
use libimagstore ::store ::Store ;
pub struct Runtime < ' a > {
rtp : PathBuf ,
2016-03-05 12:01:09 +00:00
configuration : Option < Configuration > ,
2016-02-20 20:15:09 +00:00
cli_matches : ArgMatches < ' a > ,
2016-01-20 19:46:42 +00:00
store : Store ,
}
impl < ' a > Runtime < ' a > {
/**
* Gets the CLI spec for the program and retreives the config file path ( or uses the default on
* in $HOME / . imag / config , $XDG_CONFIG_DIR / imag / config or from env ( " $IMAG_CONFIG " )
* and builds the Runtime object with it .
*
* The cli_spec object should be initially build with the ::get_default_cli_builder ( ) function .
*
* /
2016-02-20 20:15:09 +00:00
pub fn new ( cli_spec : App < ' a , ' a > ) -> Result < Runtime < ' a > , RuntimeError > {
2016-01-29 19:36:37 +00:00
use std ::env ;
2016-03-05 11:36:11 +00:00
use std ::error ::Error ;
2016-01-29 19:36:37 +00:00
2016-03-05 12:01:09 +00:00
use configuration ::error ::ConfigErrorKind ;
2016-01-20 19:46:42 +00:00
let matches = cli_spec . get_matches ( ) ;
2016-01-29 19:36:37 +00:00
let rtp : PathBuf = matches . value_of ( " runtimepath " )
. map ( PathBuf ::from )
. unwrap_or_else ( | | {
env ::var ( " HOME " )
. map ( PathBuf ::from )
. map ( | mut p | { p . push ( " .imag " ) ; p } )
. unwrap_or_else ( | _ | {
panic! ( " You seem to be $HOME-less. Please get a $HOME before using this software. We are sorry for you and hope you have some accommodation anyways. " ) ;
} )
} ) ;
2016-01-20 19:46:42 +00:00
let storepath = matches . value_of ( " storepath " )
. map ( PathBuf ::from )
. unwrap_or ( {
let mut spath = rtp . clone ( ) ;
2016-01-28 19:05:43 +00:00
spath . push ( " store " ) ;
2016-01-20 19:46:42 +00:00
spath
} ) ;
2016-03-05 11:36:11 +00:00
let cfg = Configuration ::new ( & rtp ) ;
2016-03-05 12:01:09 +00:00
let cfg = if cfg . is_err ( ) {
let e = cfg . err ( ) . unwrap ( ) ;
if e . kind ( ) ! = ConfigErrorKind ::NoConfigFileFound {
let cause : Option < Box < Error > > = Some ( Box ::new ( e ) ) ;
return Err ( RuntimeError ::new ( RuntimeErrorKind ::Instantiate , cause ) ) ;
} else {
None
}
} else {
Some ( cfg . unwrap ( ) )
} ;
2016-03-05 11:36:11 +00:00
2016-01-21 17:43:03 +00:00
Store ::new ( storepath ) . map ( | store | {
Runtime {
cli_matches : matches ,
2016-03-05 11:36:11 +00:00
configuration : cfg ,
2016-01-21 17:43:03 +00:00
rtp : rtp ,
store : store ,
}
} )
. map_err ( | e | {
RuntimeError ::new ( RuntimeErrorKind ::Instantiate , Some ( Box ::new ( e ) ) )
} )
2016-01-20 19:46:42 +00:00
}
/**
2016-01-21 20:24:20 +00:00
* Get a commandline - interface builder object from ` clap `
*
* This commandline interface builder object already contains some predefined interface flags :
* * - v | - - verbose for verbosity
* * - - debug for debugging
* * - c < file > | - - config < file > for alternative configuration file
* * - r < path > | - - rtp < path > for alternative runtimepath
* * - - store < path > for alternative store path
* Each has the appropriate help text included .
*
* The ` appname ` shall be " imag-<command> " .
2016-01-20 19:46:42 +00:00
* /
pub fn get_default_cli_builder ( appname : & ' a str ,
version : & ' a str ,
about : & ' a str )
2016-02-20 20:15:09 +00:00
-> App < ' a , ' a >
2016-01-20 19:46:42 +00:00
{
App ::new ( appname )
. version ( version )
. author ( " Matthias Beyer <mail@beyermatthias.de> " )
. about ( about )
. arg ( Arg ::with_name ( " verbosity " )
. short ( " v " )
. long ( " verbose " )
. help ( " Enables verbosity " )
. required ( false )
. takes_value ( false ) )
. arg ( Arg ::with_name ( " debugging " )
. long ( " debug " )
. help ( " Enables debugging output " )
. required ( false )
. takes_value ( false ) )
. arg ( Arg ::with_name ( " config " )
. long ( " config " )
. help ( " Path to alternative config file " )
. required ( false )
. takes_value ( true ) )
. arg ( Arg ::with_name ( " runtimepath " )
. long ( " rtp " )
. help ( " Alternative runtimepath " )
. required ( false )
. takes_value ( true ) )
. arg ( Arg ::with_name ( " storepath " )
. long ( " store " )
. help ( " Alternative storepath. Must be specified as full path, can be outside of the RTP " )
. required ( false )
. takes_value ( true ) )
}
2016-01-21 20:24:20 +00:00
/**
* Initialize the internal logger
* /
2016-01-20 19:46:42 +00:00
pub fn init_logger ( & self ) {
let lvl = if self . is_debugging ( ) {
LogLevelFilter ::Debug
} else if self . is_verbose ( ) {
LogLevelFilter ::Info
} else {
LogLevelFilter ::Error
} ;
log ::set_logger ( | max_log_lvl | {
max_log_lvl . set ( lvl ) ;
debug! ( " Init logger with {} " , lvl ) ;
Box ::new ( ImagLogger ::new ( lvl . to_log_level ( ) . unwrap ( ) ) )
} )
. map_err ( | _ | {
panic! ( " Could not setup logger " ) ;
} )
. ok ( ) ;
}
2016-01-21 20:24:20 +00:00
/**
* Get the verbosity flag value
* /
2016-01-20 19:46:42 +00:00
pub fn is_verbose ( & self ) -> bool {
self . cli_matches . is_present ( " verbosity " )
}
2016-01-21 20:24:20 +00:00
/**
* Get the debugging flag value
* /
2016-01-20 19:46:42 +00:00
pub fn is_debugging ( & self ) -> bool {
self . cli_matches . is_present ( " debugging " )
}
2016-01-21 20:24:20 +00:00
/**
* Get the runtimepath
* /
2016-01-20 19:46:42 +00:00
pub fn rtp ( & self ) -> & PathBuf {
& self . rtp
}
2016-01-21 20:24:20 +00:00
/**
* Get the commandline interface matches
* /
2016-01-20 19:46:42 +00:00
pub fn cli ( & self ) -> & ArgMatches {
& self . cli_matches
}
2016-01-21 20:24:20 +00:00
/**
* Get the store object
* /
2016-01-20 19:46:42 +00:00
pub fn store ( & self ) -> & Store {
& self . store
}
}