-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
uninstall: refuse when dependents still installed #1082
uninstall: refuse when dependents still installed #1082
Conversation
cdb1e6f
to
01422c3
Compare
Here's what I've tested with: brew install feedgnuplot
brew uninstall gnuplot # check it refuses
brew uninstall --force gnuplot # check it uninstalls
brew uninstall feedgnuplot # check it uninstalls (because nothing depends on it) |
Does it make sense to rename |
dependants_output = dependants.map { |k| "#{k.name} #{k.version}" }.join(", ") | ||
conjugation = dependants.count == 1 ? "is" : "are" | ||
ofail "Refusing to uninstall #{keg} because it is required by #{dependants_output}, which #{conjugation} currently installed." | ||
puts "Remove it anyway with `brew uninstall --force #{keg.name}`." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe You can override this and force removal with brew uninstall --force ...
@penman From my reading this just handles direct and not recursive dependencies. What do you think about handling this recursively? |
@MikeMcQuaid it should handle recursive dependencies! It uses the list of dependencies from the tab, which is based on the recursive dependency list. |
@penman 👏 |
I think the brew code mostly uses "dependent" not "dependant" |
@MikeMcQuaid @ilovezfs so |
Right, I think the two options shouldn't directly interact with each other. |
I wonder if this PR breaks
I'm quite keen to avoid |
Was thinking the same (but we probably don't really want people typing it anyway...). |
As for whether we want people typing it, if you need to uninstall and reinstall something (for example: we didn't bump the revision but someone needs the change), they're going to have to type it, unless we want to force them to uninstall every dependent, which would almost certainly be unnecessary since otherwise there would have been a revision bump. If this PR is merged, that option will very much so be exposed to users whether we like it or not. |
This is the default behaviour of pretty much every other package manager. What makes them different to us? |
If the status quo is the only justification I don't think it's good enough to not implement the functionality. |
We're not managing system components. I'd start there. |
@zmwangx Many of our users would disagree that we don't have anything mission critical. I'm open to different approaches to this functionality but needs to go in and be on by default to be useful. |
When was the last time someone filed an issue due to uninstalling something they shouldn't have? I don't think we actually see that user problem in the wild much since people tend to install things and then leave them alone. If anything this PR will probably inadvertently cause more such issues by sending people on cleaning sprees since uninstall is "safe" now, when in fact due to undeclared dependencies, dependencies hidden behind |
@zmwangx but I bet it fails if you try to uninstall |
That doesn't matter because we track the actual used dependencies. |
We regularly see issues with |
@zmwangx interesting. |
doctor complaining about that is not the same as it causing a user reported issue :) |
I've seen enough of them. I'm also fed up of people complaining in person and on the internets about this being another example of our dependency system being shitty. |
And if in doubt: we should do what other package managers do unless there's a really good reason. |
Be careful what you wish for :) |
Yup, reproduced what @zmwangx described. |
Agree in principle. I might leave one or two for now just to make sure that the options are understood correctly, and move the rest somewhere else. (Although, it sure would be nice if they were just faster 🤔.) |
This was moved to Keg, but looks like I forgot to get rid of it here.
7eaa7bb
to
bb30b01
Compare
I think it's probably still worth just removing them. Agreed about them being faster but integration tests are always going to be significantly slower so I think we really only want one per command. |
Okay, I'll remove the two extra integration tests. (I'm just desperate to get this merged, heh.) However, I'm still very wary of leaving Homebrew with no tests ensuring that it doesn't inadvertently block uninstalling things that shouldn't be blocked. |
I appreciate the concern ❤️ but we'll do some manual testing and you've added some new unit tests which should help here. |
Something else that could be useful is writing out manual tests cases you've done so I can evaluate and rerun them. |
I totally missed these comments. Oops! This should be a pretty complete test: # These probably should all be run with HOMEBREW_BUILD_FROM_SOURCE set.
# There should be no formulae currently installed that depend on ant or rlwrap.
# Run the follow tests as a developer
brew reinstall abcl
brew uninstall ant # should succeed
# Run the following tests as a non-developer
brew reinstall abcl
brew uninstall ant # should fail
brew uninstall --force ant # should fail
brew uninstall --ignore-dependencies ant # should work
brew reinstall abcl
brew uninstall abcl # should work
brew reinstall abcl
brew uninstall ant abcl # should work
brew reinstall
brew uninstall abcl ant # should work
brew reinstall abcl
brew uninstall rlwrap # should work
# To test the fallback for formulae installed before runtime
# dependencies were recorded, delete the runtime_dependencies
# array from the abcl INSTALL_RECEIPT after every `reinstall`. |
#: Check the given <formulae> for missing dependencies. If no <formulae> are | ||
#: given, check all installed brews. | ||
#: | ||
#: If `--hide=`<hidden> is passed, act as if none of <hidden> are installed. | ||
#: <hidden> should be a comma-seperated list of formulae. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: seperated
➡️ separated
Anything else I should be doing that I've missed? |
Sorry, on vacation so will be a bit before I can test/merge this. |
No problem, just making sure. :) |
Great work @alyssais! My testing is all good and I'll merge this tomorrow. |
msg << " required by #{dependents.join(", ")}, which " | ||
msg << (dependents.count == 1 ? "is" : "are") | ||
msg << " currently installed." | ||
ofail msg |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can be in another PR but I reckon a non-fatal version of this message should be printed in the developer case as a "Warning" rather than "Error".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. I'll do a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alyssais Was thinking of releasing a new tag with this in it on Mondayish? Any chance you'll be able to do this over the weekend? If not, no worries and I'll jump in on this before then. Thanks again!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm mostly done already! Just need to fix a test failure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, looking forward to it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MikeMcQuaid in doing this, I think I've identified an (probably very rare) edge case where uninstalling can now result in a crash. Shouldn't take much to fix, but you may want to avoid releasing this until has been. As soon as I've nailed down exactly how to reproduce (should be imminent) I'll open an issue explaining it.
🎉 Great work @alyssais! |
brew tests
with your changes locally?Makes
brew uninstall foo
(but notbrew uninstall --force foo
) refuse to uninstallfoo
if kegs that depend on it are still installed.Closes #934.