use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct Config {
pub vm_library_path: PathBuf,
pub metadata_path: PathBuf,
pub ascii_art_path: PathBuf,
pub snapshot_prefix: String,
#[serde(default)]
pub default_iso_path: Option<PathBuf>,
pub default_memory_mb: u32,
pub default_cpu_cores: u32,
pub default_disk_size_gb: u32,
pub default_display: String,
pub default_enable_kvm: bool,
pub confirm_before_launch: bool,
pub enable_multi_gpu_passthrough: bool,
pub default_ivshmem_size_mb: u32,
pub show_gpu_warnings: bool,
pub single_gpu_enabled: bool,
pub single_gpu_auto_tty: bool,
pub single_gpu_dm_override: Option<String>,
pub looking_glass_client_path: Option<PathBuf>,
pub looking_glass_auto_launch: bool,
}
impl Default for Config {
fn default() -> Self {
let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
let config_dir = dirs::config_dir()
.unwrap_or_else(|| home.join(".config"))
.join("vm-curator");
Self {
vm_library_path: home.join("vm-space"),
metadata_path: config_dir.join("metadata"),
ascii_art_path: config_dir.join("ascii"),
snapshot_prefix: "snapshot".to_string(),
default_iso_path: None,
default_memory_mb: 4096,
default_cpu_cores: 2,
default_disk_size_gb: 64,
default_display: "gtk".to_string(),
default_enable_kvm: true,
confirm_before_launch: true,
enable_multi_gpu_passthrough: false,
default_ivshmem_size_mb: 64,
show_gpu_warnings: true,
single_gpu_enabled: false,
single_gpu_auto_tty: false,
single_gpu_dm_override: None,
looking_glass_client_path: None,
looking_glass_auto_launch: true,
}
}
}
impl Config {
pub fn load() -> Result<Self> {
let config_path = Self::config_file_path();
if config_path.exists() {
let content = std::fs::read_to_string(&config_path)
.with_context(|| format!("Failed to read config from {:?}", config_path))?;
toml::from_str(&content)
.with_context(|| format!("Failed to parse config from {:?}", config_path))
} else {
Ok(Self::default())
}
}
pub fn save(&self) -> Result<()> {
let config_path = Self::config_file_path();
if let Some(parent) = config_path.parent() {
std::fs::create_dir_all(parent)
.with_context(|| format!("Failed to create config directory {:?}", parent))?;
}
let content = toml::to_string_pretty(self)
.context("Failed to serialize config")?;
std::fs::write(&config_path, content)
.with_context(|| format!("Failed to write config to {:?}", config_path))?;
Ok(())
}
pub fn config_file_path() -> PathBuf {
dirs::config_dir()
.unwrap_or_else(|| PathBuf::from(".config"))
.join("vm-curator")
.join("config.toml")
}
}