From ca6c75d229c73a2523e95aa3736a8031c2f8c158 Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Mon, 27 Aug 2018 10:12:02 +0100 Subject: [PATCH] Check version conflicts using linkage. Instead of refusing to install software preemptively by assuming multiple linkage to differing versions of the same library we now make `brew linkage --test` verify that we don't have two versions of the same library linked at the same time. This will be considerably more permissive whilst checking the actual problem that we're worried about. --- Library/Homebrew/formula_installer.rb | 21 -------------------- Library/Homebrew/linkage_checker.rb | 28 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index 66a44a9cde..85f7e0c5f5 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -155,8 +155,6 @@ class FormulaInstaller recursive_deps = formula.recursive_dependencies recursive_formulae = recursive_deps.map(&:to_formula) - recursive_runtime_formulae = - formula.runtime_formula_dependencies(undeclared: false) recursive_dependencies = [] recursive_formulae.each do |dep| @@ -182,25 +180,6 @@ class FormulaInstaller EOS end - version_hash = {} - version_conflicts = Set.new - recursive_runtime_formulae.each do |f| - name = f.name - unversioned_name, = name.split("@") - next if unversioned_name == "python" - version_hash[unversioned_name] ||= Set.new - version_hash[unversioned_name] << name - next if version_hash[unversioned_name].length < 2 - version_conflicts += version_hash[unversioned_name] - end - unless version_conflicts.empty? - raise CannotInstallFormulaError, <<~EOS - #{formula.full_name} contains conflicting version recursive dependencies: - #{version_conflicts.to_a.join ", "} - View these with `brew deps --tree #{formula.full_name}`. - EOS - end - pinned_unsatisfied_deps = recursive_deps.select do |dep| dep.to_formula.pinned? && !dep.satisfied?(inherited_options_for(dep)) end diff --git a/Library/Homebrew/linkage_checker.rb b/Library/Homebrew/linkage_checker.rb index 31345ec610..05eace4e93 100644 --- a/Library/Homebrew/linkage_checker.rb +++ b/Library/Homebrew/linkage_checker.rb @@ -19,6 +19,7 @@ class LinkageChecker @indirect_deps = [] @undeclared_deps = [] @unnecessary_deps = [] + @version_conflict_deps = [] check_dylibs(rebuild_cache: rebuild_cache) end @@ -50,11 +51,14 @@ class LinkageChecker def display_test_output(puts_output: true) display_items "Missing libraries", @broken_dylibs, puts_output: puts_output display_items "Broken dependencies", @broken_deps, puts_output: puts_output + display_items "Conflicting libraries", @version_conflict_deps, puts_output: puts_output puts "No broken library linkage" unless broken_library_linkage? end def broken_library_linkage? - !@broken_dylibs.empty? || !@broken_deps.empty? + !@broken_dylibs.empty? || + !@broken_deps.empty? || + !@version_conflict_deps.empty? end private @@ -127,8 +131,8 @@ class LinkageChecker end if formula - @indirect_deps, @undeclared_deps, @unnecessary_deps = - check_undeclared_deps + @indirect_deps, @undeclared_deps, @unnecessary_deps, + @version_conflict_deps = check_formula_deps end return unless keg_files_dylibs_was_empty @@ -136,7 +140,7 @@ class LinkageChecker store&.update!(keg_files_dylibs: keg_files_dylibs) end - def check_undeclared_deps + def check_formula_deps filter_out = proc do |dep| next true if dep.build? next false unless dep.optional? || dep.recommended? @@ -170,13 +174,25 @@ class LinkageChecker unnecessary_deps = declared_deps_full_names.reject do |full_name| next true if Formula[full_name].bin.directory? name = full_name.split("/").last - @brewed_dylibs.keys.map { |x| x.split("/").last }.include?(name) + @brewed_dylibs.keys.map { |l| l.split("/").last }.include?(name) end missing_deps = @broken_deps.values.flatten.map { |d| dylib_to_dep(d) } unnecessary_deps -= missing_deps - [indirect_deps, undeclared_deps, unnecessary_deps] + version_hash = {} + version_conflict_deps = Set.new + @brewed_dylibs.keys.each do |l| + name = l.split("/").last + unversioned_name, = name.split("@") + version_hash[unversioned_name] ||= Set.new + version_hash[unversioned_name] << name + next if version_hash[unversioned_name].length < 2 + version_conflict_deps += version_hash[unversioned_name] + end + + [indirect_deps, undeclared_deps, + unnecessary_deps, version_conflict_deps.to_a] end def sort_by_formula_full_name!(arr)