1use std::env;
3use std::path::{Path, PathBuf};
4
5use directories::UserDirs; use tracing::debug;
7
8use super::error::Result; pub const SPS_ROOT: &str = "/opt/sps";
12const SPS_ROOT_MARKER_FILENAME: &str = ".sps_root_v1";
13
14#[derive(Debug, Clone)]
15pub struct Config {
16 pub sps_root: PathBuf, pub api_base_url: String,
18 pub artifact_domain: Option<String>,
19 pub docker_registry_token: Option<String>,
20 pub docker_registry_basic_auth: Option<String>,
21 pub github_api_token: Option<String>,
22}
23
24impl Config {
25 pub fn load() -> Result<Self> {
26 debug!("Loading sps configuration");
27 let sps_root_path = PathBuf::from(SPS_ROOT);
28
29 let api_base_url = "https://formulae.brew.sh/api".to_string();
30
31 let artifact_domain = env::var("HOMEBREW_ARTIFACT_DOMAIN").ok();
32 let docker_registry_token = env::var("HOMEBREW_DOCKER_REGISTRY_TOKEN").ok();
33 let docker_registry_basic_auth = env::var("HOMEBREW_DOCKER_REGISTRY_BASIC_AUTH_TOKEN").ok();
34 let github_api_token = env::var("HOMEBREW_GITHUB_API_TOKEN").ok();
35
36 debug!("Configuration loaded successfully.");
37 Ok(Self {
38 sps_root: sps_root_path,
39 api_base_url,
40 artifact_domain,
41 docker_registry_token,
42 docker_registry_basic_auth,
43 github_api_token,
44 })
45 }
46
47 pub fn sps_root(&self) -> &Path {
48 &self.sps_root
49 }
50
51 pub fn bin_dir(&self) -> PathBuf {
52 self.sps_root.join("bin")
53 }
54
55 pub fn cellar_dir(&self) -> PathBuf {
56 self.sps_root.join("cellar")
57 }
58
59 pub fn cask_room_dir(&self) -> PathBuf {
60 self.sps_root.join("cask_room")
61 }
62
63 pub fn cask_store_dir(&self) -> PathBuf {
64 self.sps_root.join("cask_store")
65 }
66
67 pub fn opt_dir(&self) -> PathBuf {
68 self.sps_root.join("opt")
69 }
70
71 pub fn taps_dir(&self) -> PathBuf {
72 self.sps_root.join("taps")
73 }
74
75 pub fn cache_dir(&self) -> PathBuf {
76 self.sps_root.join("cache")
77 }
78
79 pub fn logs_dir(&self) -> PathBuf {
80 self.sps_root.join("logs")
81 }
82
83 pub fn tmp_dir(&self) -> PathBuf {
84 self.sps_root.join("tmp")
85 }
86
87 pub fn state_dir(&self) -> PathBuf {
88 self.sps_root.join("state")
89 }
90
91 pub fn man_base_dir(&self) -> PathBuf {
92 self.sps_root.join("share").join("man")
93 }
94
95 pub fn sps_root_marker_path(&self) -> PathBuf {
96 self.sps_root.join(SPS_ROOT_MARKER_FILENAME)
97 }
98
99 pub fn applications_dir(&self) -> PathBuf {
100 if cfg!(target_os = "macos") {
101 PathBuf::from("/Applications")
102 } else {
103 self.home_dir().join("Applications")
104 }
105 }
106
107 pub fn formula_cellar_dir(&self, formula_name: &str) -> PathBuf {
108 self.cellar_dir().join(formula_name)
109 }
110
111 pub fn formula_keg_path(&self, formula_name: &str, version_str: &str) -> PathBuf {
112 self.formula_cellar_dir(formula_name).join(version_str)
113 }
114
115 pub fn formula_opt_path(&self, formula_name: &str) -> PathBuf {
116 self.opt_dir().join(formula_name)
117 }
118
119 pub fn cask_room_token_path(&self, cask_token: &str) -> PathBuf {
120 self.cask_room_dir().join(cask_token)
121 }
122
123 pub fn cask_store_token_path(&self, cask_token: &str) -> PathBuf {
124 self.cask_store_dir().join(cask_token)
125 }
126
127 pub fn cask_store_version_path(&self, cask_token: &str, version_str: &str) -> PathBuf {
128 self.cask_store_token_path(cask_token).join(version_str)
129 }
130
131 pub fn cask_store_app_path(
132 &self,
133 cask_token: &str,
134 version_str: &str,
135 app_name: &str,
136 ) -> PathBuf {
137 self.cask_store_version_path(cask_token, version_str)
138 .join(app_name)
139 }
140
141 pub fn cask_room_version_path(&self, cask_token: &str, version_str: &str) -> PathBuf {
142 self.cask_room_token_path(cask_token).join(version_str)
143 }
144
145 pub fn home_dir(&self) -> PathBuf {
146 UserDirs::new().map_or_else(|| PathBuf::from("/"), |ud| ud.home_dir().to_path_buf())
147 }
148
149 pub fn get_tap_path(&self, name: &str) -> Option<PathBuf> {
150 let parts: Vec<&str> = name.split('/').collect();
151 if parts.len() == 2 {
152 Some(
153 self.taps_dir()
154 .join(parts[0])
155 .join(format!("homebrew-{}", parts[1])),
156 )
157 } else {
158 None
159 }
160 }
161
162 pub fn get_formula_path_from_tap(&self, tap_name: &str, formula_name: &str) -> Option<PathBuf> {
163 self.get_tap_path(tap_name).and_then(|tap_path| {
164 let json_path = tap_path
165 .join("Formula")
166 .join(format!("{formula_name}.json"));
167 if json_path.exists() {
168 return Some(json_path);
169 }
170 let rb_path = tap_path.join("Formula").join(format!("{formula_name}.rb"));
171 if rb_path.exists() {
172 return Some(rb_path);
173 }
174 None
175 })
176 }
177}
178
179impl Default for Config {
180 fn default() -> Self {
181 Self::load().expect("Failed to load default configuration")
182 }
183}
184
185pub fn load_config() -> Result<Config> {
188 Config::load()
189}