feat: improve Homebrew backend with rich search results and JSON details#30
Conversation
Fixes #9 Rewrites the BrewManager search and details to return version and description information alongside every result. ## Search Previously: names only (no version, no description) Now: 1. Names are fetched via `brew search --formula <query>` (fast) 2. A single batch `brew info --json=v2 <name1> <name2>...` call enriches all results with version and description 3. Results are cached in SEARCH_CACHE to avoid repeat CLI calls 4. Respects max_search_results config setting ## Installed Packages Uses `brew list --formula --versions` so the Installed tab shows actual version strings instead of the generic 'Installed' label. ## Updates Uses `brew outdated --verbose` which includes version transition info (e.g. '1.2 (installed 1.1)') in the version column. ## Details Switched from text-parsing `brew info` to structured `brew info --json=v2` parsing, surfacing: Name, Version, Description, Homepage, License, Tap, Dependencies, and Installed Version. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR enhances the Homebrew (brew) package manager backend to return richer, structured package metadata (version/description in search results and structured JSON details), and introduces a new update_packages API on the PackageManager trait for upgrading selected packages.
Changes:
- Homebrew search now enriches
brew searchresults with batchbrew info --json=v2metadata and caches search results. - Homebrew installed/updates lists now surface real version strings (via
brew list --versionsandbrew outdated --verbose). - Adds
PackageManager::update_packages(...)and implements it for Apt/Arch/Brew plusCombinedManager.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| src/managers/mod.rs | Extends PackageManager with update_packages and forwards it through CombinedManager. |
| src/managers/brew.rs | Reworks brew search/details to use JSON metadata; adds caching; improves installed/updates version display; adds brew update_packages. |
| src/managers/arch.rs | Adds Arch implementation of update_packages (pacman vs AUR split). |
| src/managers/apt.rs | Adds Apt implementation of update_packages via apt install --only-upgrade. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Check cache first | ||
| { | ||
| let cache = SEARCH_CACHE.lock().unwrap(); | ||
| if let Some(cached) = cache.get(query) { | ||
| return cached.clone(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Fixed. The cache key in brew.rs is now format!("brew:{}", query) so each backend in a CombinedManager has its own key namespace and searches can't overwrite each other's results.
| // Step 1: get matching package names via `brew search` | ||
| let names: Vec<String> = { | ||
| let output = Command::new("brew") | ||
| .args(["search", "--formula", query]) | ||
| .output() | ||
| .ok(); | ||
| match output { | ||
| Some(o) => String::from_utf8_lossy(&o.stdout) | ||
| .lines() | ||
| .map(|l| l.trim().to_string()) | ||
| .filter(|l| !l.is_empty() && !l.starts_with("==>")) | ||
| .take(30) | ||
| .collect(), |
There was a problem hiding this comment.
Fixed. Config is now loaded before the names-fetch step; take(30) was replaced with take(fetch_limit) where fetch_limit = max_search_results.max(50) so we always return up to the configured maximum after score filtering.
| .filter_map(|line| { | ||
| let mut parts = line.split_whitespace(); | ||
| let name = parts.next()?.to_string(); | ||
| let version = parts.next().unwrap_or("").to_string(); | ||
| Some(Package { | ||
| provider: "brew".to_string(), | ||
| name, | ||
| version, | ||
| description: String::new(), |
There was a problem hiding this comment.
Fixed. In get_installed_details all whitespace-split tokens after the name are now collected and the last one is taken as the version (versions.last().copied().unwrap_or("")), correctly handling formulae installed with multiple parallel versions.
|
|
||
| fn update_packages(&self, terminal: &mut DefaultTerminal, pkgs: &HashSet<String>) -> Result<(), Box<dyn std::error::Error>> { | ||
| for m in &self.managers { | ||
| m.update_packages(terminal, pkgs)?; |
There was a problem hiding this comment.
Fixed. CombinedManager::update_packages now partitions pkgs by manager: for each backend it intersects the input set with that manager's get_installed() result, so only packages that manager actually owns are forwarded to it.
| fn update_packages(&self, terminal: &mut DefaultTerminal, pkgs: &HashSet<String>) -> Result<(), Box<dyn std::error::Error>> { | ||
| let mut pacman_pkgs = HashSet::new(); | ||
| let mut aur_pkgs = HashSet::new(); | ||
| for name in pkgs { | ||
| if name.starts_with("aur/") { aur_pkgs.insert(name.clone()); } else { pacman_pkgs.insert(name.clone()); } | ||
| } | ||
| if !pacman_pkgs.is_empty() { pacman::pacman_install(terminal, &pacman_pkgs)?; } | ||
| if !aur_pkgs.is_empty() { yay::aur_install(terminal, &aur_pkgs, &self.aur_helper)?; } | ||
| Ok(()) |
There was a problem hiding this comment.
Fixed. Replaced the broken aur/ prefix check (AUR package names from search_aur never carry this prefix) with provider-aware routing: when an AUR helper (e.g. yay) is configured, all packages are routed through it — it handles both official-repo and AUR packages transparently. aur_install already strips any aur/ prefix before invoking the helper binary. When no AUR helper is configured, pacman is used exclusively.
…ager partitioning, AUR routing
brew.rs:
- SEARCH_CACHE key now includes the provider ('brew:<query>') so that
CombinedManager searches for different backends don't overwrite each
other's results for the same query string.
- Replaced hardcoded take(30) with take(max_search_results) (with a small
overfetch buffer) so the configured maximum is respected.
- get_installed_details: collect all version tokens from 'brew list
--formula --versions' and take the last one, correctly handling formulae
installed with multiple parallel versions.
mod.rs:
- CombinedManager::update_packages now partitions pkgs by manager: for each
backend it intersects the package set with that manager's get_installed()
result so no backend receives packages it doesn't own.
arch.rs:
- install/update_packages: replaced the broken 'aur/' prefix check (AUR
package names never carry this prefix in practice) with provider-aware
routing: when an AUR helper is configured, route all packages through it
(it handles both official-repo and AUR packages); fall back to pacman
otherwise. aur_install already strips any 'aur/' prefix before invoking
the helper.
Addresses Copilot review comments on PR #30.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Fixes #9
Rewrites the
BrewManagersearch and details to return version and description information alongside every result.Changes
Search: Fetch names via
brew search --formula, then batch-enrich withbrew info --json=v2to add version and description. Respectsmax_search_resultsconfig. Results cached inSEARCH_CACHE.Installed: Uses
brew list --formula --versionsto show actual version strings instead of the genericInstalledlabel.Updates: Uses
brew outdated --verbosefor version transition info (e.g.1.1 < 1.2).Details: Switched from text-parsing to structured
brew info --json=v2, surfacing: Name, Version, Description, Homepage, License, Tap, Dependencies, and Installed Version.