1use std::collections::HashMap;
7use std::path::{Path, PathBuf};
8use serde::{Deserialize, Serialize};
9use crate::error::MpsError;
10
11fn default_git_remote() -> String { "origin".into() }
12fn default_git_branch() -> String { "master".into() }
13fn default_command() -> String { "open".into() }
14fn default_type_aliases() -> HashMap<String, String> { HashMap::new() }
15fn default_command_aliases() -> HashMap<String, String> { HashMap::new() }
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct Config {
21 pub mps_dir: PathBuf,
22 pub storage_dir: PathBuf,
23 pub log_file: PathBuf,
24 #[serde(default = "default_git_remote")]
25 pub git_remote: String,
26 #[serde(default = "default_git_branch")]
27 pub git_branch: String,
28 #[serde(default = "default_command")]
30 pub default_command: String,
31 #[serde(default = "default_type_aliases", alias = "aliases")]
34 pub type_aliases: HashMap<String, String>,
35 #[serde(default = "default_command_aliases")]
37 pub command_aliases: HashMap<String, String>,
38}
39
40impl Config {
41 pub fn default_config() -> Result<Self, MpsError> {
43 let home = dirs::home_dir()
44 .ok_or_else(|| MpsError::ConfigInvalid("cannot determine home directory".into()))?;
45 let mps_dir = home.join(".mps");
46 Ok(Config {
47 storage_dir: mps_dir.join("mps"),
48 log_file: mps_dir.join("mps.log"),
49 mps_dir,
50 git_remote: "origin".into(),
51 git_branch: "master".into(),
52 default_command: "open".into(),
53 type_aliases: HashMap::new(),
54 command_aliases: HashMap::new(),
55 })
56 }
57
58 pub fn load(path: &Path) -> Result<Self, MpsError> {
61 if !path.exists() {
62 return Err(MpsError::ConfigNotFound(path.to_path_buf()));
63 }
64 let content = std::fs::read_to_string(path)?;
65
66 let normalised = content
68 .lines()
69 .map(|line| {
70 if let Some(rest) = line.strip_prefix(':') {
71 rest.to_string()
72 } else {
73 line.to_string()
74 }
75 })
76 .collect::<Vec<_>>()
77 .join("\n");
78
79 let cfg: Config = serde_yaml::from_str(&normalised)
80 .map_err(|e| MpsError::ConfigInvalid(e.to_string()))?;
81 Ok(cfg)
82 }
83
84 pub fn init(path: &Path) -> Result<(), MpsError> {
86 if path.exists() {
87 return Ok(());
88 }
89 let cfg = Self::default_config()?;
90 let yaml = serde_yaml::to_string(&cfg)?;
91 std::fs::write(path, yaml)?;
92 Ok(())
93 }
94
95 pub fn ensure_dirs(&self) -> Result<(), MpsError> {
97 std::fs::create_dir_all(&self.mps_dir)?;
98 std::fs::create_dir_all(&self.storage_dir)?;
99 if !self.log_file.exists() {
100 std::fs::write(&self.log_file, "")?;
101 }
102 Ok(())
103 }
104}
105
106pub fn default_config_path() -> PathBuf {
108 std::env::var("MPS_CONFIG")
109 .map(PathBuf::from)
110 .unwrap_or_else(|_| {
111 dirs::home_dir()
112 .unwrap_or_else(|| PathBuf::from("."))
113 .join(".mps_config.yaml")
114 })
115}