use std::path::{Path, PathBuf};
#[derive(Debug, Clone)]
pub struct Paths {
pub stout_dir: PathBuf,
pub prefix: PathBuf,
pub cellar: PathBuf,
}
impl Paths {
pub fn default() -> Self {
let stout_dir = dirs::home_dir()
.map(|h| h.join(".stout"))
.unwrap_or_else(|| PathBuf::from(".stout"));
let prefix = detect_homebrew_prefix();
let cellar = prefix.join("Cellar");
Self {
stout_dir,
prefix,
cellar,
}
}
pub fn new(stout_dir: PathBuf, prefix: PathBuf) -> Self {
let cellar = prefix.join("Cellar");
Self {
stout_dir,
prefix,
cellar,
}
}
pub fn config_file(&self) -> PathBuf {
self.stout_dir.join("config.toml")
}
pub fn index_db(&self) -> PathBuf {
self.stout_dir.join("index.db")
}
pub fn manifest(&self) -> PathBuf {
self.stout_dir.join("manifest.json")
}
pub fn installed_file(&self) -> PathBuf {
self.stout_dir.join("state").join("installed.toml")
}
pub fn history_file(&self) -> PathBuf {
self.stout_dir.join("state").join("history.json")
}
pub fn formula_cache(&self) -> PathBuf {
self.stout_dir.join("cache").join("formulas")
}
pub fn download_cache(&self) -> PathBuf {
self.stout_dir.join("cache").join("downloads")
}
pub fn ensure_dirs(&self) -> std::io::Result<()> {
std::fs::create_dir_all(&self.stout_dir)?;
std::fs::create_dir_all(self.stout_dir.join("state"))?;
std::fs::create_dir_all(self.formula_cache())?;
std::fs::create_dir_all(self.download_cache())?;
Ok(())
}
pub fn package_path(&self, name: &str, version: &str) -> PathBuf {
self.cellar.join(name).join(version)
}
pub fn is_installed(&self, name: &str, version: &str) -> bool {
self.package_path(name, version).exists()
}
pub fn installed_versions(&self, name: &str) -> Vec<String> {
let pkg_dir = self.cellar.join(name);
if !pkg_dir.exists() {
return Vec::new();
}
std::fs::read_dir(&pkg_dir)
.ok()
.map(|entries| {
entries
.filter_map(|e| e.ok())
.filter(|e| e.file_type().map(|t| t.is_dir()).unwrap_or(false))
.filter_map(|e| e.file_name().into_string().ok())
.collect()
})
.unwrap_or_default()
}
}
fn detect_homebrew_prefix() -> PathBuf {
let candidates = [
"/opt/homebrew", "/usr/local", "/home/linuxbrew/.linuxbrew", ];
for path in candidates {
let p = Path::new(path);
if p.join("Cellar").exists() {
return p.to_path_buf();
}
}
PathBuf::from("/opt/homebrew")
}
impl Default for Paths {
fn default() -> Self {
Self::default()
}
}