rustpm 0.2.0

A fast, friendly APT frontend with kernel, desktop, and sources management
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;

#[derive(Debug, Serialize, Deserialize, Default)]
pub struct Config {
    #[serde(default = "default_true")]
    pub color: bool,
    #[serde(default = "default_true")]
    pub auto_update_grub: bool,
    #[serde(default)]
    pub kernel_filter: KernelFilter,
    #[serde(default = "default_history_max")]
    pub history_max_entries: usize,
    #[serde(default)]
    pub updates: UpdateConfig,
}

#[derive(Debug, Serialize, Deserialize, Default)]
pub struct KernelFilter {
    pub hide_debug: bool,
    pub hide_unsigned: bool,
    pub hide_rt: bool,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct UpdateConfig {
    #[serde(default = "default_true")]
    pub check_enabled: bool,
    #[serde(default = "default_update_url")]
    pub check_url: String,
    pub last_checked: Option<String>,
    #[serde(default = "default_check_interval")]
    pub check_interval_hours: u64,
}

impl Default for UpdateConfig {
    fn default() -> Self {
        Self {
            check_enabled: true,
            check_url: default_update_url(),
            last_checked: None,
            check_interval_hours: 24,
        }
    }
}

fn default_true() -> bool { true }
fn default_history_max() -> usize { 50 }
fn default_check_interval() -> u64 { 24 }
fn default_update_url() -> String {
    "https://crates.io/api/v1/crates/rustpm".to_string()
}

fn config_path() -> PathBuf {
    let home = std::env::var("HOME").unwrap_or_else(|_| "/root".to_string());
    PathBuf::from(home).join(".config").join("rustpm").join("config.toml")
}

impl Config {
    pub fn load() -> Result<Self> {
        let path = config_path();
        if !path.exists() {
            return Ok(Self::default());
        }
        let content = fs::read_to_string(&path)?;
        Ok(toml::from_str(&content)?)
    }

    pub fn save(&self) -> Result<()> {
        let path = config_path();
        if let Some(parent) = path.parent() {
            fs::create_dir_all(parent)?;
        }
        fs::write(&path, toml::to_string_pretty(self)?)?;
        Ok(())
    }
}