Skip to content

Commit 8bfa497

Browse files
Jerry XieJerry Xie
authored andcommitted
perf: use batch brew install with native parallelism for CLI packages
Replaces the custom parallel worker pool with a simpler batch install approach that leverages Homebrew's native parallel download capability (introduced in Homebrew/brew#20975). Changes: - CLI packages are now installed in a single batch: brew install pkg1 pkg2 pkg3... - Removes 78 lines of complex worker pool code - Casks remain sequential due to TTY/password prompt requirements - Dry-run now shows the actual batch command This aligns with modern Homebrew's HOMEBREW_DOWNLOAD_CONCURRENCY=auto (default since Nov 2025) which handles parallel downloads automatically.
1 parent 1578184 commit 8bfa497

1 file changed

Lines changed: 23 additions & 78 deletions

File tree

internal/brew/brew.go

Lines changed: 23 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ import (
1616
"github.com/openbootdotdev/openboot/internal/ui"
1717
)
1818

19-
const maxWorkers = 1
20-
2119
type OutdatedPackage struct {
2220
Name string
2321
Current string
@@ -208,8 +206,8 @@ func InstallWithProgress(cliPkgs, caskPkgs []string, dryRun bool) (installedForm
208206

209207
if dryRun {
210208
ui.Info("Would install packages:")
211-
for _, p := range cliPkgs {
212-
fmt.Printf(" brew install %s\n", p)
209+
if len(cliPkgs) > 0 {
210+
fmt.Printf(" brew install %s\n", strings.Join(cliPkgs, " "))
213211
}
214212
for _, p := range caskPkgs {
215213
fmt.Printf(" brew install --cask %s\n", p)
@@ -261,17 +259,29 @@ func InstallWithProgress(cliPkgs, caskPkgs []string, dryRun bool) (installedForm
261259
var allFailed []failedJob
262260

263261
if len(newCli) > 0 {
264-
failed := runParallelInstallWithProgress(newCli, progress)
265-
failedSet := make(map[string]bool, len(failed))
266-
for _, f := range failed {
267-
failedSet[f.name] = true
268-
}
269-
for _, p := range newCli {
270-
if !failedSet[p] {
271-
installedFormulae = append(installedFormulae, p)
262+
progress.SetCurrent(fmt.Sprintf("Installing %d CLI packages...", len(newCli)))
263+
ui.Info(fmt.Sprintf("Installing %d CLI packages with native brew parallelism...", len(newCli)))
264+
265+
args := append([]string{"install"}, newCli...)
266+
cmd := brewInstallCmd(args...)
267+
output, err := cmd.CombinedOutput()
268+
outputStr := string(output)
269+
270+
for _, pkg := range newCli {
271+
progress.IncrementWithStatus(true)
272+
if err == nil || !strings.Contains(outputStr, pkg) {
273+
installedFormulae = append(installedFormulae, pkg)
274+
} else {
275+
errMsg := parseBrewError(outputStr)
276+
if errMsg == "" {
277+
errMsg = "install failed"
278+
}
279+
allFailed = append(allFailed, failedJob{
280+
installJob: installJob{name: pkg, isCask: false},
281+
errMsg: errMsg,
282+
})
272283
}
273284
}
274-
allFailed = append(allFailed, failed...)
275285
}
276286

277287
if len(newCask) > 0 {
@@ -366,71 +376,6 @@ type failedJob struct {
366376
errMsg string
367377
}
368378

369-
func runParallelInstallWithProgress(pkgs []string, progress *ui.StickyProgress) []failedJob {
370-
if len(pkgs) == 0 {
371-
return nil
372-
}
373-
374-
jobs := make([]installJob, 0, len(pkgs))
375-
for _, pkg := range pkgs {
376-
jobs = append(jobs, installJob{name: pkg, isCask: false})
377-
}
378-
379-
jobChan := make(chan installJob, len(jobs))
380-
results := make(chan installResult, len(jobs))
381-
382-
var wg sync.WaitGroup
383-
workers := maxWorkers
384-
if len(jobs) < workers {
385-
workers = len(jobs)
386-
}
387-
388-
for i := 0; i < workers; i++ {
389-
wg.Add(1)
390-
go func() {
391-
defer wg.Done()
392-
for job := range jobChan {
393-
progress.SetCurrent(job.name)
394-
start := time.Now()
395-
errMsg := installFormulaWithError(job.name)
396-
elapsed := time.Since(start)
397-
progress.IncrementWithStatus(errMsg == "")
398-
duration := ui.FormatDuration(elapsed)
399-
if errMsg == "" {
400-
progress.PrintLine(" %s %s", ui.Green("✔ "+job.name), ui.Cyan("("+duration+")"))
401-
} else {
402-
progress.PrintLine(" %s %s", ui.Red("✗ "+job.name+" ("+errMsg+")"), ui.Cyan("("+duration+")"))
403-
}
404-
results <- installResult{name: job.name, failed: errMsg != "", isCask: job.isCask, errMsg: errMsg}
405-
}
406-
}()
407-
}
408-
409-
go func() {
410-
for _, job := range jobs {
411-
jobChan <- job
412-
}
413-
close(jobChan)
414-
}()
415-
416-
go func() {
417-
wg.Wait()
418-
close(results)
419-
}()
420-
421-
var failed []failedJob
422-
for result := range results {
423-
if result.failed {
424-
failed = append(failed, failedJob{
425-
installJob: installJob{name: result.name, isCask: result.isCask},
426-
errMsg: result.errMsg,
427-
})
428-
}
429-
}
430-
431-
return failed
432-
}
433-
434379
func installCaskWithProgress(pkg string, progress *ui.StickyProgress) string {
435380
progress.PauseForInteractive()
436381

0 commit comments

Comments
 (0)