diff options
Diffstat (limited to 'makima/src/daemon/cli/config.rs')
| -rw-r--r-- | makima/src/daemon/cli/config.rs | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/makima/src/daemon/cli/config.rs b/makima/src/daemon/cli/config.rs new file mode 100644 index 0000000..8199b88 --- /dev/null +++ b/makima/src/daemon/cli/config.rs @@ -0,0 +1,128 @@ +//! CLI configuration management. +//! +//! Handles loading and saving CLI configuration from ~/.makima/config.toml. +//! This is separate from daemon configuration and is used for interactive CLI commands. + +use clap::Args; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::path::PathBuf; + +/// Arguments for setting the API key +#[derive(Args, Debug, Clone)] +pub struct SetKeyArgs { + /// The API key to save + pub api_key: String, +} + +/// Arguments for setting the API URL +#[derive(Args, Debug, Clone)] +pub struct SetUrlArgs { + /// The API URL to save + pub api_url: String, +} + +/// CLI configuration stored in ~/.makima/config.toml +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct CliConfig { + /// API URL for the makima server + #[serde(default = "default_api_url")] + pub api_url: String, + + /// API key for authentication + #[serde(default)] + pub api_key: Option<String>, +} + +fn default_api_url() -> String { + "https://api.makima.jp".to_string() +} + +impl CliConfig { + /// Get the config directory path (~/.makima) + pub fn config_dir() -> Option<PathBuf> { + dirs::home_dir().map(|h| h.join(".makima")) + } + + /// Get the config file path (~/.makima/config.toml) + pub fn config_path() -> Option<PathBuf> { + Self::config_dir().map(|d| d.join("config.toml")) + } + + /// Load CLI config from ~/.makima/config.toml + /// Returns default config if file doesn't exist + pub fn load() -> Self { + let Some(path) = Self::config_path() else { + return Self::default(); + }; + + if !path.exists() { + return Self::default(); + } + + match fs::read_to_string(&path) { + Ok(contents) => { + toml::from_str(&contents).unwrap_or_else(|e| { + eprintln!("Warning: Failed to parse {}: {}", path.display(), e); + Self::default() + }) + } + Err(e) => { + eprintln!("Warning: Failed to read {}: {}", path.display(), e); + Self::default() + } + } + } + + /// Save CLI config to ~/.makima/config.toml + pub fn save(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> { + let Some(dir) = Self::config_dir() else { + return Err("Could not determine home directory".into()); + }; + + let Some(path) = Self::config_path() else { + return Err("Could not determine config path".into()); + }; + + // Create config directory if it doesn't exist + if !dir.exists() { + fs::create_dir_all(&dir)?; + } + + let contents = toml::to_string_pretty(self) + .map_err(|e| format!("Failed to serialize config: {}", e))?; + fs::write(&path, contents)?; + + Ok(()) + } + + /// Get API key, preferring environment variable over config file + pub fn get_api_key(&self) -> Option<String> { + // Environment variable takes precedence + if let Ok(key) = std::env::var("MAKIMA_API_KEY") { + if !key.is_empty() { + return Some(key); + } + } + + // Fall back to config file + self.api_key.clone() + } + + /// Get API URL, preferring environment variable over config file + pub fn get_api_url(&self) -> String { + // Environment variable takes precedence + if let Ok(url) = std::env::var("MAKIMA_API_URL") { + if !url.is_empty() { + return url; + } + } + + // Fall back to config file, or default if empty + if self.api_url.is_empty() { + default_api_url() + } else { + self.api_url.clone() + } + } +} |
