install glibc/gcc automatically if too old.
Right now this is done through the gcc@5 formula.
See 9692318ca6/Formula/gcc%405.rb (L33)
This is fragile because when we will migrate to gcc@11
we have to think about migrating the installation from one gcc formula to another..
Also, not having the right glibc version results in a non-functional brew
installation on an older Linux: the glibc installation needs
to be done by brew, and not by a workaround in a specific formula
Co-Authored-By: Mike McQuaid <mike@mikemcquaid.com>
Co-Authored-By: Bo Anderson <mail@boanderson.me>
Co-Authored-By: Shaun Jackman <sjackman@gmail.com>
			
			
This commit is contained in:
		
							parent
							
								
									2415339124
								
							
						
					
					
						commit
						d271614872
					
				@ -28,6 +28,8 @@ class DependencyCollector
 | 
			
		||||
  def initialize
 | 
			
		||||
    @deps = Dependencies.new
 | 
			
		||||
    @requirements = Requirements.new
 | 
			
		||||
 | 
			
		||||
    init_global_dep_tree_if_needed!
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def initialize_copy(other)
 | 
			
		||||
@ -68,6 +70,12 @@ class DependencyCollector
 | 
			
		||||
    parse_spec(spec, Array(tags))
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { params(related_formula_names: T::Array[String]).returns(T.nilable(Dependency)) }
 | 
			
		||||
  def gcc_dep_if_needed(related_formula_names); end
 | 
			
		||||
 | 
			
		||||
  sig { params(related_formula_names: T::Array[String]).returns(T.nilable(Dependency)) }
 | 
			
		||||
  def glibc_dep_if_needed(related_formula_names); end
 | 
			
		||||
 | 
			
		||||
  def git_dep_if_needed(tags)
 | 
			
		||||
    return if Utils::Git.available?
 | 
			
		||||
 | 
			
		||||
@ -110,6 +118,9 @@ class DependencyCollector
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  sig { void }
 | 
			
		||||
  def init_global_dep_tree_if_needed!; end
 | 
			
		||||
 | 
			
		||||
  def parse_spec(spec, tags)
 | 
			
		||||
    case spec
 | 
			
		||||
    when String
 | 
			
		||||
 | 
			
		||||
@ -98,6 +98,16 @@ class DevelopmentTools
 | 
			
		||||
      @gcc_version = {}
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(T::Boolean) }
 | 
			
		||||
    def build_system_too_old?
 | 
			
		||||
      false
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(T::Boolean) }
 | 
			
		||||
    def system_gcc_too_old?
 | 
			
		||||
      false
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(T::Boolean) }
 | 
			
		||||
    def ca_file_handles_most_https_certificates?
 | 
			
		||||
      # The system CA file is too old for some modern HTTPS certificates on
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,8 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "extend/os/mac/dependency_collector" if OS.mac?
 | 
			
		||||
if OS.mac?
 | 
			
		||||
  require "extend/os/mac/dependency_collector"
 | 
			
		||||
elsif OS.linux?
 | 
			
		||||
  require "extend/os/linux/dependency_collector"
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										76
									
								
								Library/Homebrew/extend/os/linux/dependency_collector.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								Library/Homebrew/extend/os/linux/dependency_collector.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,76 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "os/linux/glibc"
 | 
			
		||||
 | 
			
		||||
class DependencyCollector
 | 
			
		||||
  extend T::Sig
 | 
			
		||||
 | 
			
		||||
  undef gcc_dep_if_needed
 | 
			
		||||
  undef glibc_dep_if_needed
 | 
			
		||||
  undef init_global_dep_tree_if_needed!
 | 
			
		||||
 | 
			
		||||
  sig { params(related_formula_names: T::Set[String]).returns(T.nilable(Dependency)) }
 | 
			
		||||
  def gcc_dep_if_needed(related_formula_names)
 | 
			
		||||
    return unless DevelopmentTools.system_gcc_too_old?
 | 
			
		||||
    return if related_formula_names.include?(GCC)
 | 
			
		||||
    return if global_dep_tree[GCC]&.intersect?(related_formula_names)
 | 
			
		||||
    return if global_dep_tree[GLIBC]&.intersect?(related_formula_names) # gcc depends on glibc
 | 
			
		||||
 | 
			
		||||
    Dependency.new(GCC)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { params(related_formula_names: T::Set[String]).returns(T.nilable(Dependency)) }
 | 
			
		||||
  def glibc_dep_if_needed(related_formula_names)
 | 
			
		||||
    return unless OS::Linux::Glibc.below_ci_version?
 | 
			
		||||
    return if global_dep_tree[GLIBC]&.intersect?(related_formula_names)
 | 
			
		||||
 | 
			
		||||
    Dependency.new(GLIBC)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  GLIBC = "glibc"
 | 
			
		||||
  GCC = CompilerSelector.preferred_gcc.freeze
 | 
			
		||||
 | 
			
		||||
  # Use class variables to avoid this expensive logic needing to be done more
 | 
			
		||||
  # than once.
 | 
			
		||||
  # rubocop:disable Style/ClassVars
 | 
			
		||||
  @@global_dep_tree = {}
 | 
			
		||||
 | 
			
		||||
  sig { void }
 | 
			
		||||
  def init_global_dep_tree_if_needed!
 | 
			
		||||
    return unless DevelopmentTools.build_system_too_old?
 | 
			
		||||
    return if @@global_dep_tree.present?
 | 
			
		||||
 | 
			
		||||
    # Defined in precedence order (gcc depends on glibc).
 | 
			
		||||
    global_deps = [GLIBC, GCC].freeze
 | 
			
		||||
 | 
			
		||||
    @@global_dep_tree = global_deps.to_h { |name| [name, Set.new([name])] }
 | 
			
		||||
 | 
			
		||||
    global_deps.each do |global_dep_name|
 | 
			
		||||
      # This is an arbitrary number picked based on testing the current tree
 | 
			
		||||
      # depth and just to ensure that this doesn't loop indefinitely if we
 | 
			
		||||
      # introduce a circular dependency by mistake.
 | 
			
		||||
      maximum_tree_depth = 10
 | 
			
		||||
      current_tree_depth = 0
 | 
			
		||||
 | 
			
		||||
      deps = Formula[global_dep_name].deps
 | 
			
		||||
      while deps.present?
 | 
			
		||||
        current_tree_depth += 1
 | 
			
		||||
        if current_tree_depth > maximum_tree_depth
 | 
			
		||||
          raise "maximum tree depth (#{maximum_tree_depth}) exceeded calculating #{global_dep_name} dependency tree!"
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        @@global_dep_tree[global_dep_name].merge(deps.map(&:name))
 | 
			
		||||
        deps = deps.flat_map { |dep| dep.to_formula.deps }
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { returns(T::Hash[String, T::Set[String]]) }
 | 
			
		||||
  def global_dep_tree
 | 
			
		||||
    @@global_dep_tree
 | 
			
		||||
  end
 | 
			
		||||
  # rubocop:enable Style/ClassVars
 | 
			
		||||
end
 | 
			
		||||
@ -21,6 +21,18 @@ class DevelopmentTools
 | 
			
		||||
      :gcc
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(T::Boolean) }
 | 
			
		||||
    def build_system_too_old?
 | 
			
		||||
      return @build_system_too_old if defined? @build_system_too_old
 | 
			
		||||
 | 
			
		||||
      @build_system_too_old = (system_gcc_too_old? || OS::Linux::Glibc.below_ci_version?)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(T::Boolean) }
 | 
			
		||||
    def system_gcc_too_old?
 | 
			
		||||
      gcc_version("gcc") < OS::LINUX_GCC_CI_VERSION
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig { returns(T::Hash[String, T.nilable(String)]) }
 | 
			
		||||
    def build_system_info
 | 
			
		||||
      generic_build_system_info.merge({
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ class Formula
 | 
			
		||||
  undef shared_library
 | 
			
		||||
  undef loader_path
 | 
			
		||||
  undef deuniversalize_machos
 | 
			
		||||
  undef add_global_deps_to_spec
 | 
			
		||||
 | 
			
		||||
  sig { params(name: String, version: T.nilable(T.any(String, Integer))).returns(String) }
 | 
			
		||||
  def shared_library(name, version = nil)
 | 
			
		||||
@ -23,4 +24,20 @@ class Formula
 | 
			
		||||
 | 
			
		||||
  sig { params(targets: T.nilable(T.any(Pathname, String))).void }
 | 
			
		||||
  def deuniversalize_machos(*targets); end
 | 
			
		||||
 | 
			
		||||
  sig { params(spec: SoftwareSpec).void }
 | 
			
		||||
  def add_global_deps_to_spec(spec)
 | 
			
		||||
    @global_deps ||= begin
 | 
			
		||||
      dependency_collector = spec.dependency_collector
 | 
			
		||||
      related_formula_names = Set.new([
 | 
			
		||||
        name,
 | 
			
		||||
        *versioned_formulae_names,
 | 
			
		||||
      ])
 | 
			
		||||
      [
 | 
			
		||||
        dependency_collector.gcc_dep_if_needed(related_formula_names),
 | 
			
		||||
        dependency_collector.glibc_dep_if_needed(related_formula_names),
 | 
			
		||||
      ].compact.freeze
 | 
			
		||||
    end
 | 
			
		||||
    @global_deps.each { |dep| spec.dependency_collector.add(dep) }
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -80,9 +80,5 @@ class LinkageChecker
 | 
			
		||||
    @unwanted_system_dylibs = @system_dylibs.reject do |s|
 | 
			
		||||
      SYSTEM_LIBRARY_ALLOWLIST.include? File.basename(s)
 | 
			
		||||
    end
 | 
			
		||||
    # FIXME: Remove this when these dependencies are injected correctly (e.g. through `DependencyCollector`)
 | 
			
		||||
    # See discussion at
 | 
			
		||||
    #   https://github.com/Homebrew/brew/pull/13577
 | 
			
		||||
    @undeclared_deps -= [CompilerSelector.preferred_gcc, "glibc", "gcc"]
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -262,9 +262,13 @@ class Formula
 | 
			
		||||
    return unless spec.url
 | 
			
		||||
 | 
			
		||||
    spec.owner = self
 | 
			
		||||
    add_global_deps_to_spec(spec)
 | 
			
		||||
    instance_variable_set("@#{name}", spec)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { params(spec: SoftwareSpec).void }
 | 
			
		||||
  def add_global_deps_to_spec(spec); end
 | 
			
		||||
 | 
			
		||||
  def determine_active_spec(requested)
 | 
			
		||||
    spec = send(requested) || stable || head
 | 
			
		||||
    spec || raise(FormulaSpecificationError, "formulae require at least a URL")
 | 
			
		||||
@ -443,7 +447,7 @@ class Formula
 | 
			
		||||
  # Returns any `@`-versioned formulae names for any formula (including versioned formulae).
 | 
			
		||||
  sig { returns(T::Array[String]) }
 | 
			
		||||
  def versioned_formulae_names
 | 
			
		||||
    @versioned_formulae_names ||= Pathname.glob(path.to_s.gsub(/(@[\d.]+)?\.rb$/, "@*.rb")).map do |versioned_path|
 | 
			
		||||
    Pathname.glob(path.to_s.gsub(/(@[\d.]+)?\.rb$/, "@*.rb")).map do |versioned_path|
 | 
			
		||||
      next if versioned_path == path
 | 
			
		||||
 | 
			
		||||
      versioned_path.basename(".rb").to_s
 | 
			
		||||
@ -453,7 +457,7 @@ class Formula
 | 
			
		||||
  # Returns any `@`-versioned Formula objects for any Formula (including versioned formulae).
 | 
			
		||||
  sig { returns(T::Array[Formula]) }
 | 
			
		||||
  def versioned_formulae
 | 
			
		||||
    @versioned_formulae ||= versioned_formulae_names.map do |name|
 | 
			
		||||
    versioned_formulae_names.map do |name|
 | 
			
		||||
      Formula[name]
 | 
			
		||||
    rescue FormulaUnavailableError
 | 
			
		||||
      nil
 | 
			
		||||
 | 
			
		||||
@ -581,11 +581,9 @@ class FormulaInstaller
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def expand_dependencies_for_formula(formula, inherited_options)
 | 
			
		||||
    any_bottle_used = false
 | 
			
		||||
 | 
			
		||||
    # Cache for this expansion only. FormulaInstaller has a lot of inputs which can alter expansion.
 | 
			
		||||
    cache_key = "FormulaInstaller-#{formula.full_name}-#{Time.now.to_f}"
 | 
			
		||||
    expanded_deps = Dependency.expand(formula, cache_key: cache_key) do |dependent, dep|
 | 
			
		||||
    Dependency.expand(formula, cache_key: cache_key) do |dependent, dep|
 | 
			
		||||
      inherited_options[dep.name] |= inherited_options_for(dep)
 | 
			
		||||
      build = effective_build_options_for(
 | 
			
		||||
        dependent,
 | 
			
		||||
@ -601,36 +599,14 @@ class FormulaInstaller
 | 
			
		||||
        Dependency.prune
 | 
			
		||||
      elsif dep.satisfied?(inherited_options[dep.name])
 | 
			
		||||
        Dependency.skip
 | 
			
		||||
      else
 | 
			
		||||
        any_bottle_used ||= install_bottle_for?(dep.to_formula, build)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    [expanded_deps, any_bottle_used]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def expand_dependencies
 | 
			
		||||
    inherited_options = Hash.new { |hash, key| hash[key] = Options.new }
 | 
			
		||||
    any_bottle_used = pour_bottle?
 | 
			
		||||
 | 
			
		||||
    expanded_deps, any_dep_bottle_used = expand_dependencies_for_formula(formula, inherited_options)
 | 
			
		||||
    any_bottle_used ||= any_dep_bottle_used
 | 
			
		||||
 | 
			
		||||
    # We require some dependencies (glibc, GCC 5, etc.) if binaries were built.
 | 
			
		||||
    # Native binaries shouldn't exist in cross-platform `all` bottles.
 | 
			
		||||
    if any_bottle_used && !formula.bottled?(:all) && !Keg.bottle_dependencies.empty?
 | 
			
		||||
      all_bottle_deps = Keg.bottle_dependencies.flat_map do |bottle_dep|
 | 
			
		||||
        bottle_dep.recursive_dependencies.map(&:name) + [bottle_dep.name]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      if all_bottle_deps.exclude?(formula.name)
 | 
			
		||||
        bottle_deps = Keg.bottle_dependencies.flat_map do |bottle_dep|
 | 
			
		||||
          expanded_bottle_deps, = expand_dependencies_for_formula(bottle_dep, inherited_options)
 | 
			
		||||
          expanded_bottle_deps
 | 
			
		||||
        end
 | 
			
		||||
        expanded_deps = Dependency.merge_repeats(bottle_deps + expanded_deps)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
    expanded_deps = expand_dependencies_for_formula(formula, inherited_options)
 | 
			
		||||
 | 
			
		||||
    expanded_deps.map { |dep| [dep, inherited_options[dep.name]] }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -366,17 +366,6 @@ class Keg
 | 
			
		||||
  def self.file_linked_libraries(_file, _string)
 | 
			
		||||
    []
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def self.bottle_dependencies
 | 
			
		||||
    return [] unless Homebrew::SimulateSystem.simulating_or_running_on_linux?
 | 
			
		||||
 | 
			
		||||
    @bottle_dependencies ||= begin
 | 
			
		||||
      formulae = []
 | 
			
		||||
      gcc = Formulary.factory(CompilerSelector.preferred_gcc)
 | 
			
		||||
      formulae << gcc if DevelopmentTools.gcc_version("gcc") < gcc.version.to_i
 | 
			
		||||
      formulae
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
require "extend/os/keg_relocate"
 | 
			
		||||
 | 
			
		||||
@ -44,6 +44,11 @@ module OS
 | 
			
		||||
      def below_minimum_version?
 | 
			
		||||
        system_version < minimum_version
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T::Boolean) }
 | 
			
		||||
      def below_ci_version?
 | 
			
		||||
        system_version < LINUX_GLIBC_CI_VERSION
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -50,6 +50,11 @@ class SoftwareSpec
 | 
			
		||||
    @uses_from_macos_elements = []
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def initialize_copy(other)
 | 
			
		||||
    super
 | 
			
		||||
    @dependency_collector = @dependency_collector.dup
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def owner=(owner)
 | 
			
		||||
    @name = owner.name
 | 
			
		||||
    @full_name = owner.full_name
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,20 @@ require "installed_dependents"
 | 
			
		||||
describe InstalledDependents do
 | 
			
		||||
  include FileUtils
 | 
			
		||||
 | 
			
		||||
  def setup_test_keg(name, version)
 | 
			
		||||
  def stub_formula(name, version = "1.0", &block)
 | 
			
		||||
    f = formula(name) do
 | 
			
		||||
      url "#{name}-#{version}"
 | 
			
		||||
 | 
			
		||||
      instance_eval(&block) if block
 | 
			
		||||
    end
 | 
			
		||||
    stub_formula_loader f
 | 
			
		||||
    stub_formula_loader f, "homebrew/core/#{f}"
 | 
			
		||||
    f
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def setup_test_keg(name, version, &block)
 | 
			
		||||
    stub_formula(name, version, &block)
 | 
			
		||||
 | 
			
		||||
    path = HOMEBREW_CELLAR/name/version
 | 
			
		||||
    (path/"bin").mkpath
 | 
			
		||||
 | 
			
		||||
@ -18,27 +31,25 @@ describe InstalledDependents do
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  let!(:keg) { setup_test_keg("foo", "1.0") }
 | 
			
		||||
  let!(:keg_only_keg) do
 | 
			
		||||
    setup_test_keg("foo-keg-only", "1.0") do
 | 
			
		||||
      keg_only "a good reason"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "::find_some_installed_dependents" do
 | 
			
		||||
    def stub_formula_name(name)
 | 
			
		||||
      f = formula(name) { url "foo-1.0" }
 | 
			
		||||
      stub_formula_loader f
 | 
			
		||||
      stub_formula_loader f, "homebrew/core/#{f}"
 | 
			
		||||
      f
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def setup_test_keg(name, version)
 | 
			
		||||
      f = stub_formula_name(name)
 | 
			
		||||
    def setup_test_keg(name, version, &block)
 | 
			
		||||
      keg = super
 | 
			
		||||
      Tab.create(f, DevelopmentTools.default_compiler, :libcxx).write
 | 
			
		||||
      Tab.create(keg.to_formula, DevelopmentTools.default_compiler, :libcxx).write
 | 
			
		||||
      keg
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    before do
 | 
			
		||||
      keg.link
 | 
			
		||||
      keg_only_keg.optlink
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def alter_tab(keg = dependent)
 | 
			
		||||
    def alter_tab(keg)
 | 
			
		||||
      tab = Tab.for_keg(keg)
 | 
			
		||||
      yield tab
 | 
			
		||||
      tab.write
 | 
			
		||||
@ -46,24 +57,26 @@ describe InstalledDependents do
 | 
			
		||||
 | 
			
		||||
    # 1.1.6 is the earliest version of Homebrew that generates correct runtime
 | 
			
		||||
    # dependency lists in {Tab}s.
 | 
			
		||||
    def dependencies(deps, homebrew_version: "1.1.6")
 | 
			
		||||
      alter_tab do |tab|
 | 
			
		||||
    def tab_dependencies(keg, deps, homebrew_version: "1.1.6")
 | 
			
		||||
      alter_tab(keg) do |tab|
 | 
			
		||||
        tab.homebrew_version = homebrew_version
 | 
			
		||||
        tab.tabfile = dependent/Tab::FILENAME
 | 
			
		||||
        tab.tabfile = keg/Tab::FILENAME
 | 
			
		||||
        tab.runtime_dependencies = deps
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def unreliable_dependencies(deps)
 | 
			
		||||
    def unreliable_tab_dependencies(keg, deps)
 | 
			
		||||
      # 1.1.5 is (hopefully!) the last version of Homebrew that generates
 | 
			
		||||
      # incorrect runtime dependency lists in {Tab}s.
 | 
			
		||||
      dependencies(deps, homebrew_version: "1.1.5")
 | 
			
		||||
      tab_dependencies(keg, deps, homebrew_version: "1.1.5")
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    let(:dependent) { setup_test_keg("bar", "1.0") }
 | 
			
		||||
 | 
			
		||||
    specify "a dependency with no Tap in Tab" do
 | 
			
		||||
      tap_dep = setup_test_keg("baz", "1.0")
 | 
			
		||||
      dependent = setup_test_keg("bar", "1.0") do
 | 
			
		||||
        depends_on "foo"
 | 
			
		||||
        depends_on "baz"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # allow tap_dep to be linked too
 | 
			
		||||
      FileUtils.rm_r tap_dep/"bin"
 | 
			
		||||
@ -71,83 +84,93 @@ describe InstalledDependents do
 | 
			
		||||
 | 
			
		||||
      alter_tab(keg) { |t| t.source["tap"] = nil }
 | 
			
		||||
 | 
			
		||||
      dependencies nil
 | 
			
		||||
      Formula["bar"].class.depends_on "foo"
 | 
			
		||||
      Formula["bar"].class.depends_on "baz"
 | 
			
		||||
      tab_dependencies dependent, nil
 | 
			
		||||
 | 
			
		||||
      result = described_class.find_some_installed_dependents([keg, tap_dep])
 | 
			
		||||
      expect(result).to eq([[keg, tap_dep], ["bar"]])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    specify "no dependencies anywhere" do
 | 
			
		||||
      dependencies nil
 | 
			
		||||
      dependent = setup_test_keg("bar", "1.0")
 | 
			
		||||
      tab_dependencies dependent, nil
 | 
			
		||||
      expect(described_class.find_some_installed_dependents([keg])).to be_nil
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    specify "missing Formula dependency" do
 | 
			
		||||
      dependencies nil
 | 
			
		||||
      Formula["bar"].class.depends_on "foo"
 | 
			
		||||
      dependent = setup_test_keg("bar", "1.0") do
 | 
			
		||||
        depends_on "foo"
 | 
			
		||||
      end
 | 
			
		||||
      tab_dependencies dependent, nil
 | 
			
		||||
      expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar"]])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    specify "uninstalling dependent and dependency" do
 | 
			
		||||
      dependencies nil
 | 
			
		||||
      Formula["bar"].class.depends_on "foo"
 | 
			
		||||
      dependent = setup_test_keg("bar", "1.0") do
 | 
			
		||||
        depends_on "foo"
 | 
			
		||||
      end
 | 
			
		||||
      tab_dependencies dependent, nil
 | 
			
		||||
      expect(described_class.find_some_installed_dependents([keg, dependent])).to be_nil
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    specify "renamed dependency" do
 | 
			
		||||
      dependencies nil
 | 
			
		||||
      dependent = setup_test_keg("bar", "1.0") do
 | 
			
		||||
        depends_on "foo"
 | 
			
		||||
      end
 | 
			
		||||
      tab_dependencies dependent, nil
 | 
			
		||||
 | 
			
		||||
      stub_formula_loader Formula["foo"], "homebrew/core/foo-old"
 | 
			
		||||
      renamed_path = HOMEBREW_CELLAR/"foo-old"
 | 
			
		||||
      (HOMEBREW_CELLAR/"foo").rename(renamed_path)
 | 
			
		||||
      renamed_keg = Keg.new(renamed_path/"1.0")
 | 
			
		||||
 | 
			
		||||
      Formula["bar"].class.depends_on "foo"
 | 
			
		||||
      renamed_keg = Keg.new(renamed_path/keg.version.to_s)
 | 
			
		||||
 | 
			
		||||
      result = described_class.find_some_installed_dependents([renamed_keg])
 | 
			
		||||
      expect(result).to eq([[renamed_keg], ["bar"]])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    specify "empty dependencies in Tab" do
 | 
			
		||||
      dependencies []
 | 
			
		||||
      dependent = setup_test_keg("bar", "1.0")
 | 
			
		||||
      tab_dependencies dependent, []
 | 
			
		||||
      expect(described_class.find_some_installed_dependents([keg])).to be_nil
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    specify "same name but different version in Tab" do
 | 
			
		||||
      dependencies [{ "full_name" => "foo", "version" => "1.1" }]
 | 
			
		||||
      dependent = setup_test_keg("bar", "1.0")
 | 
			
		||||
      tab_dependencies dependent, [{ "full_name" => keg.name, "version" => "1.1" }]
 | 
			
		||||
      expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar"]])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    specify "different name and same version in Tab" do
 | 
			
		||||
      stub_formula_name("baz")
 | 
			
		||||
      dependencies [{ "full_name" => "baz", "version" => keg.version.to_s }]
 | 
			
		||||
      stub_formula("baz")
 | 
			
		||||
      dependent = setup_test_keg("bar", "1.0")
 | 
			
		||||
      tab_dependencies dependent, [{ "full_name" => "baz", "version" => keg.version.to_s }]
 | 
			
		||||
      expect(described_class.find_some_installed_dependents([keg])).to be_nil
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    specify "same name and version in Tab" do
 | 
			
		||||
      dependencies [{ "full_name" => "foo", "version" => "1.0" }]
 | 
			
		||||
      dependent = setup_test_keg("bar", "1.0")
 | 
			
		||||
      tab_dependencies dependent, [{ "full_name" => keg.name, "version" => keg.version.to_s }]
 | 
			
		||||
      expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar"]])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    specify "fallback for old versions" do
 | 
			
		||||
      unreliable_dependencies [{ "full_name" => "baz", "version" => "1.0" }]
 | 
			
		||||
      Formula["bar"].class.depends_on "foo"
 | 
			
		||||
      dependent = setup_test_keg("bar", "1.0") do
 | 
			
		||||
        depends_on "foo"
 | 
			
		||||
      end
 | 
			
		||||
      unreliable_tab_dependencies dependent, [{ "full_name" => "baz", "version" => "1.0" }]
 | 
			
		||||
      expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar"]])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    specify "non-opt-linked" do
 | 
			
		||||
      keg.remove_opt_record
 | 
			
		||||
      dependencies [{ "full_name" => "foo", "version" => "1.0" }]
 | 
			
		||||
      dependent = setup_test_keg("bar", "1.0")
 | 
			
		||||
      tab_dependencies dependent, [{ "full_name" => keg.name, "version" => keg.version.to_s }]
 | 
			
		||||
      expect(described_class.find_some_installed_dependents([keg])).to be_nil
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    specify "keg-only" do
 | 
			
		||||
      keg.unlink
 | 
			
		||||
      Formula["foo"].class.keg_only "a good reason"
 | 
			
		||||
      dependencies [{ "full_name" => "foo", "version" => "1.1" }] # different version
 | 
			
		||||
      expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar"]])
 | 
			
		||||
      dependent = setup_test_keg("bar", "1.0")
 | 
			
		||||
      tab_dependencies dependent, [{ "full_name" => keg_only_keg.name, "version" => "1.1" }] # different version
 | 
			
		||||
      expect(described_class.find_some_installed_dependents([keg_only_keg])).to eq([[keg_only_keg], ["bar"]])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def stub_cask_name(name, version, dependency)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user