Expand description
Kombrucha Library - Rust API for package management
This library provides a programmatic interface to Homebrew package management operations. It enables downstream projects to interact with Homebrew packages, dependencies, and installation metadata without shelling out to the CLI.
§Architecture
- api.rs: Homebrew JSON API client with caching
- cellar.rs: Local Cellar inspection (installed packages)
- download.rs: Parallel bottle downloads from GHCR
- extract.rs: Bottle extraction to Cellar
- symlink.rs: Symlink management for installed packages
- tap.rs: Custom tap management
- receipt.rs: Installation receipt generation and metadata
- platform.rs: Platform detection for bottle selection
- cache.rs: Persistent disk caching of API data
- error.rs: Unified error types
§Key Concepts
§Cellar
The Cellar is Homebrew’s package directory (typically /opt/homebrew/Cellar on macOS).
Each installed package has a directory structure:
/opt/homebrew/Cellar/
ripgrep/
13.0.0/
bin/
lib/
INSTALL_RECEIPT.json§Bottles
Bottles are precompiled .tar.gz archives containing binaries for a specific platform.
The library can download, verify, and extract bottles from GitHub Container Registry (GHCR).
§API Client
The BrewApi client queries Homebrew’s public JSON API for formula metadata,
with in-memory and persistent disk caching.
§Symlinks
After extraction, symlinks make binaries and libraries accessible from standard
directories (e.g., /opt/homebrew/bin/ripgrep → ../Cellar/ripgrep/13.0.0/bin/ripgrep).
§Quick Start
use kombrucha::{BrewApi, cellar};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// List installed packages
let installed = cellar::list_installed()?;
for pkg in installed {
println!("{} {}", pkg.name, pkg.version);
}
// Query package metadata
let api = BrewApi::new()?;
let formula = api.fetch_formula("ripgrep").await?;
println!("{}: {}", formula.name, formula.desc.unwrap_or_default());
Ok(())
}§Common Tasks
§Query Package Information
use kombrucha::BrewApi;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let api = BrewApi::new()?;
// Fetch metadata for a formula
let formula = api.fetch_formula("python").await?;
println!("Name: {}", formula.name);
println!("Version: {}", formula.versions.stable.unwrap_or_default());
println!("Description: {}", formula.desc.unwrap_or_default());
println!("Dependencies: {}", formula.dependencies.join(", "));
Ok(())
}§List Installed Packages
use kombrucha::cellar;
fn main() -> anyhow::Result<()> {
// Get all installed packages
let installed = cellar::list_installed()?;
println!("Installed packages: {}", installed.len());
for pkg in installed {
println!(" {} {}", pkg.name, pkg.version);
}
// Get versions of a specific formula
let versions = cellar::get_installed_versions("python")?;
if !versions.is_empty() {
println!("Python latest: {}", versions[0].version);
}
Ok(())
}§Search for Packages
use kombrucha::BrewApi;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let api = BrewApi::new()?;
// Search across all formulae and casks
let results = api.search("python").await?;
println!("Found {} formulae", results.formulae.len());
for formula in &results.formulae {
println!(" {} - {}", formula.name, formula.desc.as_deref().unwrap_or(""));
}
Ok(())
}§Download and Extract a Bottle
use kombrucha::{BrewApi, download, extract, symlink, cellar};
use std::fs;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let api = BrewApi::new()?;
let client = reqwest::Client::new();
// Fetch formula metadata
let formula = api.fetch_formula("ripgrep").await?;
// Step 1: Download bottle
let bottle_path = download::download_bottle(&formula, None, &client).await?;
println!("Downloaded bottle to: {}", bottle_path.display());
// Step 2: Extract to Cellar
let version = formula.versions.stable.unwrap();
let cellar_dir = extract::extract_bottle(&bottle_path, "ripgrep", &version)?;
println!("Extracted to: {}", cellar_dir.display());
// Step 3: Create symlinks
let linked = symlink::link_formula("ripgrep", &version)?;
println!("Created {} symlinks", linked.len());
// Step 4: Create version-agnostic links
symlink::optlink("ripgrep", &version)?;
Ok(())
}§Read Installation Metadata
use kombrucha::{receipt::InstallReceipt, cellar};
use std::path::Path;
fn main() -> anyhow::Result<()> {
// Read an existing installation's receipt
let cellar_path = cellar::cellar_path().join("ripgrep").join("13.0.0");
let receipt = InstallReceipt::read(&cellar_path)?;
println!("Installed with: {}", receipt.homebrew_version);
println!("Installed on request: {}", receipt.installed_on_request);
println!("Runtime dependencies: {}", receipt.runtime_dependencies.len());
Ok(())
}§Work with Custom Taps
use kombrucha::tap;
fn main() -> anyhow::Result<()> {
// List installed taps
let taps = tap::list_taps()?;
println!("Installed taps: {}", taps.join(", "));
// Parse formula metadata from a tap
let formula_path = tap::tap_directory("user/repo")?
.join("Formula")
.join("mypackage.rb");
if let Some(version) = tap::parse_formula_version(&formula_path)? {
println!("Formula version: {}", version);
}
Ok(())
}§Error Handling
All fallible operations return Result<T>, which is an alias for
std::result::Result<T, BruError>. Common error variants:
BruError::FormulaNotFound- Formula doesn’t exist in HomebrewBruError::ApiError- Network request failedBruError::IoError- File system operation failedBruError::JsonError- JSON parsing failed
use kombrucha::{BrewApi, BruError};
#[tokio::main]
async fn main() {
let api = BrewApi::new().unwrap();
match api.fetch_formula("nonexistent-package").await {
Ok(formula) => println!("Found: {}", formula.name),
Err(BruError::FormulaNotFound(name)) => println!("'{}' not found", name),
Err(e) => eprintln!("Error: {}", e),
}
}§Performance Characteristics
- API queries: ~200-500ms per request (cached in-memory for session, disk cache 24h)
- List installed: 10-50ms on typical systems (depends on number of packages)
- Download bottles: Limited to 8 concurrent downloads; 500 Mbps connection downloads 10 bottles in ~5-10 seconds
- Extract bottles: 50-200ms per bottle (depends on size and disk speed)
- Symlink creation: 10-50ms per formula (parallelized with rayon)
Re-exports§
pub use api::Bottle;pub use api::BrewApi;pub use api::Cask;pub use api::Formula;pub use api::SearchResults;pub use api::Versions;pub use cache::get_cached_casks;pub use cache::get_cached_formulae;pub use cache::store_casks;pub use cache::store_formulae;pub use cellar::InstalledPackage;pub use cellar::RuntimeDependency;pub use cellar::cellar_path;pub use cellar::detect_prefix;pub use cellar::list_installed;pub use download::cache_dir;pub use error::BruError;pub use error::Result;pub use extract::extract_bottle;pub use package_manager::CleanupResult;pub use package_manager::Dependencies;pub use package_manager::HealthCheck;pub use package_manager::InstallResult;pub use package_manager::OutdatedPackage;pub use package_manager::PackageManager;pub use package_manager::ReinstallResult;pub use package_manager::UninstallResult;pub use package_manager::UpgradeResult;pub use receipt::InstallReceipt;pub use symlink::link_formula;pub use symlink::normalize_path;pub use symlink::optlink;pub use symlink::unlink_formula;pub use symlink::unoptlink;pub use tap::get_core_formula_version;pub use tap::list_taps;pub use tap::parse_formula_info;pub use tap::parse_formula_version;
Modules§
- api
- Homebrew JSON API client with in-memory caching.
- cache
- Local disk caching of Homebrew API data.
- cellar
- Homebrew Cellar inspection - reading and analyzing installed packages.
- download
- Bottle download manager with parallel downloads and optional progress tracking.
- error
- Error types for Kombrucha library operations.
- extract
- Bottle extraction and installation to Cellar.
- package_
manager - High-level PackageManager API - unified interface for package management operations.
- platform
- Platform detection for selecting the correct bottle type.
- receipt
- Install receipt generation and metadata.
- symlink
- Symlink management for installed formulae.
- tap
- Homebrew tap management - custom third-party repositories.