diff options
| author | Alyssa Ross | 2016-09-22 13:27:33 +0100 |
|---|---|---|
| committer | Alyssa Ross | 2016-10-25 22:34:34 +0100 |
| commit | 6f0aabe70700654fdd19d1800fa61f4cdea25266 (patch) | |
| tree | 16b58f43e35c8902175221dc41d19f8622b39b91 | |
| parent | 3f3fa4d0f7d5c28598fb7a2495d01efa35c7f7a2 (diff) | |
| download | brew-6f0aabe70700654fdd19d1800fa61f4cdea25266.tar.bz2 | |
uninstall: refuse when dependants still installed
Closes #934.
| -rw-r--r-- | Library/Homebrew/cmd/uninstall.rb | 9 | ||||
| -rw-r--r-- | Library/Homebrew/formula.rb | 7 | ||||
| -rw-r--r-- | Library/Homebrew/keg.rb | 15 | ||||
| -rw-r--r-- | Library/Homebrew/test/test_keg.rb | 69 |
4 files changed, 93 insertions, 7 deletions
diff --git a/Library/Homebrew/cmd/uninstall.rb b/Library/Homebrew/cmd/uninstall.rb index 8bcfc31fb..3d40c2350 100644 --- a/Library/Homebrew/cmd/uninstall.rb +++ b/Library/Homebrew/cmd/uninstall.rb @@ -16,6 +16,15 @@ module Homebrew if !ARGV.force? ARGV.kegs.each do |keg| + dependants = keg.installed_dependants + if dependants.any? + 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}`." + next + end + keg.lock do puts "Uninstalling #{keg}... (#{keg.abv})" keg.unlink diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 69cab88c4..c2467b7bc 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -1337,6 +1337,13 @@ class Formula end end + # Clear caches of .racks and .installed. + # @private + def self.clear_cache + @racks = nil + @installed = nil + end + # An array of all racks currently installed. # @private def self.racks diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb index d2c9e12e8..0f58d688c 100644 --- a/Library/Homebrew/keg.rb +++ b/Library/Homebrew/keg.rb @@ -292,6 +292,21 @@ class Keg PkgVersion.parse(path.basename.to_s) end + def formula + Formulary.from_keg(self) + end + + def installed_dependants + Formula.installed.flat_map(&:installed_kegs).select do |keg| + Tab.for_keg(keg).runtime_dependencies.any? do |dep| + # Resolve formula rather than directly comparing names + # in case of conflicts between formulae from different taps. + dep_formula = Formulary.factory(dep["full_name"]) + dep_formula == formula && dep["version"] == version.to_s + end + end + end + def find(*args, &block) path.find(*args, &block) end diff --git a/Library/Homebrew/test/test_keg.rb b/Library/Homebrew/test/test_keg.rb index 3abf3fc27..41ccb27ee 100644 --- a/Library/Homebrew/test/test_keg.rb +++ b/Library/Homebrew/test/test_keg.rb @@ -5,15 +5,22 @@ require "stringio" class LinkTests < Homebrew::TestCase include FileUtils - def setup - keg = HOMEBREW_CELLAR.join("foo", "1.0") - keg.join("bin").mkpath + def setup_test_keg(name, version) + path = HOMEBREW_CELLAR.join(name, version) + path.join("bin").mkpath %w[hiworld helloworld goodbye_cruel_world].each do |file| - touch keg.join("bin", file) + touch path.join("bin", file) end - @keg = Keg.new(keg) + keg = Keg.new(path) + @kegs ||= [] + @kegs << keg + keg + end + + def setup + @keg = setup_test_keg("foo", "1.0") @dst = HOMEBREW_PREFIX.join("bin", "helloworld") @nonexistent = Pathname.new("/some/nonexistent/path") @@ -27,8 +34,10 @@ class LinkTests < Homebrew::TestCase end def teardown - @keg.unlink - @keg.uninstall + @kegs.each do |keg| + keg.unlink + keg.uninstall + end $stdout = @old_stdout @@ -305,3 +314,49 @@ class LinkTests < Homebrew::TestCase keg.uninstall end end + +class InstalledDependantsTests < LinkTests + def stub_formula_name(name) + stub_formula_loader formula(name) { url "foo-1.0" } + end + + def setup_test_keg(name, version) + stub_formula_name(name) + keg = super + Formula.clear_cache + keg + end + + def setup + super + @dependant = setup_test_keg("bar", "1.0") + end + + def dependencies(deps) + tab = Tab.for_keg(@dependant) + tab.tabfile = @dependant.join("INSTALL_RECEIPT.json") + tab.runtime_dependencies = deps + tab.write + end + + def test_no_dependencies + dependencies [] + assert_empty @keg.installed_dependants + end + + def test_same_name_different_version + dependencies [{ "full_name" => "foo", "version" => "1.1" }] + assert_empty @keg.installed_dependants + end + + def test_different_name_same_version + stub_formula_name("baz") + dependencies [{ "full_name" => "baz", "version" => @keg.version.to_s }] + assert_empty @keg.installed_dependants + end + + def test_same_name_and_version + dependencies [{ "full_name" => "foo", "version" => "1.0" }] + assert_equal [@dependant], @keg.installed_dependants + end +end |
