1use std::env;
3use std::path::{Path, PathBuf};
4
5use dirs;
6use tracing::debug;
7
8use super::cache;
9use super::error::Result; const DEFAULT_LINUX_PREFIX: &str = "/home/linuxbrew/.linuxbrew";
13const DEFAULT_MACOS_INTEL_PREFIX: &str = "/usr/local";
14const DEFAULT_MACOS_ARM_PREFIX: &str = "/opt/homebrew";
15
16fn determine_prefix() -> PathBuf {
19 if let Ok(prefix) = env::var("SPS_PREFIX").or_else(|_| env::var("HOMEBREW_PREFIX")) {
20 debug!("Using prefix from environment variable: {}", prefix);
21 return PathBuf::from(prefix);
22 }
23
24 let default_prefix = if cfg!(target_os = "linux") {
25 DEFAULT_LINUX_PREFIX
26 } else if cfg!(target_os = "macos") {
27 if cfg!(target_arch = "aarch64") {
28 DEFAULT_MACOS_ARM_PREFIX
29 } else {
30 DEFAULT_MACOS_INTEL_PREFIX
31 }
32 } else {
33 "/usr/local/sps"
35 };
36 debug!("Using default prefix for OS/Arch: {}", default_prefix);
37 PathBuf::from(default_prefix)
38}
39
40#[derive(Debug, Clone)]
41pub struct Config {
42 pub prefix: PathBuf,
43 pub cellar: PathBuf,
44 pub taps_dir: PathBuf,
45 pub cache_dir: PathBuf,
46 pub api_base_url: String,
47 pub artifact_domain: Option<String>,
48 pub docker_registry_token: Option<String>,
49 pub docker_registry_basic_auth: Option<String>,
50 pub github_api_token: Option<String>,
51 pub private_cask_store_dir: PathBuf,
52}
53
54impl Config {
55 pub fn load() -> Result<Self> {
56 debug!("Loadingspsconfiguration");
57 let prefix = determine_prefix();
58 let cellar = prefix.join("Cellar");
59 let taps_dir = prefix.join("Library/Taps");
60 let cache_dir = cache::get_cache_dir()?;
61 let api_base_url = "https://formulae.brew.sh/api".to_string();
62
63 let mut private_cask_store_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("/"));
65 private_cask_store_dir.push(".local");
66 private_cask_store_dir.push("share");
67 private_cask_store_dir.push("sps");
68 private_cask_store_dir.push("cask_store");
69
70 let artifact_domain = env::var("HOMEBREW_ARTIFACT_DOMAIN").ok();
71 let docker_registry_token = env::var("HOMEBREW_DOCKER_REGISTRY_TOKEN").ok();
72 let docker_registry_basic_auth = env::var("HOMEBREW_DOCKER_REGISTRY_BASIC_AUTH_TOKEN").ok();
73 let github_api_token = env::var("HOMEBREW_GITHUB_API_TOKEN").ok();
74
75 if artifact_domain.is_some() {
76 debug!("Loaded HOMEBREW_ARTIFACT_DOMAIN");
77 }
78 if docker_registry_token.is_some() {
79 debug!("Loaded HOMEBREW_DOCKER_REGISTRY_TOKEN");
80 }
81 if docker_registry_basic_auth.is_some() {
82 debug!("Loaded HOMEBREW_DOCKER_REGISTRY_BASIC_AUTH_TOKEN");
83 }
84 if github_api_token.is_some() {
85 debug!("Loaded HOMEBREW_GITHUB_API_TOKEN");
86 }
87
88 debug!("Configuration loaded successfully.");
89 Ok(Self {
90 prefix,
91 cellar,
92 taps_dir,
93 cache_dir,
94 api_base_url,
95 artifact_domain,
96 docker_registry_token,
97 docker_registry_basic_auth,
98 github_api_token,
99 private_cask_store_dir,
100 })
101 }
102
103 pub fn prefix(&self) -> &Path {
106 &self.prefix
107 }
108
109 pub fn cellar_path(&self) -> &Path {
110 &self.cellar
111 }
112
113 pub fn caskroom_dir(&self) -> PathBuf {
114 self.prefix.join("Caskroom")
115 }
116
117 pub fn opt_dir(&self) -> PathBuf {
118 self.prefix.join("opt")
119 }
120
121 pub fn bin_dir(&self) -> PathBuf {
122 self.prefix.join("bin")
123 }
124
125 pub fn applications_dir(&self) -> PathBuf {
126 if cfg!(target_os = "macos") {
127 PathBuf::from("/Applications")
128 } else {
129 self.prefix.join("Applications")
130 }
131 }
132
133 pub fn formula_cellar_dir(&self, formula_name: &str) -> PathBuf {
134 self.cellar_path().join(formula_name)
135 }
136
137 pub fn formula_keg_path(&self, formula_name: &str, version_str: &str) -> PathBuf {
138 self.formula_cellar_dir(formula_name).join(version_str)
139 }
140
141 pub fn formula_opt_link_path(&self, formula_name: &str) -> PathBuf {
142 self.opt_dir().join(formula_name)
143 }
144
145 pub fn cask_dir(&self, cask_token: &str) -> PathBuf {
146 self.caskroom_dir().join(cask_token)
147 }
148
149 pub fn cask_token_path(&self, cask_token: &str) -> PathBuf {
151 self.caskroom_dir().join(cask_token)
152 }
153
154 pub fn private_cask_store_base_dir(&self) -> &Path {
156 &self.private_cask_store_dir
157 }
158
159 pub fn private_cask_token_path(&self, cask_token: &str) -> PathBuf {
161 self.private_cask_store_dir.join(cask_token)
162 }
163
164 pub fn private_cask_version_path(&self, cask_token: &str, version_str: &str) -> PathBuf {
166 self.private_cask_token_path(cask_token).join(version_str)
167 }
168
169 pub fn private_cask_app_path(
171 &self,
172 cask_token: &str,
173 version_str: &str,
174 app_name: &str,
175 ) -> PathBuf {
176 self.private_cask_version_path(cask_token, version_str)
177 .join(app_name)
178 }
179
180 pub fn cask_version_path(&self, cask_token: &str, version_str: &str) -> PathBuf {
181 self.cask_dir(cask_token).join(version_str)
182 }
183
184 pub fn home_dir(&self) -> PathBuf {
186 dirs::home_dir().unwrap_or_else(|| PathBuf::from("/"))
187 }
188
189 pub fn manpagedir(&self) -> PathBuf {
191 self.prefix.join("share").join("man")
192 }
193
194 pub fn get_tap_path(&self, name: &str) -> Option<PathBuf> {
197 let parts: Vec<&str> = name.split('/').collect();
198 if parts.len() == 2 {
199 Some(
200 self.taps_dir
201 .join(parts[0])
202 .join(format!("homebrew-{}", parts[1])),
203 )
204 } else {
205 None
206 }
207 }
208
209 pub fn get_formula_path_from_tap(&self, tap_name: &str, formula_name: &str) -> Option<PathBuf> {
210 self.get_tap_path(tap_name).and_then(|tap_path| {
211 let json_path = tap_path
212 .join("Formula")
213 .join(format!("{formula_name}.json"));
214 if json_path.exists() {
215 return Some(json_path);
216 }
217 let rb_path = tap_path.join("Formula").join(format!("{formula_name}.rb"));
218 if rb_path.exists() {
219 return Some(rb_path);
220 }
221 None
222 })
223 }
224}
225
226impl Default for Config {
227 fn default() -> Self {
228 Self::load().expect("Failed to load default configuration")
229 }
230}
231
232pub fn load_config() -> Result<Config> {
233 Config::load()
234}