aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlyssa Ross2016-09-22 13:27:33 +0100
committerAlyssa Ross2016-10-25 22:34:34 +0100
commit6f0aabe70700654fdd19d1800fa61f4cdea25266 (patch)
tree16b58f43e35c8902175221dc41d19f8622b39b91
parent3f3fa4d0f7d5c28598fb7a2495d01efa35c7f7a2 (diff)
downloadbrew-6f0aabe70700654fdd19d1800fa61f4cdea25266.tar.bz2
uninstall: refuse when dependants still installed
Closes #934.
-rw-r--r--Library/Homebrew/cmd/uninstall.rb9
-rw-r--r--Library/Homebrew/formula.rb7
-rw-r--r--Library/Homebrew/keg.rb15
-rw-r--r--Library/Homebrew/test/test_keg.rb69
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