winbrew_database\config/
types.rs

1use std::collections::HashMap;
2use std::path::PathBuf;
3
4use super::keys::env_override;
5use super::registry;
6use crate::core::env::LOCALAPPDATA;
7pub use crate::models::shared::config::{ConfigSection, ConfigValueSource as ConfigSource};
8use serde::{Deserialize, Serialize};
9
10const FALLBACK_ROOT_PATH: &str = r"C:\winbrew";
11
12#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13pub struct Config {
14    #[serde(default)]
15    pub core: CoreConfig,
16
17    #[serde(default)]
18    pub paths: PathsConfig,
19
20    #[serde(skip, default)]
21    pub env: ConfigEnv,
22
23    #[serde(skip, default)]
24    pub(crate) config_root: Option<PathBuf>,
25}
26
27#[derive(Debug, Clone, Default)]
28pub struct ConfigEnv {
29    values: HashMap<String, String>,
30}
31
32impl ConfigEnv {
33    pub fn capture() -> Self {
34        let mut values = HashMap::new();
35
36        for def in registry::KEYS {
37            if let Some(value) = env_override(def.key) {
38                values.insert(def.key.to_string(), value);
39            }
40        }
41
42        Self { values }
43    }
44
45    pub fn value(&self, key: &str) -> Option<&str> {
46        self.values.get(key).map(String::as_str)
47    }
48
49    pub fn root_override(&self) -> Option<&str> {
50        self.value("paths.root")
51    }
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct CoreConfig {
56    #[serde(default = "default_log_level")]
57    pub log_level: String,
58
59    #[serde(default = "default_file_log_level")]
60    pub file_log_level: String,
61
62    #[serde(default = "default_true")]
63    pub auto_update: bool,
64
65    #[serde(default = "default_true")]
66    pub confirm_remove: bool,
67
68    #[serde(default)]
69    pub default_yes: bool,
70
71    #[serde(default = "default_true")]
72    pub color: bool,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct PathsConfig {
77    #[serde(default = "default_root_path")]
78    pub root: String,
79
80    #[serde(default = "default_packages_path")]
81    pub packages: String,
82
83    #[serde(default = "default_data_path")]
84    pub data: String,
85
86    #[serde(default = "default_logs_path")]
87    pub logs: String,
88
89    #[serde(default = "default_cache_path")]
90    pub cache: String,
91}
92
93impl Default for CoreConfig {
94    fn default() -> Self {
95        Self {
96            log_level: default_log_level(),
97            file_log_level: default_file_log_level(),
98            auto_update: default_true(),
99            confirm_remove: default_true(),
100            default_yes: false,
101            color: default_true(),
102        }
103    }
104}
105
106impl Default for PathsConfig {
107    fn default() -> Self {
108        Self {
109            root: default_root_path(),
110            packages: default_packages_path(),
111            data: default_data_path(),
112            logs: default_logs_path(),
113            cache: default_cache_path(),
114        }
115    }
116}
117
118// Shared serde helper for bool fields that default to true.
119fn default_true() -> bool {
120    true
121}
122
123fn default_log_level() -> String {
124    "info".to_string()
125}
126
127fn default_file_log_level() -> String {
128    "debug,winbrew::core=trace".to_string()
129}
130
131pub fn default_root_path() -> String {
132    std::env::var(LOCALAPPDATA)
133        .map(|local_app_data| {
134            PathBuf::from(local_app_data)
135                .join("winbrew")
136                .to_string_lossy()
137                .into_owned()
138        })
139        .unwrap_or_else(|_| FALLBACK_ROOT_PATH.to_string())
140}
141
142// These path defaults are templates, not final paths.
143// They are expanded from the configured root in core::paths::resolve_template.
144fn default_packages_path() -> String {
145    "${root}\\packages".to_string()
146}
147
148fn default_data_path() -> String {
149    "${root}\\data".to_string()
150}
151
152fn default_logs_path() -> String {
153    "${root}\\data\\logs".to_string()
154}
155
156fn default_cache_path() -> String {
157    "${root}\\data\\cache".to_string()
158}