xbp 0.6.0

XBP is a build pack and deployment management tool to deploy, rust, nextjs etc and manage the NGINX configs below it
Documentation
//! configuration management module
//!
//! handles ssh configuration and yaml config file management
//! provides loading and saving of configuration files
//! supports home directory based config storage

use serde::{Deserialize, Serialize};
use std::fs;
use std::io::{self, Write};
use std::path::{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")
}