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

uninstall: refuse when dependents still installed #1082

Merged
merged 32 commits into from
Nov 11, 2016

Conversation

alyssais
Copy link
Contributor

@alyssais alyssais commented Sep 22, 2016

  • 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 tests with your changes locally?

Makes brew uninstall foo (but not brew uninstall --force foo) refuse to uninstall foo if kegs that depend on it are still installed.

Closes #934.

@alyssais alyssais changed the title uninstall: warn when dependants still installed uninstall: refuse when dependants still installed Sep 22, 2016
@alyssais
Copy link
Contributor Author

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)

@vladshablinsky
Copy link
Contributor

Does it make sense to rename Keg#formula to Keg#to_formula similar to Dependency#to_formula method?

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}`."
Copy link
Member

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 ...

@MikeMcQuaid
Copy link
Member

@penman From my reading this just handles direct and not recursive dependencies. What do you think about handling this recursively?

@alyssais
Copy link
Contributor Author

@MikeMcQuaid it should handle recursive dependencies! It uses the list of dependencies from the tab, which is based on the recursive dependency list.

@MikeMcQuaid
Copy link
Member

@penman 👏

@MikeMcQuaid
Copy link
Member

@penman @ilovezfs made a good point to me privately: this probably shouldn't overload --force (although I realise that was my idea originally) so instead should be something like --ignore-dependents or something?

@ilovezfs
Copy link
Contributor

I think the brew code mostly uses "dependent" not "dependant"

@alyssais
Copy link
Contributor Author

@MikeMcQuaid @ilovezfs so brew uninstall --force would also refuse to uninstall a keg with dependents without --ignore-dependents?

@ilovezfs
Copy link
Contributor

Right, I think the two options shouldn't directly interact with each other.

@DomT4
Copy link
Member

DomT4 commented Sep 23, 2016

I wonder if this PR breaks brew bundle as-is, given brew bundle IIRC doesn't try to remove things in order of leaves but simply alphabetically.

--ignore-dependents or something?

I'm quite keen to avoid dependents or dependants because people will absolutely & regularly mistype that flag. It should be something fairly simple, and less likely to be bashed wrongly into the keyboard.

@MikeMcQuaid
Copy link
Member

I'm quite keen to avoid dependents or dependants because people will absolutely & regularly mistype that flag. It should be something fairly simple, and less likely to be bashed wrongly into the keyboard.

Was thinking the same (but we probably don't really want people typing it anyway...).

@ilovezfs
Copy link
Contributor

ilovezfs commented Sep 24, 2016

--ignore-dependents and --ignore-dependencies (anyone want to volunteer to write a paragraph of documentation for the man page explaining the difference) seem like developer language spilling over into the CLI.

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.

@ilovezfs ilovezfs changed the title uninstall: refuse when dependants still installed uninstall: refuse when dependents still installed Sep 24, 2016
@MikeMcQuaid
Copy link
Member

IMO this is definitely going to be more trouble than its worth

This is the default behaviour of pretty much every other package manager. What makes them different to us?

@MikeMcQuaid
Copy link
Member

The difference is users are accustomed to this behavior and you're going to break user scripts

If the status quo is the only justification I don't think it's good enough to not implement the functionality.

@ilovezfs
Copy link
Contributor

This is the default behaviour of pretty much every other package manager. What makes them different to us?

We're not managing system components. I'd start there.

@MikeMcQuaid
Copy link
Member

@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.

@ilovezfs
Copy link
Contributor

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 behindif build.with? options, and anomalies of the requirement system, it won't actually be safe.

@ilovezfs
Copy link
Contributor

@zmwangx but I bet it fails if you try to uninstall rlwrap, yes?

@MikeMcQuaid
Copy link
Member

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 behindif build.with? options, and anomalies of the requirement system, it won't actually be safe.

That doesn't matter because we track the actual used dependencies.

@MikeMcQuaid
Copy link
Member

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.

We regularly see issues with brew missing output from brew doctor.

@ilovezfs
Copy link
Contributor

@zmwangx interesting.

@ilovezfs
Copy link
Contributor

We regularly see issues with brew missing output from brew doctor.

doctor complaining about that is not the same as it causing a user reported issue :)

@MikeMcQuaid
Copy link
Member

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.

@MikeMcQuaid
Copy link
Member

And if in doubt: we should do what other package managers do unless there's a really good reason.

@ilovezfs
Copy link
Contributor

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 :)

@ilovezfs
Copy link
Contributor

Yup, reproduced what @zmwangx described.

@alyssais
Copy link
Contributor Author

Additionally, I think all the new tests in this file should be made into non-integration tests instead; the integration tests are meant just as an overall smoke test and are too slow to be used for more complex cases like this.

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 🤔.)

@MikeMcQuaid
Copy link
Member

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 🤔.)

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.

@alyssais
Copy link
Contributor Author

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.

@MikeMcQuaid
Copy link
Member

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.

@MikeMcQuaid
Copy link
Member

Something else that could be useful is writing out manual tests cases you've done so I can evaluate and rerun them.

@alyssais
Copy link
Contributor Author

alyssais commented Oct 30, 2016

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.
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: seperated ➡️ separated

@alyssais
Copy link
Contributor Author

alyssais commented Nov 1, 2016

Anything else I should be doing that I've missed?

@MikeMcQuaid
Copy link
Member

Sorry, on vacation so will be a bit before I can test/merge this.

@alyssais
Copy link
Contributor Author

alyssais commented Nov 1, 2016

No problem, just making sure. :)

@MikeMcQuaid
Copy link
Member

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
Copy link
Member

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".

Copy link
Contributor Author

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.

Copy link
Member

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!

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'm mostly done already! Just need to fix a test failure.

Copy link
Member

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!

Copy link
Contributor Author

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.

@MikeMcQuaid MikeMcQuaid merged commit 2ce17a1 into Homebrew:master Nov 11, 2016
@MikeMcQuaid
Copy link
Member

🎉 Great work @alyssais!

@alyssais alyssais deleted the uninstall_dependancy_error branch November 11, 2016 12:59
@Homebrew Homebrew locked and limited conversation to collaborators May 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants