stout-bundle
Brewfile parsing, bundle management, and environment snapshots for declarative package management in Rust.
Keywords: brewfile, bundle, declarative, package-management, snapshot, ruby-parser, rust, homebrew, infrastructure-as-code
Why stout-bundle?
Managing a fleet of developer machines or reproducing an environment shouldn't require running commands one by one. stout-bundle lets you declare your dependencies in a Brewfile and install them with a single command. It also generates Brewfiles from your existing installations and creates named snapshots for rollback.
This crate powers the stout bundle, stout snapshot, and stout lock commands, but it's designed as a general-purpose library for any Rust project that needs to manage sets of packages declaratively.
Features
- Brewfile Parsing — Parse
brew,cask,tap, andmasentries from Brewfiles - Brewfile Generation — Generate Brewfiles from currently installed packages
- Bundle Installation — Install all entries in a Brewfile with dependency resolution
- Bundle Checking — Verify if a Brewfile's requirements are satisfied
- Named Snapshots — Create and restore named package snapshots
- Lockfile Support — Generate lockfiles for reproducible environments
- Ruby DSL Compatibility — Supports standard Homebrew Brewfile syntax
- Custom Directives — Extensible for custom entry types
Installation
Or in your Cargo.toml:
[]
= "0.2"
Quick Start
use Brewfile;
// Parse an existing Brewfile
let brewfile = parse?;
// Print all entries
for entry in brewfile.entries
// Generate from installed packages
let brewfile = from_installed?;
brewfile.save?;
Brewfile Syntax
Standard Homebrew Brewfile syntax is fully supported:
# Taps
tap
tap
tap ,
# Formulas (CLI tools)
brew
brew
brew
brew , restart_service: true
brew , link: true
# Casks (applications)
cask
cask
cask , args: { appdir: }
# Mac App Store apps
mas , id: 497799835
# Custom paths
brew , path:
API Overview
Parsing Brewfiles
use Brewfile;
// Parse from file
let brewfile = parse?;
// Parse from string
let brewfile = parse_str?;
// Parse with custom working directory
let brewfile = parse_with_context?;
Working with Entries
use BrewfileEntry;
for entry in brewfile.entries
Generating Brewfiles
use Brewfile;
// Generate from all installed packages
let brewfile = from_installed?;
// Generate from specific packages
let brewfile = from_packages?;
// Save to file
brewfile.save?;
// Get as string
let content = brewfile.to_string?;
Bundle Operations
use Bundle;
use Index;
let index = open_default?;
let bundle = new;
// Install all entries from a Brewfile
let results = bundle.install.await?;
for result in results
// Check if Brewfile is satisfied (all packages installed)
let is_satisfied = bundle.check?;
if !is_satisfied
// List what would be installed (dry run)
let plan = bundle.plan?;
for entry in plan.to_install
for entry in plan.to_upgrade
Snapshots
use Snapshot;
// Create a named snapshot
let snapshot = create.await?;
println!;
// List all snapshots
let snapshots = list?;
for s in snapshots
// Restore a snapshot
restore.await?;
// Delete a snapshot
delete?;
// Export snapshot as portable archive
export.await?;
import.await?;
Lockfiles
use Lockfile;
// Generate lockfile from current state
let lockfile = generate?;
lockfile.save?;
// Load and verify
let lockfile = load?;
if lockfile.is_current? else
// Restore exact versions from lockfile
lockfile.restore.await?;
Cleanup
use Bundle;
// Remove packages not in the Brewfile
let removed = cleanup.await?;
for pkg in removed
// Preview what would be removed
let to_remove = cleanup_plan?;
for pkg in to_remove
Integration with the Stout Ecosystem
stout-bundle is the automation layer of stout:
- stout-index provides metadata for resolving Brewfile entries
- stout-resolve computes installation plans for bundle operations
- stout-install executes the installations
- stout-cask handles cask entries
- stout-state tracks what's installed for generation and checking
You can use stout-bundle standalone for any project that needs Brewfile parsing or declarative package management.
License
MIT License — see the repository root for details.