easy-install 1.3.10

easy-install
use crate::error::{Context, Result};
use github_proxy::Proxy;
use guess_target::Target;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PersistentConfig {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub proxy: Option<Proxy>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub dir: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub target: Option<Target>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub timeout: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub retry: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub upx: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub strip: Option<bool>,
}

pub const DEFAULT_CONFIG_NAME: &str = "ei_config.json";
pub const DEFAULT_CONFIG_DIR: &str = ".ei";

fn get_config_path() -> Result<PathBuf> {
    let exe_path = std::env::current_exe().context("Failed to get executable path")?;
    let exe_dir = exe_path
        .parent()
        .context("Failed to get executable directory")?;
    Ok(exe_dir.join(DEFAULT_CONFIG_NAME))
}

fn get_default_config_path() -> Result<PathBuf> {
    let mut home = dirs::home_dir().context("Failed to get home dir")?;
    home.push(DEFAULT_CONFIG_DIR);
    home.push(DEFAULT_CONFIG_NAME);
    Ok(home)
}

fn read_config(config_path: &PathBuf) -> Result<PersistentConfig> {
    let content = std::fs::read_to_string(config_path)?;
    let c = serde_json::from_str::<PersistentConfig>(&content)?;
    Ok(c)
}

impl PersistentConfig {
    pub fn load() -> Self {
        for get_path in [get_config_path, get_default_config_path] {
            if let Ok(config_path) = get_path()
                && config_path.exists()
                && let Ok(c) = read_config(&config_path)
            {
                return c;
            };
        }

        let default_config = Self::default();
        let _ = default_config.save_quiet(true);
        default_config
    }

    pub fn save_quiet(&self, quiet: bool) -> Result<()> {
        let config_path = get_config_path()?;
        let content =
            serde_json::to_string_pretty(self).context("Failed to serialize configuration")?;
        std::fs::write(&config_path, content).context("Failed to write configuration file")?;
        if !quiet {
            println!("Configuration saved to: {}", config_path.display());
        }
        Ok(())
    }

    pub fn set_proxy(&mut self, proxy: Proxy) {
        self.proxy = Some(proxy);
    }

    pub fn set_dir(&mut self, dir: String) {
        self.dir = Some(dir);
    }

    pub fn set_target(&mut self, target: Target) {
        self.target = Some(target);
    }

    pub fn set_timeout(&mut self, timeout: u64) {
        self.timeout = Some(timeout);
    }
    pub fn set_retry(&mut self, retry: u64) {
        self.retry = Some(retry);
    }
    pub fn set_upx(&mut self, upx: bool) {
        self.upx = Some(upx);
    }
    pub fn set_strip(&mut self, strip: bool) {
        self.strip = Some(strip);
    }
    pub fn display(&self) {
        println!("{}", serde_json::to_string_pretty(self).unwrap_or_default())
    }
}