From 8386e6a8c18f5dee30f17386cab652b653b1b860 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Sun, 11 Feb 2018 13:25:30 +0000 Subject: [PATCH] Undeclared dependencies in runtime_dependencies Fixes https://github.com/Homebrew/brew/issues/2173. --- Library/Homebrew/formula.rb | 22 +++++++++++--- Library/Homebrew/test/formula_spec.rb | 44 +++++++++++++++++++-------- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 1355e5945c..b226963eaf 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -1487,10 +1487,7 @@ class Formula # Returns a list of Dependency objects that are required at runtime. # @private def runtime_dependencies - recursive_dependencies do |_, dependency| - Dependency.prune if dependency.build? - Dependency.prune if !dependency.required? && build.without?(dependency) - end + declared_runtime_dependencies | undeclared_runtime_dependencies end # Returns a list of formulae depended on by this formula that aren't @@ -1835,6 +1832,23 @@ class Formula private + def declared_runtime_dependencies + recursive_dependencies do |_, dependency| + Dependency.prune if dependency.build? + Dependency.prune if !dependency.required? && build.without?(dependency) + end + end + + def undeclared_runtime_dependencies + return [] unless optlinked? + + keg = Keg.new(opt_prefix) + linkage_checker = LinkageChecker.new(keg, self) + dylib_formula_names = linkage_checker.brewed_dylibs.keys + linked_formulae_names = dylib_formula_names - [name] + linked_formulae_names.map { |n| Dependency.new(n) } + end + # Returns the prefix for a given formula version number. # @private def versioned_prefix(v) diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb index a9d09cb00b..865ea38361 100644 --- a/Library/Homebrew/test/formula_spec.rb +++ b/Library/Homebrew/test/formula_spec.rb @@ -685,26 +685,44 @@ describe Formula do expect(f5.runtime_dependencies.map(&:name)).to eq(["f1", "f4"]) end - specify "runtime dependencies with optional deps from tap" do - tap_loader = double + describe "#runtime_dependencies" do + specify "runtime dependencies with optional deps from tap" do + tap_loader = double - allow(tap_loader).to receive(:get_formula).and_raise(RuntimeError, "tried resolving tap formula") - allow(Formulary).to receive(:loader_for).with("foo/bar/f1", from: nil).and_return(tap_loader) - stub_formula_loader(formula("f2") { url("f2-1.0") }, "baz/qux/f2") + allow(tap_loader).to receive(:get_formula).and_raise(RuntimeError, "tried resolving tap formula") + allow(Formulary).to receive(:loader_for).with("foo/bar/f1", from: nil).and_return(tap_loader) + stub_formula_loader(formula("f2") { url("f2-1.0") }, "baz/qux/f2") - f3 = formula "f3" do - url "f3-1.0" + f3 = formula "f3" do + url "f3-1.0" - depends_on "foo/bar/f1" => :optional - depends_on "baz/qux/f2" + depends_on "foo/bar/f1" => :optional + depends_on "baz/qux/f2" + end + + expect(f3.runtime_dependencies.map(&:name)).to eq(["baz/qux/f2"]) + + stub_formula_loader(formula("f1") { url("f1-1.0") }, "foo/bar/f1") + f3.build = BuildOptions.new(Options.create(["--with-f1"]), f3.options) + + expect(f3.runtime_dependencies.map(&:name)).to eq(["foo/bar/f1", "baz/qux/f2"]) end - expect(f3.runtime_dependencies.map(&:name)).to eq(["baz/qux/f2"]) + it "includes non-declared direct dependencies" do + formula = Class.new(Testball).new + dependency = formula("dependency") { url "f-1.0" } - stub_formula_loader(formula("f1") { url("f1-1.0") }, "foo/bar/f1") - f3.build = BuildOptions.new(Options.create(["--with-f1"]), f3.options) + formula.brew { formula.install } + keg = Keg.for(formula.prefix) + keg.link - expect(f3.runtime_dependencies.map(&:name)).to eq(["foo/bar/f1", "baz/qux/f2"]) + brewed_dylibs = { dependency.name => Set["some.dylib"] } + linkage_checker = double("linkage checker", brewed_dylibs: brewed_dylibs) + allow(LinkageChecker).to receive(:new).with(keg, any_args) + .and_return(linkage_checker) + + expect(formula.runtime_dependencies).to include an_object_having_attributes(name: dependency.name) + end end specify "requirements" do