cli.rs (2930B)
1 #![cfg(feature = "cli")] 2 3 use clap::Parser; 4 use config::{Map, Value}; 5 use serde::de::DeserializeOwned; 6 use std::path::{Path, PathBuf}; 7 8 use crate::error::{RuntimeCliError, RuntimeError}; 9 10 pub fn parse_and_load_path<Args, C, FP>(path_of: FP) -> Result<(Args, C), RuntimeError> 11 where 12 Args: Parser, 13 C: DeserializeOwned, 14 FP: Fn(&Args) -> Option<&Path>, 15 { 16 let args = Args::try_parse().map_err(RuntimeCliError::from)?; 17 let path = resolve_path(path_of(&args))?; 18 let cfg = crate::config::load_required_file::<C>(&path)?; 19 Ok((args, cfg)) 20 } 21 22 pub fn parse_and_load_path_with_env_overrides<Args, C, FP, FO>( 23 path_of: FP, 24 env_prefix: Option<&str>, 25 overrides_of: FO, 26 ) -> Result<(Args, C), RuntimeError> 27 where 28 Args: Parser, 29 C: DeserializeOwned, 30 FP: Fn(&Args) -> Option<&Path>, 31 FO: Fn(&Args) -> Option<Map<String, Value>>, 32 { 33 let args = Args::try_parse().map_err(RuntimeCliError::from)?; 34 let path = resolve_path(path_of(&args))?; 35 let cfg = crate::config::load_required_file_with_env_and_overrides::<C>( 36 &path, 37 env_prefix, 38 overrides_of(&args), 39 )?; 40 Ok((args, cfg)) 41 } 42 43 pub fn parse_and_load_path_with_init<Args, C, FP, FL>( 44 path_of: FP, 45 logs_dir_of: FL, 46 default_level: Option<&str>, 47 ) -> Result<(Args, C), RuntimeError> 48 where 49 Args: Parser, 50 C: DeserializeOwned, 51 FP: Fn(&Args) -> Option<&Path>, 52 FL: Fn(&C) -> &str, 53 { 54 let (args, cfg) = parse_and_load_path::<Args, C, FP>(path_of)?; 55 crate::tracing::init_with_logs_dir(Path::new(logs_dir_of(&cfg)), default_level)?; 56 Ok((args, cfg)) 57 } 58 59 pub fn parse_and_load_path_with_env_overrides_and_init<Args, C, FP, FO, FL>( 60 path_of: FP, 61 env_prefix: Option<&str>, 62 overrides_of: FO, 63 logs_dir_of: FL, 64 default_level: Option<&str>, 65 ) -> Result<(Args, C), RuntimeError> 66 where 67 Args: Parser, 68 C: DeserializeOwned, 69 FP: Fn(&Args) -> Option<&Path>, 70 FO: Fn(&Args) -> Option<Map<String, Value>>, 71 FL: Fn(&C) -> &str, 72 { 73 let (args, cfg) = parse_and_load_path_with_env_overrides::<Args, C, FP, FO>( 74 path_of, 75 env_prefix, 76 overrides_of, 77 )?; 78 crate::tracing::init_with_logs_dir(Path::new(logs_dir_of(&cfg)), default_level)?; 79 Ok((args, cfg)) 80 } 81 82 #[inline] 83 fn resolve_path(p: Option<&Path>) -> Result<PathBuf, RuntimeCliError> { 84 p.map(Path::to_path_buf) 85 .ok_or(RuntimeCliError::MissingConfigPath) 86 } 87 88 #[cfg(test)] 89 mod tests { 90 use std::path::PathBuf; 91 92 use super::resolve_path; 93 use crate::RuntimeCliError; 94 95 #[test] 96 fn resolve_path_requires_explicit_path() { 97 let err = resolve_path(None).expect_err("missing path should error"); 98 assert!(matches!(err, RuntimeCliError::MissingConfigPath)); 99 100 let path = PathBuf::from("/tmp/config.toml"); 101 assert_eq!( 102 resolve_path(Some(path.as_path())).expect("path should resolve"), 103 path 104 ); 105 } 106 }