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}
52
53impl Config {
54 pub fn load() -> Result<Self> {
55 debug!("Loadingspsconfiguration");
56 let prefix = determine_prefix();
57 let cellar = prefix.join("Cellar");
58 let taps_dir = prefix.join("Library/Taps");
59 let cache_dir = cache::get_cache_dir()?;
60 let api_base_url = "https://formulae.brew.sh/api".to_string();
61
62 let artifact_domain = env::var("HOMEBREW_ARTIFACT_DOMAIN").ok();
63 let docker_registry_token = env::var("HOMEBREW_DOCKER_REGISTRY_TOKEN").ok();
64 let docker_registry_basic_auth = env::var("HOMEBREW_DOCKER_REGISTRY_BASIC_AUTH_TOKEN").ok();
65 let github_api_token = env::var("HOMEBREW_GITHUB_API_TOKEN").ok();
66
67 if artifact_domain.is_some() {
68 debug!("Loaded HOMEBREW_ARTIFACT_DOMAIN");
69 }
70 if docker_registry_token.is_some() {
71 debug!("Loaded HOMEBREW_DOCKER_REGISTRY_TOKEN");
72 }
73 if docker_registry_basic_auth.is_some() {
74 debug!("Loaded HOMEBREW_DOCKER_REGISTRY_BASIC_AUTH_TOKEN");
75 }
76 if github_api_token.is_some() {
77 debug!("Loaded HOMEBREW_GITHUB_API_TOKEN");
78 }
79
80 debug!("Configuration loaded successfully.");
81 Ok(Self {
82 prefix,
83 cellar,
84 taps_dir,
85 cache_dir,
86 api_base_url,
87 artifact_domain,
88 docker_registry_token,
89 docker_registry_basic_auth,
90 github_api_token,
91 })
92 }
93
94 pub fn prefix(&self) -> &Path {
97 &self.prefix
98 }
99
100 pub fn cellar_path(&self) -> &Path {
101 &self.cellar
102 }
103
104 pub fn caskroom_dir(&self) -> PathBuf {
105 self.prefix.join("Caskroom")
106 }
107
108 pub fn opt_dir(&self) -> PathBuf {
109 self.prefix.join("opt")
110 }
111
112 pub fn bin_dir(&self) -> PathBuf {
113 self.prefix.join("bin")
114 }
115
116 pub fn applications_dir(&self) -> PathBuf {
117 if cfg!(target_os = "macos") {
118 PathBuf::from("/Applications")
119 } else {
120 self.prefix.join("Applications")
121 }
122 }
123
124 pub fn formula_cellar_dir(&self, formula_name: &str) -> PathBuf {
125 self.cellar_path().join(formula_name)
126 }
127
128 pub fn formula_keg_path(&self, formula_name: &str, version_str: &str) -> PathBuf {
129 self.formula_cellar_dir(formula_name).join(version_str)
130 }
131
132 pub fn formula_opt_link_path(&self, formula_name: &str) -> PathBuf {
133 self.opt_dir().join(formula_name)
134 }
135
136 pub fn cask_dir(&self, cask_token: &str) -> PathBuf {
137 self.caskroom_dir().join(cask_token)
138 }
139
140 pub fn cask_version_path(&self, cask_token: &str, version_str: &str) -> PathBuf {
141 self.cask_dir(cask_token).join(version_str)
142 }
143
144 pub fn home_dir(&self) -> PathBuf {
146 dirs::home_dir().unwrap_or_else(|| PathBuf::from("/"))
147 }
148
149 pub fn manpagedir(&self) -> PathBuf {
151 self.prefix.join("share").join("man")
152 }
153
154 pub fn get_tap_path(&self, name: &str) -> Option<PathBuf> {
157 let parts: Vec<&str> = name.split('/').collect();
158 if parts.len() == 2 {
159 Some(
160 self.taps_dir
161 .join(parts[0])
162 .join(format!("homebrew-{}", parts[1])),
163 )
164 } else {
165 None
166 }
167 }
168
169 pub fn get_formula_path_from_tap(&self, tap_name: &str, formula_name: &str) -> Option<PathBuf> {
170 self.get_tap_path(tap_name).and_then(|tap_path| {
171 let json_path = tap_path
172 .join("Formula")
173 .join(format!("{formula_name}.json"));
174 if json_path.exists() {
175 return Some(json_path);
176 }
177 let rb_path = tap_path.join("Formula").join(format!("{formula_name}.rb"));
178 if rb_path.exists() {
179 return Some(rb_path);
180 }
181 None
182 })
183 }
184}
185
186impl Default for Config {
187 fn default() -> Self {
188 Self::load().expect("Failed to load default configuration")
189 }
190}
191
192pub fn load_config() -> Result<Config> {
193 Config::load()
194}