use clap::Parser; use crate::config::config_file::ConfigFile; use crate::config::error::ConfigurationError; use crate::config::logging::LoggingConfiguration; use crate::config::runtime::RuntimeConfiguration; use crate::config::command_line::ClientArguments; pub use crate::config::command_line::ClientCommand; use std::ffi::OsString; use tracing_core::LevelFilter; pub struct ClientConfiguration { pub runtime: RuntimeConfiguration, pub logging: LoggingConfiguration, config_file: Option, command: ClientCommand, } impl ClientConfiguration { /// Load a basic client configuration for this run. /// /// This will parse the process's command line arguments, and parse /// a config file if given, but will not interpret this information /// beyond that required to understand the user's goals for the /// runtime system and logging. For this reason, it is not async, /// as it is responsible for determining all the information we /// will use to generate the runtime. pub fn new(args: I) -> Result where I: IntoIterator, T: Into + Clone, { let mut command_line_arguments = ClientArguments::try_parse_from(args)?; let mut config_file = ConfigFile::new(command_line_arguments.arguments.config_file.take())?; let mut runtime = RuntimeConfiguration::default(); let mut logging = LoggingConfiguration::default(); // we prefer the command line to the config file, so first merge // in the config file so that when we later merge the command line, // it overwrites any config file options. if let Some(config_file) = config_file.as_mut() { config_file.merge_standard_options_into(&mut runtime, &mut logging); } command_line_arguments.arguments.merge_standard_options_into(&mut runtime, &mut logging); if command_line_arguments.command.is_list_command() { logging.filter = LevelFilter::ERROR; } Ok(ClientConfiguration { runtime, logging, config_file, command: command_line_arguments.command, }) } // Returns the command we received from the user pub fn command(&self) -> &ClientCommand { &self.command } }