use serde::{Deserialize, Serialize};
use std::env;
use std::fs;
use std::path::PathBuf;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SshConfig {
pub password: Option<String>,
pub username: Option<String>,
pub host: Option<String>,
pub project_dir: Option<String>,
}
impl SshConfig {
pub fn new() -> Self {
SshConfig {
password: None,
username: None,
host: None,
project_dir: None,
}
}
pub fn load() -> Result<Self, String> {
let config_path = get_config_path();
if !config_path.exists() {
return Ok(SshConfig::new());
}
let content = fs::read_to_string(&config_path)
.map_err(|e| format!("Failed to read config file: {}", e))?;
serde_yaml::from_str(&content).map_err(|e| format!("Failed to parse config file: {}", e))
}
pub fn save(&self) -> Result<(), String> {
let config_path = get_config_path();
let config_dir = config_path.parent().ok_or("Invalid config path")?;
fs::create_dir_all(config_dir)
.map_err(|e| format!("Failed to create config directory: {}", e))?;
let content = serde_yaml::to_string(self)
.map_err(|e| format!("Failed to serialize config: {}", e))?;
fs::write(&config_path, content).map_err(|e| format!("Failed to write config file: {}", e))
}
}
fn get_config_path() -> PathBuf {
dirs::home_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join(".xbp")
.join("config.yaml")
}
const DEFAULT_API_XBP_URL: &str = "https://api.xbp.app";
#[derive(Debug, Clone)]
pub struct ApiConfig {
base_url: String,
}
impl ApiConfig {
pub fn load() -> Self {
let raw_url = env::var("API_XBP_URL").unwrap_or_else(|_| DEFAULT_API_XBP_URL.to_string());
let base_url = Self::normalize_base_url(&raw_url);
ApiConfig { base_url }
}
pub fn base_url(&self) -> &str {
&self.base_url
}
pub fn version_endpoint(&self, project_name: &str) -> String {
format!("{}/version?project_name={}", self.base_url, project_name)
}
pub fn increment_endpoint(&self) -> String {
format!("{}/version/increment", self.base_url)
}
fn normalize_base_url(raw: &str) -> String {
let trimmed = raw.trim();
if trimmed.is_empty() {
return DEFAULT_API_XBP_URL.to_string();
}
let trimmed = trimmed.trim_end_matches('/');
if trimmed.is_empty() {
return DEFAULT_API_XBP_URL.to_string();
}
trimmed.to_string()
}
}