From 8386e6a8c18f5dee30f17386cab652b653b1b860 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Sun, 11 Feb 2018 13:25:30 +0000 Subject: [PATCH 01/11] 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 From 40ca03e975041b4fce9a3097fed5739653c039f3 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Sun, 11 Feb 2018 16:23:22 +0000 Subject: [PATCH 02/11] Add undeclared dependencies to Tab when installing An installed formula doesn't get optlinked until _after_ it's installed, meaning that we can't rely on `opt_prefix` to get the right keg. So, if not optlinked, fall back to the formula's prefix, which will be that of the current installation. --- Library/Homebrew/formula.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index b226963eaf..a6e7750c6c 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -13,6 +13,7 @@ require "pkg_version" require "tap" require "keg" require "migrator" +require "os/mac/linkage_checker" require "extend/ENV" require "language/python" @@ -1840,9 +1841,14 @@ class Formula end def undeclared_runtime_dependencies - return [] unless optlinked? + if optlinked? + keg = Keg.new(opt_prefix) + elsif prefix.directory? + keg = Keg.new(prefix) + else + return [] + end - 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] From 10ec789660edb7f727f11989cff003bf2f7275e7 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Sun, 11 Feb 2018 16:30:58 +0000 Subject: [PATCH 03/11] Don't include declared dependencies in undeclared oops --- Library/Homebrew/formula.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index a6e7750c6c..f6fa558b99 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -1850,9 +1850,7 @@ class Formula end 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) } + linkage_checker.undeclared_deps.map { |n| Dependency.new(n) } end # Returns the prefix for a given formula version number. From fa5245f7adf38833b03e92e42aa5217ac5157773 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Thu, 15 Feb 2018 18:41:45 +0000 Subject: [PATCH 04/11] Only check undeclared dependencies on macOS We don't currently have a LinkageChecker on Linux, so can't do this. --- Library/Homebrew/extend/os/mac/formula.rb | 16 +++++++ Library/Homebrew/formula.rb | 12 +----- Library/Homebrew/test/formula_spec.rb | 44 ++++++-------------- Library/Homebrew/test/os/mac/formula_spec.rb | 19 +++++++++ 4 files changed, 49 insertions(+), 42 deletions(-) create mode 100644 Library/Homebrew/extend/os/mac/formula.rb create mode 100644 Library/Homebrew/test/os/mac/formula_spec.rb diff --git a/Library/Homebrew/extend/os/mac/formula.rb b/Library/Homebrew/extend/os/mac/formula.rb new file mode 100644 index 0000000000..0954e85872 --- /dev/null +++ b/Library/Homebrew/extend/os/mac/formula.rb @@ -0,0 +1,16 @@ +require "os/mac/linkage_checker" + +class Formula + def undeclared_runtime_dependencies + if optlinked? + keg = Keg.new(opt_prefix) + elsif prefix.directory? + keg = Keg.new(prefix) + else + return [] + end + + linkage_checker = LinkageChecker.new(keg, self) + linkage_checker.undeclared_deps.map { |n| Dependency.new(n) } + end +end diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index f6fa558b99..72d9b14e5f 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -13,7 +13,6 @@ require "pkg_version" require "tap" require "keg" require "migrator" -require "os/mac/linkage_checker" require "extend/ENV" require "language/python" @@ -1841,16 +1840,7 @@ class Formula end def undeclared_runtime_dependencies - if optlinked? - keg = Keg.new(opt_prefix) - elsif prefix.directory? - keg = Keg.new(prefix) - else - return [] - end - - linkage_checker = LinkageChecker.new(keg, self) - linkage_checker.undeclared_deps.map { |n| Dependency.new(n) } + [] end # Returns the prefix for a given formula version number. diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb index 865ea38361..a9d09cb00b 100644 --- a/Library/Homebrew/test/formula_spec.rb +++ b/Library/Homebrew/test/formula_spec.rb @@ -685,44 +685,26 @@ describe Formula do expect(f5.runtime_dependencies.map(&:name)).to eq(["f1", "f4"]) end - describe "#runtime_dependencies" do - specify "runtime dependencies with optional deps from tap" do - tap_loader = double + 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" - 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"]) + depends_on "foo/bar/f1" => :optional + depends_on "baz/qux/f2" end - it "includes non-declared direct dependencies" do - formula = Class.new(Testball).new - dependency = formula("dependency") { url "f-1.0" } + expect(f3.runtime_dependencies.map(&:name)).to eq(["baz/qux/f2"]) - formula.brew { formula.install } - keg = Keg.for(formula.prefix) - keg.link + stub_formula_loader(formula("f1") { url("f1-1.0") }, "foo/bar/f1") + f3.build = BuildOptions.new(Options.create(["--with-f1"]), f3.options) - 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 + expect(f3.runtime_dependencies.map(&:name)).to eq(["foo/bar/f1", "baz/qux/f2"]) end specify "requirements" do diff --git a/Library/Homebrew/test/os/mac/formula_spec.rb b/Library/Homebrew/test/os/mac/formula_spec.rb new file mode 100644 index 0000000000..21920238b4 --- /dev/null +++ b/Library/Homebrew/test/os/mac/formula_spec.rb @@ -0,0 +1,19 @@ +RSpec.describe Formula do + describe "#runtime_dependencies" do + it "includes non-declared direct dependencies" do + formula = Class.new(Testball).new + dependency = formula("dependency") { url "f-1.0" } + + formula.brew { formula.install } + keg = Keg.for(formula.prefix) + keg.link + + 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 +end From 51b27039be6dc4d856f86b542a12d29e28fb86d1 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Thu, 1 Mar 2018 17:30:42 +0000 Subject: [PATCH 05/11] Revert "Only check undeclared dependencies on macOS" This reverts commit fa5245f7adf38833b03e92e42aa5217ac5157773. --- Library/Homebrew/extend/os/mac/formula.rb | 16 ------- Library/Homebrew/formula.rb | 12 +++++- Library/Homebrew/test/formula_spec.rb | 44 ++++++++++++++------ Library/Homebrew/test/os/mac/formula_spec.rb | 19 --------- 4 files changed, 42 insertions(+), 49 deletions(-) delete mode 100644 Library/Homebrew/extend/os/mac/formula.rb delete mode 100644 Library/Homebrew/test/os/mac/formula_spec.rb diff --git a/Library/Homebrew/extend/os/mac/formula.rb b/Library/Homebrew/extend/os/mac/formula.rb deleted file mode 100644 index 0954e85872..0000000000 --- a/Library/Homebrew/extend/os/mac/formula.rb +++ /dev/null @@ -1,16 +0,0 @@ -require "os/mac/linkage_checker" - -class Formula - def undeclared_runtime_dependencies - if optlinked? - keg = Keg.new(opt_prefix) - elsif prefix.directory? - keg = Keg.new(prefix) - else - return [] - end - - linkage_checker = LinkageChecker.new(keg, self) - linkage_checker.undeclared_deps.map { |n| Dependency.new(n) } - end -end diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 72d9b14e5f..f6fa558b99 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -13,6 +13,7 @@ require "pkg_version" require "tap" require "keg" require "migrator" +require "os/mac/linkage_checker" require "extend/ENV" require "language/python" @@ -1840,7 +1841,16 @@ class Formula end def undeclared_runtime_dependencies - [] + if optlinked? + keg = Keg.new(opt_prefix) + elsif prefix.directory? + keg = Keg.new(prefix) + else + return [] + end + + linkage_checker = LinkageChecker.new(keg, self) + linkage_checker.undeclared_deps.map { |n| Dependency.new(n) } end # Returns the prefix for a given formula version number. 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 diff --git a/Library/Homebrew/test/os/mac/formula_spec.rb b/Library/Homebrew/test/os/mac/formula_spec.rb deleted file mode 100644 index 21920238b4..0000000000 --- a/Library/Homebrew/test/os/mac/formula_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -RSpec.describe Formula do - describe "#runtime_dependencies" do - it "includes non-declared direct dependencies" do - formula = Class.new(Testball).new - dependency = formula("dependency") { url "f-1.0" } - - formula.brew { formula.install } - keg = Keg.for(formula.prefix) - keg.link - - 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 -end From 0a2f0ab4563f4d438aac9137deae2b1cf15366c5 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Mon, 12 Mar 2018 09:20:24 +0000 Subject: [PATCH 06/11] Fix formula/linkage_checker infinite recursion --- Library/Homebrew/formula.rb | 40 ++++++++++++++--------------- Library/Homebrew/linkage_checker.rb | 3 ++- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index dbe74b5848..29f6c728da 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -1491,6 +1491,26 @@ class Formula declared_runtime_dependencies | undeclared_runtime_dependencies end + 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 + if optlinked? + keg = Keg.new(opt_prefix) + elsif prefix.directory? + keg = Keg.new(prefix) + else + return [] + end + + linkage_checker = LinkageChecker.new(keg, self) + linkage_checker.undeclared_deps.map { |n| Dependency.new(n) } + end + # Returns a list of formulae depended on by this formula that aren't # installed def missing_dependencies(hide: nil) @@ -1833,26 +1853,6 @@ 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 - if optlinked? - keg = Keg.new(opt_prefix) - elsif prefix.directory? - keg = Keg.new(prefix) - else - return [] - end - - linkage_checker = LinkageChecker.new(keg, self) - linkage_checker.undeclared_deps.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/linkage_checker.rb b/Library/Homebrew/linkage_checker.rb index cf6c12f22c..345fde47e6 100644 --- a/Library/Homebrew/linkage_checker.rb +++ b/Library/Homebrew/linkage_checker.rb @@ -63,7 +63,8 @@ class LinkageChecker formula.build.without?(dep) end declared_deps = formula.deps.reject { |dep| filter_out.call(dep) }.map(&:name) - recursive_deps = keg.to_formula.runtime_dependencies.map { |dep| dep.to_formula.full_name } + recursive_deps = keg.to_formula.declared_runtime_dependencies + .map { |dep| dep.to_formula.full_name } declared_dep_names = declared_deps.map { |dep| dep.split("/").last } indirect_deps = [] undeclared_deps = [] From 264acb22f4443ecd6c9133e7700ac06b63a3012b Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Sat, 7 Apr 2018 12:16:10 +0100 Subject: [PATCH 07/11] Restore Formula#declared_runtime_dependencies This got lost in a merge. --- Library/Homebrew/formula.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 75cb846103..c6af96f6d0 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -1498,6 +1498,13 @@ class Formula declared_runtime_dependencies | undeclared_runtime_dependencies end + 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 if optlinked? keg = Keg.new(opt_prefix) From 3c0443123f3ba86c8dffe087253b73e2e328bfeb Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Sat, 7 Apr 2018 12:17:12 +0100 Subject: [PATCH 08/11] Test Formula with undeclared_deps Changed in 10ec789660edb7f727f11989cff003bf2f7275e7. --- Library/Homebrew/test/formula_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb index 0680644c88..bb0d1d2ba7 100644 --- a/Library/Homebrew/test/formula_spec.rb +++ b/Library/Homebrew/test/formula_spec.rb @@ -716,8 +716,7 @@ describe Formula do keg = Keg.for(formula.prefix) keg.link - brewed_dylibs = { dependency.name => Set["some.dylib"] } - linkage_checker = double("linkage checker", brewed_dylibs: brewed_dylibs) + linkage_checker = double("linkage checker", undeclared_deps: [dependency.name]) allow(LinkageChecker).to receive(:new).with(keg, any_args) .and_return(linkage_checker) From c167614797f324f5d0fb7d2d5f77ced27a697d61 Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Wed, 25 Apr 2018 10:26:02 +0100 Subject: [PATCH 09/11] linkage_checker: handle missing formulae. --- Library/Homebrew/linkage_checker.rb | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/linkage_checker.rb b/Library/Homebrew/linkage_checker.rb index 45812e31df..f60cca98c1 100644 --- a/Library/Homebrew/linkage_checker.rb +++ b/Library/Homebrew/linkage_checker.rb @@ -62,10 +62,17 @@ class LinkageChecker next false unless dep.optional? || dep.recommended? formula.build.without?(dep) end + declared_deps = formula.deps.reject { |dep| filter_out.call(dep) }.map(&:name) - runtime_deps = keg.to_formula.declared_runtime_dependencies - recursive_deps = runtime_deps.map { |dep| dep.to_formula.name } declared_dep_names = declared_deps.map { |dep| dep.split("/").last } + recursive_deps = formula.declared_runtime_dependencies.map do |dep| + begin + dep.to_formula.name + rescue FormulaUnavailableError + nil + end + end.compact + indirect_deps = [] undeclared_deps = [] @brewed_dylibs.each_key do |full_name| @@ -77,13 +84,16 @@ class LinkageChecker undeclared_deps << full_name end end + sort_by_formula_full_name!(indirect_deps) sort_by_formula_full_name!(undeclared_deps) + unnecessary_deps = declared_dep_names.reject do |full_name| name = full_name.split("/").last next true if Formula[name].bin.directory? @brewed_dylibs.keys.map { |x| x.split("/").last }.include?(name) end + [indirect_deps, undeclared_deps, unnecessary_deps] end From 3454d6a96199cc4f405a52d1525d0cc760a0ebf8 Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Wed, 25 Apr 2018 11:44:29 +0100 Subject: [PATCH 10/11] runtime_deps: improve documentation and consistency. --- Library/Homebrew/formula.rb | 27 +++++++++++++++++++-------- Library/Homebrew/linkage_checker.rb | 4 +++- Library/Homebrew/test/formula_spec.rb | 9 ++++----- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 69c60a3d28..5a146d4bcc 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -1487,12 +1487,23 @@ class Formula Requirement.expand(self, &block) end + # Returns a Keg for the opt_prefix or installed_prefix if they exist. + # If not, return nil. + # @private + def opt_or_installed_prefix_keg + if optlinked? && opt_prefix.exist? + Keg.new(opt_prefix) + elsif installed_prefix.directory? + Keg.new(installed_prefix) + end + end + # Returns a list of Dependency objects that are required at runtime. # @private def runtime_dependencies(read_from_tab: true) if read_from_tab && installed_prefix.directory? && - (keg = Keg.new(installed_prefix)) && + (keg = opt_or_installed_prefix_keg) && (tab_deps = keg.runtime_dependencies) return tab_deps.map { |d| Dependency.new d["full_name"] }.compact end @@ -1500,6 +1511,8 @@ class Formula declared_runtime_dependencies | undeclared_runtime_dependencies end + # Returns a list of Dependency objects that are declared in the formula. + # @private def declared_runtime_dependencies recursive_dependencies do |_, dependency| Dependency.prune if dependency.build? @@ -1507,14 +1520,12 @@ class Formula end end + # Returns a list of Dependency objects that are not declared in the formula + # but the formula links to. + # @private def undeclared_runtime_dependencies - if optlinked? - keg = Keg.new(opt_prefix) - elsif prefix.directory? - keg = Keg.new(prefix) - else - return [] - end + keg = opt_or_installed_prefix_keg + return [] unless keg linkage_checker = LinkageChecker.new(keg, self) linkage_checker.undeclared_deps.map { |n| Dependency.new(n) } diff --git a/Library/Homebrew/linkage_checker.rb b/Library/Homebrew/linkage_checker.rb index 6984397435..85bb003a3f 100644 --- a/Library/Homebrew/linkage_checker.rb +++ b/Library/Homebrew/linkage_checker.rb @@ -2,6 +2,8 @@ require "keg" require "formula" class LinkageChecker + attr_reader :undeclared_deps + def initialize(keg, formula = nil) @keg = keg @formula = formula || resolve_formula(keg) @@ -142,7 +144,7 @@ class LinkageChecker missing_deps = @broken_deps.values.flatten.map { |d| dylib_to_dep(d) } unnecessary_deps -= missing_deps - + [indirect_deps, undeclared_deps, unnecessary_deps] end diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb index bb0d1d2ba7..6ad102756e 100644 --- a/Library/Homebrew/test/formula_spec.rb +++ b/Library/Homebrew/test/formula_spec.rb @@ -708,19 +708,18 @@ describe Formula do expect(f3.runtime_dependencies.map(&:name)).to eq(["foo/bar/f1", "baz/qux/f2"]) end - it "includes non-declared direct dependencies" do + it "includes non-declared direct dependencies", :focus do formula = Class.new(Testball).new dependency = formula("dependency") { url "f-1.0" } formula.brew { formula.install } - keg = Keg.for(formula.prefix) + keg = Keg.for(formula.installed_prefix) keg.link linkage_checker = double("linkage checker", undeclared_deps: [dependency.name]) - allow(LinkageChecker).to receive(:new).with(keg, any_args) - .and_return(linkage_checker) + allow(LinkageChecker).to receive(:new).and_return(linkage_checker) - expect(formula.runtime_dependencies).to include an_object_having_attributes(name: dependency.name) + expect(formula.runtime_dependencies.map(&:name)).to eq [dependency.name] end end From 8035afcc36ac45ebd127f670b13ab32414c310fa Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Wed, 25 Apr 2018 12:08:33 +0100 Subject: [PATCH 11/11] linkage_checker: fix generic pathname calls. --- Library/Homebrew/extend/pathname.rb | 8 ++++++++ Library/Homebrew/linkage_checker.rb | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/extend/pathname.rb b/Library/Homebrew/extend/pathname.rb index ec7293496e..dfe24b7886 100644 --- a/Library/Homebrew/extend/pathname.rb +++ b/Library/Homebrew/extend/pathname.rb @@ -472,9 +472,17 @@ class Pathname } end + def binary_executable? + false + end + def mach_o_bundle? false end + + def dylib? + false + end end require "extend/os/pathname" diff --git a/Library/Homebrew/linkage_checker.rb b/Library/Homebrew/linkage_checker.rb index 85bb003a3f..bf390c4270 100644 --- a/Library/Homebrew/linkage_checker.rb +++ b/Library/Homebrew/linkage_checker.rb @@ -66,7 +66,7 @@ class LinkageChecker checked_dylibs = Set.new @keg.find do |file| next if file.symlink? || file.directory? - next unless file.dylib? || file.binary_executable? || file.mach_o_bundle? + next if !file.dylib? && !file.binary_executable? && !file.mach_o_bundle? # weakly loaded dylibs may not actually exist on disk, so skip them # when checking for broken linkage