aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlyssa Ross2016-09-30 19:34:14 +0100
committerAlyssa Ross2016-10-25 22:34:35 +0100
commitef13f8eacaa62be6d2e4ee0af5041a6563fd0c71 (patch)
tree916a19234345c2640a653fb730e1fb791fecd354
parent452691528d4c5c67175963ddb33f5cc3d51dce41 (diff)
downloadbrew-ef13f8eacaa62be6d2e4ee0af5041a6563fd0c71.tar.bz2
uninstall: only <=1 Diagnostic.missing_deps call
-rw-r--r--Library/Homebrew/cmd/uninstall.rb43
-rw-r--r--Library/Homebrew/keg.rb4
-rw-r--r--Library/Homebrew/test/test_uninstall.rb18
3 files changed, 57 insertions, 8 deletions
diff --git a/Library/Homebrew/cmd/uninstall.rb b/Library/Homebrew/cmd/uninstall.rb
index e00109bac..92b3beff4 100644
--- a/Library/Homebrew/cmd/uninstall.rb
+++ b/Library/Homebrew/cmd/uninstall.rb
@@ -6,6 +6,7 @@
require "keg"
require "formula"
+require "diagnostic"
require "migrator"
module Homebrew
@@ -75,17 +76,45 @@ module Homebrew
end
def check_for_dependents(kegs)
+ return false unless result = find_some_installed_dependents(kegs)
+
+ requireds, dependents = result
+
+ msg = "Refusing to uninstall #{requireds.join(", ")} because "
+ msg << (requireds.count == 1 ? "it is" : "they are")
+ msg << " required by #{dependents.join(", ")}, which "
+ msg << (dependents.count == 1 ? "is" : "are")
+ msg << " currently installed."
+ ofail msg
+ print "You can override this and force removal with "
+ puts "`brew uninstall --ignore-dependencies #{requireds.map(&:name).join(" ")}`."
+
+ true
+ end
+
+ # Will return some kegs, and some dependencies, if they're present.
+ # For efficiency, we don't bother trying to get complete data.
+ def find_some_installed_dependents(kegs)
kegs.each do |keg|
dependents = keg.installed_dependents - kegs
- next if dependents.empty?
+ dependents.map! { |d| "#{d.name} #{d.version}" }
+ return [keg], dependents if dependents.any?
+ end
- dependents_output = dependents.map { |k| "#{k.name} #{k.version}" }.join(", ")
- conjugation = dependents.count == 1 ? "is" : "are"
- ofail "Refusing to uninstall #{keg} because it is required by #{dependents_output}, which #{conjugation} currently installed."
- puts "You can override this and force removal with `brew uninstall --ignore-dependencies #{keg.name}`."
- return true
+ # Find formulae that didn't have dependencies saved in all of their kegs,
+ # so need them to be calculated now.
+ #
+ # This happens after the initial dependency check because it's sloooow.
+ remaining_formulae = Formula.installed.select { |f|
+ f.installed_kegs.any? { |k| Tab.for_keg(k).runtime_dependencies.nil? }
+ }
+ Diagnostic.missing_deps(remaining_formulae, kegs.map(&:name)) do |dependent, required|
+ kegs_by_name = kegs.group_by(&:to_formula)
+ required_kegs = required.map { |f| kegs_by_name[f].sort_by(&:version).last }
+ return required_kegs, [dependent]
end
- false
+
+ nil
end
def rm_pin(rack)
diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb
index 257594671..16717ea4e 100644
--- a/Library/Homebrew/keg.rb
+++ b/Library/Homebrew/keg.rb
@@ -298,7 +298,9 @@ class Keg
def installed_dependents
Formula.installed.flat_map(&:installed_kegs).select do |keg|
- Tab.for_keg(keg).runtime_dependencies.any? do |dep|
+ tab = Tab.for_keg(keg)
+ next if tab.runtime_dependencies.nil? # no dependency information saved.
+ tab.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"])
diff --git a/Library/Homebrew/test/test_uninstall.rb b/Library/Homebrew/test/test_uninstall.rb
index ede1e321b..c36a14477 100644
--- a/Library/Homebrew/test/test_uninstall.rb
+++ b/Library/Homebrew/test/test_uninstall.rb
@@ -43,6 +43,24 @@ class IntegrationCommandTestUninstall < IntegrationCommandTestCase
end
end
+ def test_uninstall_leaving_dependents_no_runtime_dependencies_in_tab
+ cmd("install", "testball_f2")
+
+ f2_keg = f2.installed_kegs.first
+ f2_tab = Tab.for_keg(f2_keg)
+ f2_tab.runtime_dependencies = nil
+ f2_tab.write
+
+ run_as_not_developer do
+ assert_match "Refusing to uninstall",
+ cmd_fail("uninstall", "testball_f1")
+ refute_empty f1.installed_kegs
+ assert_match "Uninstalling #{f2.rack}",
+ cmd("uninstall", "testball_f2")
+ assert_empty f2.installed_kegs
+ end
+ end
+
def test_uninstall_force_leaving_dependents
cmd("install", "testball_f2")
run_as_not_developer do