Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

brew bundle [install] --cleanup removes dependencies when reading from stdin #1378

Closed
motohedgehog opened this issue Jun 6, 2024 · 4 comments · Fixed by #1379
Closed

brew bundle [install] --cleanup removes dependencies when reading from stdin #1378

motohedgehog opened this issue Jun 6, 2024 · 4 comments · Fixed by #1379
Assignees

Comments

@motohedgehog
Copy link

motohedgehog commented Jun 6, 2024

Overview

I did my best to find any similar bug reports, but couldn't, so here goes.

I've run into a weird brew bundle behaviour while working on declarative package management in my personal dotfiles repo (I use chezmoi).

How To Reproduce

I could reproduce the problem on a pristine macOS 14.5 running under UTM and a clean Homebrew installation.

Suppose I install one formula and one cask:

$ brew install -q tealdeer homebrew/cask/appcleaner

==> Installing Cask appcleaner
==> Moving App 'AppCleaner.app' to '/Applications/AppCleaner.app'
🍺  appcleaner was successfully installed!
==> Fetching tealdeer
==> Caveats
zsh completions have been installed to:
  /opt/homebrew/share/zsh/site-functions
==> Summary
🍺  /opt/homebrew/Cellar/tealdeer/1.6.1: 13 files, 3.9MB
== > Running `brew cleanup tealdeer`...
Dis able this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
==> Caveats
==> tealdeer
zsh completions have been installed to:
  /opt/homebrew/share/zsh/site-functions

I then run brew bundle dump and get my Brewfile:

$ brew bundle dump
==> Tapping homebrew/bundle
Cloning into '/opt/homebrew/Library/Taps/homebrew/homebrew-bundle'...
remote: Enumerating objects: 7993, done.
remote: Counting objects: 100% (2078/2078), done.
remote: Compressing objects: 100% (370/370), done.
remote: Total 7993 (delta 1808), reused 1855 (delta 1702), pack-reused 5915
Receiving objects: 100% (7993/7993), 1.92 MiB | 11.21 MiB/s, done.
Resolving deltas: 100% (4683/4683), done.
Tapped 1 command (109 files, 2.4MB).
Using homebrew/bundle
Homebrew Bundle complete! 3 Brewfile dependencies now installed.

At this point, I expect brew bundle [install] --cleanup to be a no-op. At a first glance, it is:

$ brew bundle --cleanup
Using homebrew/bundle
Using tealdeer
Using appcleaner
Homebrew Bundle complete! 3 Brewfile dependencies now installed.

However, things change if I pass the very same Brewfile via stdin:

$ brew bundle --cleanup --file=- < Brewfile
Using homebrew/bundle
Using tealdeer
Using appcleaner
Homebrew Bundle complete! 3 Brewfile dependencies now installed.

##########################
# Why is this happening? #
##########################
==> Uninstalling Cask appcleaner
==> Removing launchctl service net.freemacsoft.AppCleaner-SmartDelete
Password:
==> Backing App 'AppCleaner.app' up to '/opt/homebrew/Caskroom/appcleaner/3.6.8/
==> Removing App '/Applications/AppCleaner.app'
==> Purging files for version 3.6.8 of Cask appcleaner
Uninstalled 1 cask
Uninstalling tealdeer... (13 files, 3.9MB)
Uninstalled 1 formula

Homebrew says Bundle complete, but then immediately proceeds to remove both the formula and the cask.

Running brew bundle again exhibits even more bizarre behaviour as it install the formula and the cask again, and then removes the cask only:

brew bundle --cleanup --file=-
Using homebrew/bundle
Installing tealdeer
Installing appcleaner
Homebrew Bundle complete! 3 Brewfile dependencies now installed.
==> Uninstalling Cask appcleaner
==> Removing launchctl service net.freemacsoft.AppCleaner-SmartDelete
==> Backing App 'AppCleaner.app' up to '/opt/homebrew/Caskroom/appcleaner/3.6.8/
==> Removing App '/Applications/AppCleaner.app'
==> Purging files for version 3.6.8 of Cask appcleaner
Uninstalled 1 cask

Debug Information

$ brew doctor
Your system is ready to brew.
$ brew config
HOMEBREW_VERSION: 4.3.3
ORIGIN: https://github.com/Homebrew/brew
HEAD: e130e47f23b8b806096f9ec4f2c193213b8ec908
Last commit: 4 days ago
Core tap JSON: 06 Jun 20:57 UTC
Core cask tap JSON: 06 Jun 20:57 UTC
HOMEBREW_PREFIX: /opt/homebrew
HOMEBREW_CASK_OPTS: []
HOMEBREW_MAKE_JOBS: 8
Homebrew Ruby: 3.3.2 => /opt/homebrew/Library/Homebrew/vendor/portable-ruby/3.3.2/bin/ruby
CPU: octa-core 64-bit dunno
Clang: 15.0.0 build 1500
Git: 2.39.3 => /Library/Developer/CommandLineTools/usr/bin/git
Curl: 8.6.0 => /usr/bin/curl
macOS: 14.5-arm64
CLT: 15.3.0.0.1.1708646388
Xcode: N/A
Rosetta 2: false

I hope I am just missing something obvious, but so far I've been puzzled, so any help would be appreciated!

@jacobbednarz
Copy link
Member

i've got a feeling you're redirection isn't actually going to stdin in time. the < Brewfile won't be evaluated until after the command which means stdin would be empty and the behaviour here makes sense.

what does behaviour cat Brewfile | brew bundle --cleanup --file=- give you?

@motohedgehog
Copy link
Author

@jacobbednarz my shell knowledge may be a bit rusty, but I don't think cat file | command vs command < file should make any difference here (a.k.a. "useless use of cat"). I tried you suggestion though, and the behaviour remains the same.

That said, I've got very similar suspicions: an empty Brewfile indeed makes brew bundle [install] --cleanup try and remove any installed packages, so I have a hunch that it may be working in two passes (install, then cleanup) and by the time it reaches the cleanup stage the stdin is already consumed thus making it purge everything. In any case, I don' think it is the expected/desired behaviour.

It's been a while since I did any Ruby so I haven't looked at the implementation TBH.

@MikeMcQuaid MikeMcQuaid self-assigned this Jun 7, 2024
MikeMcQuaid added a commit that referenced this issue Jun 7, 2024
This was previously failing to read a valid `Brewfile` on repeated reads
so attempting to cleanup everything.

Instead, cache the `Brewfile` DSL in the `install` command and pass it
to the `cleanup` command.

Fixes #1378
@MikeMcQuaid
Copy link
Member

by the time it reaches the cleanup stage the stdin is already consumed thus making it purge everything

Exactly this. Fixed in #1379. Thanks for the great report @motohedgehog!

@jacobbednarz
Copy link
Member

nice find!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants