diff --git a/bin/miden-cli/src/commands/account.rs b/bin/miden-cli/src/commands/account.rs index f276b2a5d..179423ef4 100644 --- a/bin/miden-cli/src/commands/account.rs +++ b/bin/miden-cli/src/commands/account.rs @@ -9,7 +9,7 @@ use miden_client::{Client, PrettyPrint, ZERO}; use crate::config::CliConfig; use crate::errors::CliError; -use crate::utils::{load_config_file, load_faucet_details_map, parse_account_id}; +use crate::utils::{get_cli_config, load_faucet_details_map, parse_account_id}; use crate::{client_binary_name, create_dynamic_table}; pub const DEFAULT_ACCOUNT_ID_KEY: &str = "default_account_id"; @@ -41,7 +41,7 @@ pub struct AccountCmd { impl AccountCmd { pub async fn execute(&self, mut client: Client) -> Result<(), CliError> { - let (cli_config, _) = load_config_file()?; + let cli_config = get_cli_config()?; match self { AccountCmd { list: false, @@ -50,7 +50,7 @@ impl AccountCmd { .. } => { let account_id = parse_account_id(&client, id).await?; - show_account(client, account_id, &cli_config, self.with_code).await?; + show_account(client, account_id, cli_config, self.with_code).await?; }, AccountCmd { list: false, diff --git a/bin/miden-cli/src/commands/new_account.rs b/bin/miden-cli/src/commands/new_account.rs index 23f90feef..9d12a7f35 100644 --- a/bin/miden-cli/src/commands/new_account.rs +++ b/bin/miden-cli/src/commands/new_account.rs @@ -23,7 +23,7 @@ use tracing::debug; use crate::commands::account::set_default_account_if_unset; use crate::errors::CliError; -use crate::{CliKeyStore, client_binary_name, load_config_file}; +use crate::{CliKeyStore, client_binary_name, get_cli_config}; // CLI TYPES // ================================================================================================ @@ -200,7 +200,7 @@ impl NewAccountCmd { /// Reads component templates from the given file paths. // TODO: IO errors should have more context fn load_component_templates(paths: &[PathBuf]) -> Result, CliError> { - let (cli_config, _) = load_config_file()?; + let cli_config = get_cli_config()?; let components_base_dir = &cli_config.component_template_directory; let mut templates = Vec::new(); for path in paths { diff --git a/bin/miden-cli/src/commands/new_transactions.rs b/bin/miden-cli/src/commands/new_transactions.rs index bec480545..bf1c43c47 100644 --- a/bin/miden-cli/src/commands/new_transactions.rs +++ b/bin/miden-cli/src/commands/new_transactions.rs @@ -28,8 +28,8 @@ use crate::create_dynamic_table; use crate::errors::CliError; use crate::utils::{ SHARED_TOKEN_DOCUMENTATION, + get_cli_config, get_input_acc_id_by_prefix_or_default, - load_config_file, load_faucet_details_map, parse_account_id, }; @@ -411,7 +411,7 @@ async fn execute_transaction( .collect::>(); if delegated_proving { - let (cli_config, _) = load_config_file()?; + let cli_config = get_cli_config()?; let remote_prover_endpoint = cli_config.remote_prover_endpoint.as_ref().ok_or(CliError::Config( "Remote prover endpoint".to_string().into(), diff --git a/bin/miden-cli/src/info.rs b/bin/miden-cli/src/info.rs index 916f50bc8..93d9cc834 100644 --- a/bin/miden-cli/src/info.rs +++ b/bin/miden-cli/src/info.rs @@ -8,12 +8,12 @@ use miden_client::store::NoteFilter; use super::config::CliConfig; use crate::commands::account::DEFAULT_ACCOUNT_ID_KEY; use crate::errors::CliError; -use crate::load_config_file; +use crate::get_cli_config; pub async fn print_client_info( client: &Client, ) -> Result<(), CliError> { - let (config, _) = load_config_file()?; + let config = get_cli_config()?; println!("Client version: {}", env!("CARGO_PKG_VERSION")); print_config_stats(&config)?; diff --git a/bin/miden-cli/src/lib.rs b/bin/miden-cli/src/lib.rs index b6fb7dc3d..6b82d1ef0 100644 --- a/bin/miden-cli/src/lib.rs +++ b/bin/miden-cli/src/lib.rs @@ -27,7 +27,7 @@ use commands::sync::SyncCmd; use commands::tags::TagsCmd; use commands::transactions::TransactionCmd; -use self::utils::load_config_file; +use self::utils::get_cli_config; pub type CliKeyStore = FilesystemKeyStore; @@ -168,7 +168,7 @@ impl Cli { }; // Create the client - let (cli_config, _config_path) = load_config_file()?; + let cli_config = get_cli_config()?; let keystore = CliKeyStore::new(cli_config.secret_keys_directory.clone()) .map_err(CliError::KeyStore)?; diff --git a/bin/miden-cli/src/utils.rs b/bin/miden-cli/src/utils.rs index f4ca52947..757a2ff02 100644 --- a/bin/miden-cli/src/utils.rs +++ b/bin/miden-cli/src/utils.rs @@ -1,4 +1,5 @@ use std::path::{Path, PathBuf}; +use std::sync::OnceLock; use figment::Figment; use figment::providers::{Format, Toml}; @@ -77,18 +78,26 @@ pub(crate) async fn parse_account_id( } } -/// Loads config file from current directory and default filename and returns it alongside its path. -/// -/// This function will look for the configuration file at the provided path. If the path is -/// relative, searches in parent directories all the way to the root as well. -pub(super) fn load_config_file() -> Result<(CliConfig, PathBuf), CliError> { - let mut current_dir = std::env::current_dir()?; +// CACHED CONFIG +// ================================================================================================ + +static CLI_CONFIG: OnceLock = OnceLock::new(); + +/// Returns a reference to the global CLI configuration, loading it once on first access. +pub fn get_cli_config() -> Result<&'static CliConfig, CliError> { + // Resolve config path relative to current working directory + let mut current_dir = std::env::current_dir().map_err(CliError::IO)?; current_dir.push(CLIENT_CONFIG_FILE_NAME); - let config_path = current_dir.as_path(); + let config_path = current_dir; - let cli_config = load_config(config_path)?; + if let Some(cfg) = CLI_CONFIG.get() { + return Ok(cfg); + } - Ok((cli_config, config_path.into())) + let cfg = load_config(config_path.as_path())?; + // If another thread initialized first, ignore the error and return the stored one + let _ = CLI_CONFIG.set(cfg); + Ok(CLI_CONFIG.get().expect("CLI_CONFIG must be initialized")) } /// Loads the client configuration. @@ -100,6 +109,6 @@ fn load_config(config_file: &Path) -> Result { /// Returns the faucet details map using the config file. pub fn load_faucet_details_map() -> Result { - let (config, _) = load_config_file()?; - FaucetDetailsMap::new(config.token_symbol_map_filepath) + let config = get_cli_config()?; + FaucetDetailsMap::new(config.token_symbol_map_filepath.clone()) }