Rust · 5029 bytes Raw Blame History
1 //! Configuration management for WANDA
2
3 use crate::error::Result;
4 use serde::{Deserialize, Serialize};
5 use std::path::PathBuf;
6 use tracing::{debug, info};
7
8 /// Main WANDA configuration
9 #[derive(Debug, Clone, Serialize, Deserialize)]
10 #[serde(default)]
11 pub struct WandaConfig {
12 /// Config schema version for future migrations
13 pub version: u32,
14 /// Steam-related configuration
15 pub steam: SteamConfig,
16 /// Proton-related configuration
17 pub proton: ProtonConfig,
18 /// WeMod-related configuration
19 pub wemod: WemodConfig,
20 /// Prefix-related configuration
21 pub prefix: PrefixConfig,
22 }
23
24 impl Default for WandaConfig {
25 fn default() -> Self {
26 Self {
27 version: 1,
28 steam: SteamConfig::default(),
29 proton: ProtonConfig::default(),
30 wemod: WemodConfig::default(),
31 prefix: PrefixConfig::default(),
32 }
33 }
34 }
35
36 /// Steam configuration
37 #[derive(Debug, Clone, Serialize, Deserialize, Default)]
38 #[serde(default)]
39 pub struct SteamConfig {
40 /// Override auto-detected Steam installation path
41 pub install_path: Option<PathBuf>,
42 /// Additional Steam library folders to scan
43 pub additional_libraries: Vec<PathBuf>,
44 /// Whether to scan Flatpak Steam installation
45 pub scan_flatpak: bool,
46 }
47
48 /// Proton configuration
49 #[derive(Debug, Clone, Serialize, Deserialize, Default)]
50 #[serde(default)]
51 pub struct ProtonConfig {
52 /// Preferred Proton version (e.g., "GE-Proton9-5")
53 pub preferred_version: Option<String>,
54 /// Additional paths to search for Proton installations
55 pub search_paths: Vec<PathBuf>,
56 }
57
58 /// WeMod configuration
59 #[derive(Debug, Clone, Serialize, Deserialize)]
60 #[serde(default)]
61 pub struct WemodConfig {
62 /// Whether to automatically update WeMod
63 pub auto_update: bool,
64 /// Pin to a specific WeMod version
65 pub version: Option<String>,
66 }
67
68 impl Default for WemodConfig {
69 fn default() -> Self {
70 Self {
71 auto_update: true,
72 version: None,
73 }
74 }
75 }
76
77 /// Prefix configuration
78 #[derive(Debug, Clone, Serialize, Deserialize)]
79 #[serde(default)]
80 pub struct PrefixConfig {
81 /// Custom base path for WANDA prefixes
82 pub base_path: Option<PathBuf>,
83 /// Whether to attempt auto-repair of corrupted prefixes
84 pub auto_repair: bool,
85 }
86
87 impl Default for PrefixConfig {
88 fn default() -> Self {
89 Self {
90 base_path: None,
91 auto_repair: true,
92 }
93 }
94 }
95
96 impl WandaConfig {
97 /// Get the default config file path
98 pub fn default_path() -> PathBuf {
99 dirs::config_dir()
100 .unwrap_or_else(|| PathBuf::from("."))
101 .join("wanda")
102 .join("config.toml")
103 }
104
105 /// Get the default data directory
106 pub fn default_data_dir() -> PathBuf {
107 dirs::data_local_dir()
108 .unwrap_or_else(|| PathBuf::from("."))
109 .join("wanda")
110 }
111
112 /// Get the default cache directory
113 pub fn default_cache_dir() -> PathBuf {
114 dirs::cache_dir()
115 .unwrap_or_else(|| PathBuf::from("."))
116 .join("wanda")
117 }
118
119 /// Load configuration from the default path
120 pub fn load() -> Result<Self> {
121 Self::load_from(&Self::default_path())
122 }
123
124 /// Load configuration from a specific path
125 pub fn load_from(path: &PathBuf) -> Result<Self> {
126 if !path.exists() {
127 debug!("Config file not found at {}, using defaults", path.display());
128 return Ok(Self::default());
129 }
130
131 let content = std::fs::read_to_string(path)?;
132 let config: WandaConfig = toml::from_str(&content)?;
133 debug!("Loaded config from {}", path.display());
134 Ok(config)
135 }
136
137 /// Save configuration to the default path
138 pub fn save(&self) -> Result<()> {
139 self.save_to(&Self::default_path())
140 }
141
142 /// Save configuration to a specific path
143 pub fn save_to(&self, path: &PathBuf) -> Result<()> {
144 // Ensure parent directory exists
145 if let Some(parent) = path.parent() {
146 std::fs::create_dir_all(parent)?;
147 }
148
149 let content = toml::to_string_pretty(self)?;
150 std::fs::write(path, content)?;
151 info!("Saved config to {}", path.display());
152 Ok(())
153 }
154
155 /// Get the prefix base path (custom or default)
156 pub fn prefix_base_path(&self) -> PathBuf {
157 self.prefix
158 .base_path
159 .clone()
160 .unwrap_or_else(|| Self::default_data_dir().join("prefix"))
161 }
162 }
163
164 #[cfg(test)]
165 mod tests {
166 use super::*;
167
168 #[test]
169 fn test_default_config() {
170 let config = WandaConfig::default();
171 assert_eq!(config.version, 1);
172 assert!(config.wemod.auto_update);
173 }
174
175 #[test]
176 fn test_serialize_deserialize() {
177 let config = WandaConfig::default();
178 let toml_str = toml::to_string_pretty(&config).unwrap();
179 let parsed: WandaConfig = toml::from_str(&toml_str).unwrap();
180 assert_eq!(parsed.version, config.version);
181 }
182 }
183