keg: use Formula#runtime_dependencies.
This commit is contained in:
parent
74d6d39e45
commit
8975bf0d5b
@ -102,47 +102,30 @@ class Keg
|
|||||||
#
|
#
|
||||||
# For efficiency, we don't bother trying to get complete data.
|
# For efficiency, we don't bother trying to get complete data.
|
||||||
def self.find_some_installed_dependents(kegs)
|
def self.find_some_installed_dependents(kegs)
|
||||||
# First, check in the tabs of installed Formulae.
|
keg_names = kegs.select(&:optlinked?).map(&:name)
|
||||||
kegs.each do |keg|
|
keg_formulae = []
|
||||||
# Don't include dependencies of kegs that were in the given array.
|
|
||||||
dependents = keg.installed_dependents - kegs
|
|
||||||
dependents.map! { |d| "#{d.name} #{d.version}" }
|
|
||||||
return [keg], dependents if dependents.any?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Some kegs won't have modern Tabs with the dependencies listed.
|
|
||||||
# In this case, fall back to Formula#missing_dependencies.
|
|
||||||
|
|
||||||
# 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 do |f|
|
|
||||||
installed_kegs = f.installed_kegs
|
|
||||||
|
|
||||||
# Don't include dependencies of kegs that were in the given array.
|
|
||||||
next false if (installed_kegs - kegs).empty?
|
|
||||||
|
|
||||||
installed_kegs.any? { |k| Tab.for_keg(k).runtime_dependencies.nil? }
|
|
||||||
end
|
|
||||||
|
|
||||||
keg_names = kegs.map(&:name)
|
|
||||||
kegs_by_source = kegs.group_by do |keg|
|
kegs_by_source = kegs.group_by do |keg|
|
||||||
begin
|
begin
|
||||||
# First, attempt to resolve the keg to a formula
|
# First, attempt to resolve the keg to a formula
|
||||||
# to get up-to-date name and tap information.
|
# to get up-to-date name and tap information.
|
||||||
f = keg.to_formula
|
f = keg.to_formula
|
||||||
|
keg_formulae << f
|
||||||
[f.name, f.tap]
|
[f.name, f.tap]
|
||||||
rescue FormulaUnavailableError
|
rescue FormulaUnavailableError
|
||||||
# If the formula for the keg can't be found,
|
# If the formula for the keg can't be found,
|
||||||
# fall back to the information in the tab.
|
# fall back to the information in the tab.
|
||||||
[keg.name, Tab.for_keg(keg).tap]
|
[keg.name, keg.tab.tap]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
remaining_formulae.each do |dependent|
|
all_required_kegs = Set.new
|
||||||
required = dependent.missing_dependencies(hide: keg_names)
|
all_dependents = []
|
||||||
|
|
||||||
|
# Don't include dependencies of kegs that were in the given array.
|
||||||
|
formulae_to_check = Formula.installed - keg_formulae
|
||||||
|
|
||||||
|
formulae_to_check.each do |dependent|
|
||||||
|
required = dependent.missing_dependencies(hide: keg_names)
|
||||||
required_kegs = required.map do |f|
|
required_kegs = required.map do |f|
|
||||||
f_kegs = kegs_by_source[[f.name, f.tap]]
|
f_kegs = kegs_by_source[[f.name, f.tap]]
|
||||||
next unless f_kegs
|
next unless f_kegs
|
||||||
@ -150,12 +133,16 @@ class Keg
|
|||||||
f_kegs.sort_by(&:version).last
|
f_kegs.sort_by(&:version).last
|
||||||
end.compact
|
end.compact
|
||||||
|
|
||||||
next unless required_kegs.any?
|
next if required_kegs.empty?
|
||||||
|
|
||||||
return required_kegs, [dependent.to_s]
|
all_required_kegs += required_kegs
|
||||||
|
all_dependents << dependent.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
nil
|
return if all_required_kegs.empty?
|
||||||
|
return if all_dependents.empty?
|
||||||
|
|
||||||
|
[all_required_kegs.to_a, all_dependents.sort]
|
||||||
end
|
end
|
||||||
|
|
||||||
# if path is a file in a keg then this will return the containing Keg object
|
# if path is a file in a keg then this will return the containing Keg object
|
||||||
@ -390,25 +377,6 @@ class Keg
|
|||||||
Formulary.from_keg(self)
|
Formulary.from_keg(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
def installed_dependents
|
|
||||||
return [] unless optlinked?
|
|
||||||
tap = Tab.for_keg(self).source["tap"]
|
|
||||||
Keg.all.select do |keg|
|
|
||||||
tab = Tab.for_keg(keg)
|
|
||||||
next if tab.runtime_dependencies.nil?
|
|
||||||
tab.runtime_dependencies.any? do |dep|
|
|
||||||
# Resolve formula rather than directly comparing names
|
|
||||||
# in case of conflicts between formulae from different taps.
|
|
||||||
begin
|
|
||||||
dep_formula = Formulary.factory(dep["full_name"])
|
|
||||||
dep_formula == to_formula
|
|
||||||
rescue FormulaUnavailableError
|
|
||||||
next dep["full_name"] == "#{tap}/#{name}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def oldname_opt_record
|
def oldname_opt_record
|
||||||
@oldname_opt_record ||= if (opt_dir = HOMEBREW_PREFIX/"opt").directory?
|
@oldname_opt_record ||= if (opt_dir = HOMEBREW_PREFIX/"opt").directory?
|
||||||
opt_dir.subdirs.detect do |dir|
|
opt_dir.subdirs.detect do |dir|
|
||||||
|
|||||||
@ -373,29 +373,13 @@ describe Keg do
|
|||||||
|
|
||||||
let(:dependent) { setup_test_keg("bar", "1.0") }
|
let(:dependent) { setup_test_keg("bar", "1.0") }
|
||||||
|
|
||||||
# Test with a keg whose formula isn't known.
|
|
||||||
# This can happen if e.g. a formula is installed
|
|
||||||
# from a file path or URL.
|
|
||||||
specify "unknown Formula" do
|
|
||||||
allow(Formulary).to receive(:loader_for).and_call_original
|
|
||||||
alter_tab(keg) do |t|
|
|
||||||
t.source["tap"] = "some/tap"
|
|
||||||
t.source["path"] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
dependencies [{ "full_name" => "some/tap/foo", "version" => "1.0" }]
|
|
||||||
expect(keg.installed_dependents).to eq([dependent])
|
|
||||||
expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar 1.0"]])
|
|
||||||
|
|
||||||
dependencies nil
|
|
||||||
# It doesn't make sense for a keg with no formula to have any dependents,
|
|
||||||
# so that can't really be tested.
|
|
||||||
expect(described_class.find_some_installed_dependents([keg])).to be nil
|
|
||||||
end
|
|
||||||
|
|
||||||
specify "a dependency with no Tap in Tab" do
|
specify "a dependency with no Tap in Tab" do
|
||||||
tap_dep = setup_test_keg("baz", "1.0")
|
tap_dep = setup_test_keg("baz", "1.0")
|
||||||
|
|
||||||
|
# allow tap_dep to be linked too
|
||||||
|
FileUtils.rm_r tap_dep/"bin"
|
||||||
|
tap_dep.link
|
||||||
|
|
||||||
alter_tab(keg) { |t| t.source["tap"] = nil }
|
alter_tab(keg) { |t| t.source["tap"] = nil }
|
||||||
|
|
||||||
dependencies nil
|
dependencies nil
|
||||||
@ -408,21 +392,18 @@ describe Keg do
|
|||||||
|
|
||||||
specify "no dependencies anywhere" do
|
specify "no dependencies anywhere" do
|
||||||
dependencies nil
|
dependencies nil
|
||||||
expect(keg.installed_dependents).to be_empty
|
|
||||||
expect(described_class.find_some_installed_dependents([keg])).to be nil
|
expect(described_class.find_some_installed_dependents([keg])).to be nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "missing Formula dependency" do
|
specify "missing Formula dependency" do
|
||||||
dependencies nil
|
dependencies nil
|
||||||
Formula["bar"].class.depends_on "foo"
|
Formula["bar"].class.depends_on "foo"
|
||||||
expect(keg.installed_dependents).to be_empty
|
|
||||||
expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar"]])
|
expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar"]])
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "uninstalling dependent and dependency" do
|
specify "uninstalling dependent and dependency" do
|
||||||
dependencies nil
|
dependencies nil
|
||||||
Formula["bar"].class.depends_on "foo"
|
Formula["bar"].class.depends_on "foo"
|
||||||
expect(keg.installed_dependents).to be_empty
|
|
||||||
expect(described_class.find_some_installed_dependents([keg, dependent])).to be nil
|
expect(described_class.find_some_installed_dependents([keg, dependent])).to be nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -442,40 +423,34 @@ describe Keg do
|
|||||||
|
|
||||||
specify "empty dependencies in Tab" do
|
specify "empty dependencies in Tab" do
|
||||||
dependencies []
|
dependencies []
|
||||||
expect(keg.installed_dependents).to be_empty
|
|
||||||
expect(described_class.find_some_installed_dependents([keg])).to be nil
|
expect(described_class.find_some_installed_dependents([keg])).to be nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "same name but different version in Tab" do
|
specify "same name but different version in Tab" do
|
||||||
dependencies [{ "full_name" => "foo", "version" => "1.1" }]
|
dependencies [{ "full_name" => "foo", "version" => "1.1" }]
|
||||||
expect(keg.installed_dependents).to eq([dependent])
|
expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar"]])
|
||||||
expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar 1.0"]])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "different name and same version in Tab" do
|
specify "different name and same version in Tab" do
|
||||||
stub_formula_name("baz")
|
stub_formula_name("baz")
|
||||||
dependencies [{ "full_name" => "baz", "version" => keg.version.to_s }]
|
dependencies [{ "full_name" => "baz", "version" => keg.version.to_s }]
|
||||||
expect(keg.installed_dependents).to be_empty
|
|
||||||
expect(described_class.find_some_installed_dependents([keg])).to be nil
|
expect(described_class.find_some_installed_dependents([keg])).to be nil
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "same name and version in Tab" do
|
specify "same name and version in Tab" do
|
||||||
dependencies [{ "full_name" => "foo", "version" => "1.0" }]
|
dependencies [{ "full_name" => "foo", "version" => "1.0" }]
|
||||||
expect(keg.installed_dependents).to eq([dependent])
|
expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar"]])
|
||||||
expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar 1.0"]])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "fallback for old versions" do
|
specify "fallback for old versions" do
|
||||||
unreliable_dependencies [{ "full_name" => "baz", "version" => "1.0" }]
|
unreliable_dependencies [{ "full_name" => "baz", "version" => "1.0" }]
|
||||||
Formula["bar"].class.depends_on "foo"
|
Formula["bar"].class.depends_on "foo"
|
||||||
expect(keg.installed_dependents).to be_empty
|
|
||||||
expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar"]])
|
expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar"]])
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "non-opt-linked" do
|
specify "non-opt-linked" do
|
||||||
keg.remove_opt_record
|
keg.remove_opt_record
|
||||||
dependencies [{ "full_name" => "foo", "version" => "1.0" }]
|
dependencies [{ "full_name" => "foo", "version" => "1.0" }]
|
||||||
expect(keg.installed_dependents).to be_empty
|
|
||||||
expect(described_class.find_some_installed_dependents([keg])).to be nil
|
expect(described_class.find_some_installed_dependents([keg])).to be nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -483,8 +458,7 @@ describe Keg do
|
|||||||
keg.unlink
|
keg.unlink
|
||||||
Formula["foo"].class.keg_only "a good reason"
|
Formula["foo"].class.keg_only "a good reason"
|
||||||
dependencies [{ "full_name" => "foo", "version" => "1.1" }] # different version
|
dependencies [{ "full_name" => "foo", "version" => "1.1" }] # different version
|
||||||
expect(keg.installed_dependents).to eq([dependent])
|
expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar"]])
|
||||||
expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar 1.0"]])
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user