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

cmd/uninstall: Add env variable that runs autoremove after uninstalls #13532

Merged

Conversation

apainintheneck
Copy link
Contributor

  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same change?
  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes? Here's an example.
  • Have you successfully run brew style with your changes locally?
  • Have you successfully run brew typecheck with your changes locally?
  • Have you successfully run brew tests with your changes locally?

When HOMEBREW_UNINSTALL_AUTOREMOVE is set, brew autoremove is run after every successful call to brew uninstall. If there are no formulae or casks to uninstall, it exits early (cmd/uninstall.rb:53).

Resolves #13362.

@BrewTestBot
Copy link
Member

Review period will end on 2022-07-11 at 18:35:33 UTC.

@BrewTestBot BrewTestBot added the waiting for feedback Merging is blocked until sufficient time has passed for review label Jul 8, 2022
Copy link
Member

@dawidd6 dawidd6 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love this, great work so far!

Library/Homebrew/cmd/uninstall.rb Outdated Show resolved Hide resolved
@BrewTestBot BrewTestBot removed the waiting for feedback Merging is blocked until sufficient time has passed for review label Jul 11, 2022
@BrewTestBot
Copy link
Member

Review period ended.

@apainintheneck
Copy link
Contributor Author

Okay, I took a stab at moving the autoremove logic out into other files so that we don't have to shell out to brew autoremove from inside of brew uninstall. This needs more testing but I just wanted to get your thoughts on the refactor first. I moved the current logic into formula.rb and uninstall.rb but it could just as easily go into its own file too.

Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great so far! Would love some unit tests for the Formula methods.

@@ -343,6 +343,10 @@ module EnvConfig
default_text: "macOS: `/private/tmp`, Linux: `/tmp`.",
default: HOMEBREW_DEFAULT_TEMP,
},
HOMEBREW_UNINSTALL_AUTOREMOVE: {
description: "If set, `brew autoremove` is run after every successful call to `brew uninstall`.",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I misread this before. I wonder if a HOMEBREW_INSTALL_AUTOREMOVE makes sense to have as well that is run on each install/upgrade/reinstall or whether a HOMEBREW_AUTOREMOVE should do all of these. Thoughts?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no opinion on when exactly we should do this, but I have a strong opinion against having multiple environment variables.

If we do it after multiple commands then it should just be HOMEBREW_AUTOREMOVE.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for me @carlocab. I'll personally enable HOMEBREW_AUTOREMOVE as soon as it's around and will primarily rely on it being used at install time.

Thinking about this more, though: we automatically run brew cleanup at install time so I wonder whether running it at uninstall or cleanup time would be the most sensible implementation of HOMEBREW_AUTOREMOVE?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running it as part of/after brew cleanup makes sense to me 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear you're suggesting running autoremove after install, uninstall, upgrade and reinstall, is that right?

I just took a look at how cleanup is handled internally and it makes me think that a separate autoremove.rb file might be the way to go with this.

Also, HOMEBREW_AUTOREMOVE makes sense to me too.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear you're suggesting running autoremove after install, uninstall, upgrade and reinstall, is that right?

Yes, but I (now) think the thing that should run it after install/upgrade/reinstall is that brew cleanup should run the autoremove logic if HOMEBREW_AUTOREMOVE is set (and also perhaps if --autoremove is passed if people think that makes sense 🤔)? I could see --autoremove being useful for brew bundle cleanup.

Library/Homebrew/formula.rb Outdated Show resolved Hide resolved
When HOMEBREW_UNINSTALL_AUTOREMOVE is set, `brew autoremove` is run
after every successful call to `brew uninstall`.
This allows us to autoremove formulae in the autoremove and
uninstall commands without having to shell out to brew.
This allows us to call that logic internally in other brew
commands instead of having to shell out.
@apainintheneck
Copy link
Contributor Author

apainintheneck commented Jul 14, 2022

Okay, HOMEBREW_UNINSTALL_AUTOREMOVE has been changed to HOMEBREW_AUTOREMOVE as already discussed.

Beyond that all the logic for brew autoremove has been moved into autoremove.rb so that it can easily be run after other commands. I was not able to attach the behavior directly to brew cleanup because that runs multiple times, once for each formula; brew autoremove runs once for all installed formulae.

Also, it seems like there are currently no tests that exercise the autoremove code right now (the only thing being tested before was the arg parser). It's kind of a tricky bit of code to test though. If we're going to be running this after a bunch of other commands, I'd like to at least have a few tests in place just to catch obvious bugs.

@apainintheneck
Copy link
Contributor Author

Ah, and one more thing. It now runs after brew install, brew uninstall, brew upgrade and brew reinstall if HOMEBREW_AUTOREMOVE is set.

module_function

def remove_unused_formulae(dry_run: false)
removable_formulae = unused_formulae_with_no_dependents
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to have some basic unit tests to cover this module. This can wait until after we're agreed on design but would be good to have before PR lands.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I agree.

Library/Homebrew/cmd/reinstall.rb Outdated Show resolved Hide resolved
docs/Manpage.md Outdated
@@ -1945,6 +1945,9 @@ example, run `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just

*Default:* `300`.

- `HOMEBREW_AUTOREMOVE`
<br>If set, calls to `brew install`, `brew upgrade`, `brew reinstall` and `brew uninstall` will automatically remove unused formula dependents.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<br>If set, calls to `brew install`, `brew upgrade`, `brew reinstall` and `brew uninstall` will automatically remove unused formula dependents.
<br>If set, calls to `brew cleanup` and `brew uninstall` will automatically remove unused formula dependents. Unless HOMEBREW_NO_INSTALL_CLEANUP is set, `brew cleanup` will automatically remove unused formula dependents every 30 days.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we were going to test this out for a while first before making it the default. This would make running brew autoremove every 30 days the default. Is that what we want?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, what I was intending with this messaging is "if you set HOMEBREW_AUTOREMOVE and not HOMEBREW_NO_INSTALL_CLEANUP: brew cleanup will start doing brew autoremove periodically".

Cleanup.rb:
- Added #autoremove method
- #autoremove is called in clean when HOMEBREW_AUTOREMOVE is set

Formula.rb:
- Added #unused_formulae_with_no_dependents and helpers

Removed old autoremove.rb module.
Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great! A few tiny optional style nits and some unit tests and I think this is good to go!

Library/Homebrew/cleanup.rb Outdated Show resolved Hide resolved
Library/Homebrew/cmd/uninstall.rb Show resolved Hide resolved
Also, made sure to clear formula cache before
and after autoremoving packages.
Updated docs for:
HOMEBREW_AUTOREMOVE
HOMEBREW_NO_CLEANUP_FORMULAE
@apainintheneck
Copy link
Contributor Author

Okay, I added a few tests to make sure dependent formulae get filtered out before removing them. Would an integration test make sense here or do you think that's enough?

The docs were updated as well for two environment variables.

  • HOMEBREW_AUTOREMOVE : If set, calls to brew cleanup and brew uninstall will automatically remove unused formula dependents and if HOMEBREW_NO_INSTALL_CLEANUP is not set, brew cleanup will start running brew autoremove periodically.
  • HOMEBREW_NO_CLEANUP_FORMULAE : A comma-separated list of formulae. Homebrew will refuse to clean up or autoremove a formula if it appears on this list.

The other main thing that was changed is that two calls to Formula#clear_cache were added to Cleanup#autoremove. These are needed because the cached list of installed formula will get invalidated by a preceding call to brew uninstall and may get invalidated by a preceding call to brew install, brew reinstall or brew upgrade when run periodically after brew cleanup. The formulae cache also gets cleared after autoremoving because the list of installed formula will be invalid again. This is probably not essential (I couldn't find any code that relied on that cache that would run after Cleanup#autoremove) but better safe than sorry, right?

@apainintheneck
Copy link
Contributor Author

apainintheneck commented Jul 19, 2022

I've also been wondering if we should update the tab associated with a formula if it was originally installed as a dependency but then the user tries to install it explicitly later on (installed-as-dependency -> installed-on-request). In theory, that would mean that the user would probably want it to not get included in an autoremove cycle but I'm not sure if changing that behavior would break something else. Just an idea.

@MikeMcQuaid
Copy link
Member

I've also been wondering if we should update the tab associated with a formula if it was originally installed as a dependency but then the user tries to install it explicitly later on

I think we already do? Also, note that "installed as dependency" does not imply "not installed as request"; both can be true.

@apainintheneck apainintheneck added the in progress Maintainers are working on this label Jul 23, 2022
@apainintheneck
Copy link
Contributor Author

I think we already do? Also, note that "installed as dependency" does not imply "not installed as request"; both can be true.

You're absolutely right. I had just missed it.

@apainintheneck apainintheneck force-pushed the add-uninstall-autoremove branch 2 times, most recently from 54bd5d2 to 7bd06f6 Compare July 30, 2022 20:37
@apainintheneck apainintheneck removed the in progress Maintainers are working on this label Jul 31, 2022
Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work here! Happy for this to ship as-is or with tiny suggested changed.

expect(testball2.any_version_installed?).to be true

# When there are no unused dependencies
expect { brew "autoremove" }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally I'd say only have one brew invocation in this test, even if it reduces the coverage a bit, as it's super slow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On my machine there's only like a 5 second difference between running one and two tests and I'm still using this old iMac. Not sure how important that 5 seconds is. But yeah, I can take one out if you want.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think important enough to omit tbh, sorry!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Changed it to only one brew invocation in the integration test.

Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! Merge when ready.

@apainintheneck apainintheneck merged commit 93bf9e5 into Homebrew:master Aug 4, 2022
@github-actions github-actions bot added the outdated PR was locked due to age label Sep 4, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 4, 2022
@apainintheneck apainintheneck deleted the add-uninstall-autoremove branch January 3, 2023 00:30
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
outdated PR was locked due to age
Projects
None yet
Development

Successfully merging this pull request may close these issues.

uninstall should optionally autoremove dependencies
6 participants