upgrade, outdated: follow alias changes
This commit is contained in:
		
							parent
							
								
									3d559fa796
								
							
						
					
					
						commit
						2a683f2569
					
				@ -43,15 +43,26 @@ module Homebrew
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    outdated_formulae.each do |f|
 | 
					    outdated_formulae.each do |f|
 | 
				
			||||||
      if verbose
 | 
					      if verbose
 | 
				
			||||||
        outdated_versions = f.outdated_versions(fetch_head: fetch_head)
 | 
					        outdated_kegs = f.outdated_kegs(fetch_head: fetch_head)
 | 
				
			||||||
        current_version = if f.head? && outdated_versions.any? { |v| v.to_s == f.pkg_version.to_s }
 | 
					
 | 
				
			||||||
 | 
					        current_version = if f.alias_changed?
 | 
				
			||||||
 | 
					          latest = f.latest_formula
 | 
				
			||||||
 | 
					          "#{latest.name} (#{latest.pkg_version})"
 | 
				
			||||||
 | 
					        elsif f.head? && outdated_kegs.any? { |k| k.version.to_s == f.pkg_version.to_s }
 | 
				
			||||||
 | 
					          # There is a newer HEAD but the version number has not changed.
 | 
				
			||||||
          "latest HEAD"
 | 
					          "latest HEAD"
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
          f.pkg_version.to_s
 | 
					          f.pkg_version.to_s
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
        puts "#{f.full_name} (#{outdated_versions.join(", ")}) < #{current_version}"
 | 
					
 | 
				
			||||||
 | 
					        outdated_versions = outdated_kegs.
 | 
				
			||||||
 | 
					          group_by(&:name).
 | 
				
			||||||
 | 
					          sort_by(&:first).
 | 
				
			||||||
 | 
					          map { |name, kegs| "#{name} (#{kegs.map(&:version) * ", "})" } * ", "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        puts "#{outdated_versions} < #{current_version}"
 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
        puts f.full_name
 | 
					        puts f.full_installed_specified_name
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@ -62,7 +73,7 @@ module Homebrew
 | 
				
			|||||||
    outdated_formulae = formulae.select { |f| f.outdated?(fetch_head: fetch_head) }
 | 
					    outdated_formulae = formulae.select { |f| f.outdated?(fetch_head: fetch_head) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    outdated = outdated_formulae.each do |f|
 | 
					    outdated = outdated_formulae.each do |f|
 | 
				
			||||||
      outdated_versions = f.outdated_versions(fetch_head: fetch_head)
 | 
					      outdated_versions = f.outdated_kegs(fetch_head: fetch_head).map(&:version)
 | 
				
			||||||
      current_version = if f.head? && outdated_versions.any? { |v| v.to_s == f.pkg_version.to_s }
 | 
					      current_version = if f.head? && outdated_versions.any? { |v| v.to_s == f.pkg_version.to_s }
 | 
				
			||||||
        "HEAD"
 | 
					        "HEAD"
 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
 | 
				
			|||||||
@ -37,10 +37,10 @@ module Homebrew
 | 
				
			|||||||
      (ARGV.resolved_formulae - outdated).each do |f|
 | 
					      (ARGV.resolved_formulae - outdated).each do |f|
 | 
				
			||||||
        versions = f.installed_kegs.map(&:version)
 | 
					        versions = f.installed_kegs.map(&:version)
 | 
				
			||||||
        if versions.empty?
 | 
					        if versions.empty?
 | 
				
			||||||
          onoe "#{f.full_name} not installed"
 | 
					          onoe "#{f.full_specified_name} not installed"
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
          version = versions.max
 | 
					          version = versions.max
 | 
				
			||||||
          onoe "#{f.full_name} #{version} already installed"
 | 
					          onoe "#{f.full_specified_name} #{version} already installed"
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
      exit 1 if outdated.empty?
 | 
					      exit 1 if outdated.empty?
 | 
				
			||||||
@ -51,19 +51,21 @@ module Homebrew
 | 
				
			|||||||
      outdated -= pinned
 | 
					      outdated -= pinned
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if outdated.empty?
 | 
					    formulae_to_install = outdated.map(&:latest_formula)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if formulae_to_install.empty?
 | 
				
			||||||
      oh1 "No packages to upgrade"
 | 
					      oh1 "No packages to upgrade"
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      oh1 "Upgrading #{outdated.length} outdated package#{plural(outdated.length)}, with result:"
 | 
					      oh1 "Upgrading #{formulae_to_install.length} outdated package#{plural(formulae_to_install.length)}, with result:"
 | 
				
			||||||
      puts outdated.map { |f| "#{f.full_name} #{f.pkg_version}" } * ", "
 | 
					      puts formulae_to_install.map { |f| "#{f.full_specified_name} #{f.pkg_version}" } * ", "
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unless upgrade_pinned? || pinned.empty?
 | 
					    unless upgrade_pinned? || pinned.empty?
 | 
				
			||||||
      oh1 "Not upgrading #{pinned.length} pinned package#{plural(pinned.length)}:"
 | 
					      oh1 "Not upgrading #{pinned.length} pinned package#{plural(pinned.length)}:"
 | 
				
			||||||
      puts pinned.map { |f| "#{f.full_name} #{f.pkg_version}" } * ", "
 | 
					      puts pinned.map { |f| "#{f.full_specified_name} #{f.pkg_version}" } * ", "
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    outdated.each do |f|
 | 
					    formulae_to_install.each do |f|
 | 
				
			||||||
      upgrade_formula(f)
 | 
					      upgrade_formula(f)
 | 
				
			||||||
      next unless ARGV.include?("--cleanup")
 | 
					      next unless ARGV.include?("--cleanup")
 | 
				
			||||||
      next unless f.installed?
 | 
					      next unless f.installed?
 | 
				
			||||||
@ -76,7 +78,11 @@ module Homebrew
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def upgrade_formula(f)
 | 
					  def upgrade_formula(f)
 | 
				
			||||||
    outdated_keg = Keg.new(f.linked_keg.resolved_path) if f.linked_keg.directory?
 | 
					    formulae_maybe_with_kegs = [f] + f.old_installed_formulae
 | 
				
			||||||
 | 
					    outdated_kegs = formulae_maybe_with_kegs.
 | 
				
			||||||
 | 
					      map(&:linked_keg).
 | 
				
			||||||
 | 
					      select(&:directory?).
 | 
				
			||||||
 | 
					      map { |k| Keg.new(k.resolved_path) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fi = FormulaInstaller.new(f)
 | 
					    fi = FormulaInstaller.new(f)
 | 
				
			||||||
    fi.options             = f.build.used_options
 | 
					    fi.options             = f.build.used_options
 | 
				
			||||||
@ -87,12 +93,12 @@ module Homebrew
 | 
				
			|||||||
    fi.debug               = ARGV.debug?
 | 
					    fi.debug               = ARGV.debug?
 | 
				
			||||||
    fi.prelude
 | 
					    fi.prelude
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    oh1 "Upgrading #{f.full_name}"
 | 
					    oh1 "Upgrading #{f.full_specified_name}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # first we unlink the currently active keg for this formula otherwise it is
 | 
					    # first we unlink the currently active keg for this formula otherwise it is
 | 
				
			||||||
    # possible for the existing build to interfere with the build we are about to
 | 
					    # possible for the existing build to interfere with the build we are about to
 | 
				
			||||||
    # do! Seriously, it happens!
 | 
					    # do! Seriously, it happens!
 | 
				
			||||||
    outdated_keg.unlink if outdated_keg
 | 
					    outdated_kegs.each(&:unlink)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fi.install
 | 
					    fi.install
 | 
				
			||||||
    fi.finish
 | 
					    fi.finish
 | 
				
			||||||
@ -117,7 +123,7 @@ module Homebrew
 | 
				
			|||||||
  ensure
 | 
					  ensure
 | 
				
			||||||
    # restore previous installation state if build failed
 | 
					    # restore previous installation state if build failed
 | 
				
			||||||
    begin
 | 
					    begin
 | 
				
			||||||
      outdated_keg.link if outdated_keg && !f.installed?
 | 
					      outdated_kegs.each(&:link) if !f.installed?
 | 
				
			||||||
    rescue
 | 
					    rescue
 | 
				
			||||||
      nil
 | 
					      nil
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
				
			|||||||
@ -37,11 +37,23 @@ module HomebrewArgvExtension
 | 
				
			|||||||
            f.version.update_commit(k.version.version.commit) if k.version.head?
 | 
					            f.version.update_commit(k.version.version.commit) if k.version.head?
 | 
				
			||||||
          end
 | 
					          end
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
        f
 | 
					 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
        rack = Formulary.to_rack(name)
 | 
					        rack = Formulary.to_rack(name)
 | 
				
			||||||
        Formulary.from_rack(rack, spec(nil))
 | 
					        alias_path = Formulary.factory(name).alias_path
 | 
				
			||||||
 | 
					        f = Formulary.from_rack(rack, spec(nil), alias_path: alias_path)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # If this formula was installed with an alias that has since changed,
 | 
				
			||||||
 | 
					      # then it was specified explicitly in ARGV. (Using the alias would
 | 
				
			||||||
 | 
					      # instead have found the new formula.)
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      # Because of this, the user is referring to this specific formula,
 | 
				
			||||||
 | 
					      # not any formula targetted by the same alias, so in this context
 | 
				
			||||||
 | 
					      # the formula shouldn't be considered outdated if the alias used to
 | 
				
			||||||
 | 
					      # install it has changed.
 | 
				
			||||||
 | 
					      f.follow_installed_alias = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      f
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -60,16 +60,24 @@ class Formula
 | 
				
			|||||||
  # e.g. `this-formula`
 | 
					  # e.g. `this-formula`
 | 
				
			||||||
  attr_reader :name
 | 
					  attr_reader :name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # The name that was used to identify this {Formula}.
 | 
					  # The path to the alias that was used to identify this {Formula}.
 | 
				
			||||||
  # Could be the name of the {Formula}, or an alias.
 | 
					  # e.g. `/usr/local/Library/Taps/homebrew/homebrew-core/Aliases/another-name-for-this-formula`
 | 
				
			||||||
  # e.g. `another-name-for-this-formula`
 | 
					 | 
				
			||||||
  attr_reader :alias_path
 | 
					  attr_reader :alias_path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # The name of the alias that was used to identify this {Formula}.
 | 
				
			||||||
 | 
					  # e.g. `another-name-for-this-formula`
 | 
				
			||||||
 | 
					  attr_reader :alias_name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # The fully-qualified name of this {Formula}.
 | 
					  # The fully-qualified name of this {Formula}.
 | 
				
			||||||
  # For core formula it's the same as {#name}.
 | 
					  # For core formula it's the same as {#name}.
 | 
				
			||||||
  # e.g. `homebrew/tap-name/this-formula`
 | 
					  # e.g. `homebrew/tap-name/this-formula`
 | 
				
			||||||
  attr_reader :full_name
 | 
					  attr_reader :full_name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # The fully-qualified alias referring to this {Formula}.
 | 
				
			||||||
 | 
					  # For core formula it's the same as {#alias_name}.
 | 
				
			||||||
 | 
					  # e.g. `homebrew/tap-name/another-name-for-this-formula`
 | 
				
			||||||
 | 
					  attr_reader :full_alias_name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # The full path to this {Formula}.
 | 
					  # The full path to this {Formula}.
 | 
				
			||||||
  # e.g. `/usr/local/Library/Taps/homebrew/homebrew-core/Formula/this-formula.rb`
 | 
					  # e.g. `/usr/local/Library/Taps/homebrew/homebrew-core/Formula/this-formula.rb`
 | 
				
			||||||
  attr_reader :path
 | 
					  attr_reader :path
 | 
				
			||||||
@ -149,25 +157,31 @@ class Formula
 | 
				
			|||||||
  # @return [BuildOptions]
 | 
					  # @return [BuildOptions]
 | 
				
			||||||
  attr_accessor :build
 | 
					  attr_accessor :build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # A {Boolean} indicating whether this formula should be considered outdated
 | 
				
			||||||
 | 
					  # if the target of the alias it was installed with has since changed.
 | 
				
			||||||
 | 
					  # Defaults to true.
 | 
				
			||||||
 | 
					  # @return [Boolean]
 | 
				
			||||||
 | 
					  attr_accessor :follow_installed_alias
 | 
				
			||||||
 | 
					  alias follow_installed_alias? follow_installed_alias
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # @private
 | 
					  # @private
 | 
				
			||||||
  def initialize(name, path, spec, alias_path: nil)
 | 
					  def initialize(name, path, spec, alias_path: nil)
 | 
				
			||||||
    @name = name
 | 
					    @name = name
 | 
				
			||||||
    @path = path
 | 
					    @path = path
 | 
				
			||||||
    @alias_path = alias_path
 | 
					    @alias_path = alias_path
 | 
				
			||||||
 | 
					    @alias_name = File.basename(alias_path) if alias_path
 | 
				
			||||||
    @revision = self.class.revision || 0
 | 
					    @revision = self.class.revision || 0
 | 
				
			||||||
    @version_scheme = self.class.version_scheme || 0
 | 
					    @version_scheme = self.class.version_scheme || 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if path == Formulary.core_path(name)
 | 
					    @tap = if path == Formulary.core_path(name)
 | 
				
			||||||
      @tap = CoreTap.instance
 | 
					      CoreTap.instance
 | 
				
			||||||
      @full_name = name
 | 
					 | 
				
			||||||
    elsif path.to_s =~ HOMEBREW_TAP_PATH_REGEX
 | 
					    elsif path.to_s =~ HOMEBREW_TAP_PATH_REGEX
 | 
				
			||||||
      @tap = Tap.fetch($1, $2)
 | 
					      Tap.fetch($1, $2)
 | 
				
			||||||
      @full_name = "#{@tap}/#{name}"
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      @tap = nil
 | 
					 | 
				
			||||||
      @full_name = name
 | 
					 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @full_name = get_full_name(name)
 | 
				
			||||||
 | 
					    @full_alias_name = get_full_name(@alias_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    set_spec :stable
 | 
					    set_spec :stable
 | 
				
			||||||
    set_spec :devel
 | 
					    set_spec :devel
 | 
				
			||||||
    set_spec :head
 | 
					    set_spec :head
 | 
				
			||||||
@ -183,6 +197,7 @@ class Formula
 | 
				
			|||||||
    validate_attributes!
 | 
					    validate_attributes!
 | 
				
			||||||
    @build = active_spec.build
 | 
					    @build = active_spec.build
 | 
				
			||||||
    @pin = FormulaPin.new(self)
 | 
					    @pin = FormulaPin.new(self)
 | 
				
			||||||
 | 
					    @follow_installed_alias = true
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # @private
 | 
					  # @private
 | 
				
			||||||
@ -197,6 +212,16 @@ class Formula
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  private
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Allow full name logic to be re-used between names, aliases,
 | 
				
			||||||
 | 
					  # and installed aliases.
 | 
				
			||||||
 | 
					  def get_full_name(name)
 | 
				
			||||||
 | 
					    if name.nil? || @tap.nil? || @tap.core_tap?
 | 
				
			||||||
 | 
					      name
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      "#{@tap}/#{name}"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def set_spec(name)
 | 
					  def set_spec(name)
 | 
				
			||||||
    spec = self.class.send(name)
 | 
					    spec = self.class.send(name)
 | 
				
			||||||
    if spec.url
 | 
					    if spec.url
 | 
				
			||||||
@ -236,11 +261,39 @@ class Formula
 | 
				
			|||||||
    path if path =~ %r{#{HOMEBREW_TAP_DIR_REGEX}/Aliases}
 | 
					    path if path =~ %r{#{HOMEBREW_TAP_DIR_REGEX}/Aliases}
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def installed_alias_name
 | 
				
			||||||
 | 
					    File.basename(installed_alias_path) if installed_alias_path
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def full_installed_alias_name
 | 
				
			||||||
 | 
					    get_full_name(installed_alias_name)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # The path that was specified to find this formula.
 | 
					  # The path that was specified to find this formula.
 | 
				
			||||||
  def specified_path
 | 
					  def specified_path
 | 
				
			||||||
    alias_path || path
 | 
					    alias_path || path
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # The name specified to find this formula.
 | 
				
			||||||
 | 
					  def specified_name
 | 
				
			||||||
 | 
					    alias_name || name
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # The name (including tap) specified to find this formula.
 | 
				
			||||||
 | 
					  def full_specified_name
 | 
				
			||||||
 | 
					    full_alias_name || full_name
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # The name specified to install this formula.
 | 
				
			||||||
 | 
					  def installed_specified_name
 | 
				
			||||||
 | 
					    installed_alias_name || name
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # The name (including tap) specified to install this formula.
 | 
				
			||||||
 | 
					  def full_installed_specified_name
 | 
				
			||||||
 | 
					    full_installed_alias_name || full_name
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Is the currently active {SoftwareSpec} a {#stable} build?
 | 
					  # Is the currently active {SoftwareSpec} a {#stable} build?
 | 
				
			||||||
  # @private
 | 
					  # @private
 | 
				
			||||||
  def stable?
 | 
					  def stable?
 | 
				
			||||||
@ -1067,39 +1120,77 @@ class Formula
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # @private
 | 
					  # @private
 | 
				
			||||||
  def outdated_versions(options = {})
 | 
					  def outdated_kegs(options = {})
 | 
				
			||||||
    @outdated_versions ||= Hash.new do |cache, key|
 | 
					    @outdated_kegs ||= Hash.new do |cache, key|
 | 
				
			||||||
      raise Migrator::MigrationNeededError, self if migration_needed?
 | 
					      raise Migrator::MigrationNeededError, self if migration_needed?
 | 
				
			||||||
      cache[key] = _outdated_versions(key)
 | 
					      cache[key] = _outdated_kegs(key)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
    @outdated_versions[options]
 | 
					    @outdated_kegs[options]
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def _outdated_versions(options = {})
 | 
					  def _outdated_kegs(options = {})
 | 
				
			||||||
    all_versions = []
 | 
					    all_kegs = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    installed_kegs.each do |keg|
 | 
					    installed_kegs.each do |keg|
 | 
				
			||||||
 | 
					      all_kegs << keg
 | 
				
			||||||
      version = keg.version
 | 
					      version = keg.version
 | 
				
			||||||
      all_versions << version
 | 
					 | 
				
			||||||
      next if version.head?
 | 
					      next if version.head?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      tab = Tab.for_keg(keg)
 | 
					      tab = Tab.for_keg(keg)
 | 
				
			||||||
      next if version_scheme > tab.version_scheme
 | 
					      next if version_scheme > tab.version_scheme
 | 
				
			||||||
      next if version_scheme == tab.version_scheme && pkg_version > version
 | 
					      next if version_scheme == tab.version_scheme && pkg_version > version
 | 
				
			||||||
      return []
 | 
					      next if follow_installed_alias? && installed_alias_target_changed?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return [] # this keg is the current version of the formula, so it's not outdated
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Even if this formula hasn't been installed, there may be installations
 | 
				
			||||||
 | 
					    # of other formulae which used to be targets of the alias currently
 | 
				
			||||||
 | 
					    # targetting this formula. These should be counted as outdated versions.
 | 
				
			||||||
 | 
					    all_kegs.concat old_installed_formulae.flat_map(&:installed_kegs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    head_version = latest_head_version
 | 
					    head_version = latest_head_version
 | 
				
			||||||
    if head_version && !head_version_outdated?(head_version, options)
 | 
					    if head_version && !head_version_outdated?(head_version, options)
 | 
				
			||||||
      []
 | 
					      []
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      all_versions.sort
 | 
					      all_kegs.sort_by(&:version)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def current_installed_alias_target
 | 
				
			||||||
 | 
					    Formulary.factory(installed_alias_path) if installed_alias_path
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Has the target of the alias used to install this formula changed?
 | 
				
			||||||
 | 
					  # Returns false if the formula wasn't installed with an alias.
 | 
				
			||||||
 | 
					  def installed_alias_target_changed?
 | 
				
			||||||
 | 
					    ![self, nil].include?(current_installed_alias_target)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Is this formula the target of an alias used to install an old formula?
 | 
				
			||||||
 | 
					  def supersedes_an_installed_formula?
 | 
				
			||||||
 | 
					    old_installed_formulae.any?
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Has the alias used to install the formula changed, or are different
 | 
				
			||||||
 | 
					  # formulae already installed with this alias?
 | 
				
			||||||
 | 
					  def alias_changed?
 | 
				
			||||||
 | 
					    installed_alias_target_changed? || supersedes_an_installed_formula?
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # If the alias has changed value, return the new formula.
 | 
				
			||||||
 | 
					  # Otherwise, return self.
 | 
				
			||||||
 | 
					  def latest_formula
 | 
				
			||||||
 | 
					    installed_alias_target_changed? ? current_installed_alias_target : self
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def old_installed_formulae
 | 
				
			||||||
 | 
					    alias_path ? self.class.installed_with_alias_path(alias_path) : []
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # @private
 | 
					  # @private
 | 
				
			||||||
  def outdated?(options = {})
 | 
					  def outdated?(options = {})
 | 
				
			||||||
    !outdated_versions(options).empty?
 | 
					    !outdated_kegs(options).empty?
 | 
				
			||||||
  rescue Migrator::MigrationNeededError
 | 
					  rescue Migrator::MigrationNeededError
 | 
				
			||||||
    true
 | 
					    true
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@ -1254,6 +1345,11 @@ class Formula
 | 
				
			|||||||
    end.compact
 | 
					    end.compact
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def self.installed_with_alias_path(alias_path)
 | 
				
			||||||
 | 
					    return [] if alias_path.nil?
 | 
				
			||||||
 | 
					    installed.select { |f| f.installed_alias_path == alias_path }
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # an array of all alias files of core {Formula}
 | 
					  # an array of all alias files of core {Formula}
 | 
				
			||||||
  # @private
 | 
					  # @private
 | 
				
			||||||
  def self.core_alias_files
 | 
					  def self.core_alias_files
 | 
				
			||||||
 | 
				
			|||||||
@ -77,8 +77,11 @@ class Formulary
 | 
				
			|||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Gets the formula instance.
 | 
					    # Gets the formula instance.
 | 
				
			||||||
    def get_formula(spec)
 | 
					    #
 | 
				
			||||||
      klass.new(name, path, spec, alias_path: alias_path)
 | 
					    # `alias_path` can be overridden here in case an alias was used to refer to
 | 
				
			||||||
 | 
					    # a formula that was loaded in another way.
 | 
				
			||||||
 | 
					    def get_formula(spec, alias_path: nil)
 | 
				
			||||||
 | 
					      klass.new(name, path, spec, alias_path: alias_path || self.alias_path)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def klass
 | 
					    def klass
 | 
				
			||||||
@ -103,7 +106,7 @@ class Formulary
 | 
				
			|||||||
      super name, Formulary.path(full_name)
 | 
					      super name, Formulary.path(full_name)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_formula(spec)
 | 
					    def get_formula(spec, alias_path: nil)
 | 
				
			||||||
      formula = super
 | 
					      formula = super
 | 
				
			||||||
      formula.local_bottle_path = @bottle_filename
 | 
					      formula.local_bottle_path = @bottle_filename
 | 
				
			||||||
      formula_version = formula.pkg_version
 | 
					      formula_version = formula.pkg_version
 | 
				
			||||||
@ -120,7 +123,7 @@ class Formulary
 | 
				
			|||||||
      path = alias_path.resolved_path
 | 
					      path = alias_path.resolved_path
 | 
				
			||||||
      name = path.basename(".rb").to_s
 | 
					      name = path.basename(".rb").to_s
 | 
				
			||||||
      super name, path
 | 
					      super name, path
 | 
				
			||||||
      @alias_path = alias_path
 | 
					      @alias_path = alias_path.to_s
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -175,7 +178,7 @@ class Formulary
 | 
				
			|||||||
      super name, path
 | 
					      super name, path
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_formula(spec)
 | 
					    def get_formula(spec, alias_path: nil)
 | 
				
			||||||
      super
 | 
					      super
 | 
				
			||||||
    rescue FormulaUnavailableError => e
 | 
					    rescue FormulaUnavailableError => e
 | 
				
			||||||
      raise TapFormulaUnavailableError.new(tap, name), "", e.backtrace
 | 
					      raise TapFormulaUnavailableError.new(tap, name), "", e.backtrace
 | 
				
			||||||
@ -187,7 +190,7 @@ class Formulary
 | 
				
			|||||||
      super name, Formulary.core_path(name)
 | 
					      super name, Formulary.core_path(name)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_formula(_spec)
 | 
					    def get_formula(_spec, alias_path: nil)
 | 
				
			||||||
      raise FormulaUnavailableError, name
 | 
					      raise FormulaUnavailableError, name
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@ -215,38 +218,42 @@ class Formulary
 | 
				
			|||||||
  # * a formula pathname
 | 
					  # * a formula pathname
 | 
				
			||||||
  # * a formula URL
 | 
					  # * a formula URL
 | 
				
			||||||
  # * a local bottle reference
 | 
					  # * a local bottle reference
 | 
				
			||||||
  def self.factory(ref, spec = :stable)
 | 
					  def self.factory(ref, spec = :stable, alias_path: nil)
 | 
				
			||||||
    loader_for(ref).get_formula(spec)
 | 
					    loader_for(ref).get_formula(spec, alias_path: alias_path)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Return a Formula instance for the given rack.
 | 
					  # Return a Formula instance for the given rack.
 | 
				
			||||||
  # It will auto resolve formula's spec when requested spec is nil
 | 
					  # It will auto resolve formula's spec when requested spec is nil
 | 
				
			||||||
  def self.from_rack(rack, spec = nil)
 | 
					  #
 | 
				
			||||||
 | 
					  # The :alias_path option will be used if the formula is found not to be
 | 
				
			||||||
 | 
					  # installed, and discarded if it is installed because the alias_path used
 | 
				
			||||||
 | 
					  # to install the formula will be set instead.
 | 
				
			||||||
 | 
					  def self.from_rack(rack, spec = nil, alias_path: nil)
 | 
				
			||||||
    kegs = rack.directory? ? rack.subdirs.map { |d| Keg.new(d) } : []
 | 
					    kegs = rack.directory? ? rack.subdirs.map { |d| Keg.new(d) } : []
 | 
				
			||||||
    keg = kegs.detect(&:linked?) || kegs.detect(&:optlinked?) || kegs.max_by(&:version)
 | 
					    keg = kegs.detect(&:linked?) || kegs.detect(&:optlinked?) || kegs.max_by(&:version)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if keg
 | 
					    if keg
 | 
				
			||||||
      from_keg(keg, spec)
 | 
					      from_keg(keg, spec, :alias_path => alias_path)
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      factory(rack.basename.to_s, spec || :stable)
 | 
					      factory(rack.basename.to_s, spec || :stable, :alias_path => alias_path)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Return a Formula instance for the given keg.
 | 
					  # Return a Formula instance for the given keg.
 | 
				
			||||||
  # It will auto resolve formula's spec when requested spec is nil
 | 
					  # It will auto resolve formula's spec when requested spec is nil
 | 
				
			||||||
  def self.from_keg(keg, spec = nil)
 | 
					  def self.from_keg(keg, spec = nil, alias_path: nil)
 | 
				
			||||||
    tab = Tab.for_keg(keg)
 | 
					    tab = Tab.for_keg(keg)
 | 
				
			||||||
    tap = tab.tap
 | 
					    tap = tab.tap
 | 
				
			||||||
    spec ||= tab.spec
 | 
					    spec ||= tab.spec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    f = if tap.nil?
 | 
					    f = if tap.nil?
 | 
				
			||||||
      factory(keg.rack.basename.to_s, spec)
 | 
					      factory(keg.rack.basename.to_s, spec, :alias_path => alias_path)
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      begin
 | 
					      begin
 | 
				
			||||||
        factory("#{tap}/#{keg.rack.basename}", spec)
 | 
					        factory("#{tap}/#{keg.rack.basename}", spec, :alias_path => alias_path)
 | 
				
			||||||
      rescue FormulaUnavailableError
 | 
					      rescue FormulaUnavailableError
 | 
				
			||||||
        # formula may be migrated to different tap. Try to search in core and all taps.
 | 
					        # formula may be migrated to different tap. Try to search in core and all taps.
 | 
				
			||||||
        factory(keg.rack.basename.to_s, spec)
 | 
					        factory(keg.rack.basename.to_s, spec, :alias_path => alias_path)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
    f.build = tab
 | 
					    f.build = tab
 | 
				
			||||||
@ -346,7 +353,7 @@ class Formulary
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def self.core_path(name)
 | 
					  def self.core_path(name)
 | 
				
			||||||
    CoreTap.instance.formula_dir/"#{name.downcase}.rb"
 | 
					    CoreTap.instance.formula_dir/"#{name.to_s.downcase}.rb"
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def self.tap_paths(name, taps = Dir["#{HOMEBREW_LIBRARY}/Taps/*/*/"])
 | 
					  def self.tap_paths(name, taps = Dir["#{HOMEBREW_LIBRARY}/Taps/*/*/"])
 | 
				
			||||||
 | 
				
			|||||||
@ -89,7 +89,7 @@ class FormularyFactoryTest < Homebrew::TestCase
 | 
				
			|||||||
    FileUtils.ln_s @path, alias_path
 | 
					    FileUtils.ln_s @path, alias_path
 | 
				
			||||||
    result = Formulary.factory("foo")
 | 
					    result = Formulary.factory("foo")
 | 
				
			||||||
    assert_kind_of Formula, result
 | 
					    assert_kind_of Formula, result
 | 
				
			||||||
    assert_equal alias_path, result.alias_path
 | 
					    assert_equal alias_path.to_s, result.alias_path
 | 
				
			||||||
  ensure
 | 
					  ensure
 | 
				
			||||||
    alias_dir.rmtree
 | 
					    alias_dir.rmtree
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user