Add --os=all and --arch=all options.
				
					
				
			This commit is contained in:
		
							parent
							
								
									f7b3225574
								
							
						
					
					
						commit
						486c3765ce
					
				@ -33,13 +33,15 @@ module Homebrew
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def freeze_named_args!(named_args, cask_options:)
 | 
			
		||||
        options = {}
 | 
			
		||||
        options[:force_bottle] = true if self[:force_bottle?]
 | 
			
		||||
        options[:override_spec] = :head if self[:HEAD?]
 | 
			
		||||
        options[:flags] = flags_only unless flags_only.empty?
 | 
			
		||||
        self[:named] = NamedArgs.new(
 | 
			
		||||
          *named_args.freeze,
 | 
			
		||||
          override_spec: spec(nil),
 | 
			
		||||
          force_bottle:  self[:force_bottle?],
 | 
			
		||||
          flags:         flags_only,
 | 
			
		||||
          cask_options:  cask_options,
 | 
			
		||||
          parent:        self,
 | 
			
		||||
          parent:       self,
 | 
			
		||||
          cask_options: cask_options,
 | 
			
		||||
          **options,
 | 
			
		||||
        )
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -98,6 +100,44 @@ module Homebrew
 | 
			
		||||
        return :cask if cask? && !formula?
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T::Array[[Symbol, Symbol]]) }
 | 
			
		||||
      def os_arch_combinations
 | 
			
		||||
        skip_invalid_combinations = false
 | 
			
		||||
 | 
			
		||||
        oses = case (os_sym = os&.to_sym)
 | 
			
		||||
        when nil
 | 
			
		||||
          [SimulateSystem.current_os]
 | 
			
		||||
        when :all
 | 
			
		||||
          skip_invalid_combinations = true
 | 
			
		||||
 | 
			
		||||
          [
 | 
			
		||||
            *MacOSVersions::SYMBOLS.keys,
 | 
			
		||||
            :linux,
 | 
			
		||||
          ]
 | 
			
		||||
        else
 | 
			
		||||
          [os_sym]
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        arches = case (arch_sym = arch&.to_sym)
 | 
			
		||||
        when nil
 | 
			
		||||
          [SimulateSystem.current_arch]
 | 
			
		||||
        when :all
 | 
			
		||||
          skip_invalid_combinations = true
 | 
			
		||||
          OnSystem::ARCH_OPTIONS
 | 
			
		||||
        else
 | 
			
		||||
          [arch_sym]
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        oses.product(arches).select do |os, arch|
 | 
			
		||||
          if skip_invalid_combinations
 | 
			
		||||
            bottle_tag = Utils::Bottles::Tag.new(system: os, arch: arch)
 | 
			
		||||
            bottle_tag.valid_combination?
 | 
			
		||||
          else
 | 
			
		||||
            true
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      def option_to_name(option)
 | 
			
		||||
@ -124,14 +164,6 @@ module Homebrew
 | 
			
		||||
        @cli_args.freeze
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def spec(default = :stable)
 | 
			
		||||
        if self[:HEAD?]
 | 
			
		||||
          :head
 | 
			
		||||
        else
 | 
			
		||||
          default
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def respond_to_missing?(method_name, *)
 | 
			
		||||
        @table.key?(method_name)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -240,6 +240,9 @@ module Homebrew
 | 
			
		||||
      sig { returns(T.nilable(T::Array[String])) }
 | 
			
		||||
      def only; end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T.nilable(String)) }
 | 
			
		||||
      def os; end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T.nilable(T::Array[String])) }
 | 
			
		||||
      def except; end
 | 
			
		||||
 | 
			
		||||
@ -270,6 +273,9 @@ module Homebrew
 | 
			
		||||
      sig { returns(T::Boolean) }
 | 
			
		||||
      def s?; end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T.nilable(String)) }
 | 
			
		||||
      def arch; end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T.nilable(String)) }
 | 
			
		||||
      def appdir; end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,24 @@ module Homebrew
 | 
			
		||||
    #
 | 
			
		||||
    # @api private
 | 
			
		||||
    class NamedArgs < Array
 | 
			
		||||
      def initialize(*args, parent: Args.new, override_spec: nil, force_bottle: false, flags: [], cask_options: false)
 | 
			
		||||
      sig {
 | 
			
		||||
        params(
 | 
			
		||||
          args:          String,
 | 
			
		||||
          parent:        Args,
 | 
			
		||||
          override_spec: Symbol,
 | 
			
		||||
          force_bottle:  T::Boolean,
 | 
			
		||||
          flags:         T::Array[String],
 | 
			
		||||
          cask_options:  T::Boolean,
 | 
			
		||||
        ).void
 | 
			
		||||
      }
 | 
			
		||||
      def initialize(
 | 
			
		||||
        *args,
 | 
			
		||||
        parent: Args.new,
 | 
			
		||||
        override_spec: T.unsafe(nil),
 | 
			
		||||
        force_bottle: T.unsafe(nil),
 | 
			
		||||
        flags: T.unsafe(nil),
 | 
			
		||||
        cask_options: false
 | 
			
		||||
      )
 | 
			
		||||
        require "cask/cask"
 | 
			
		||||
        require "cask/cask_loader"
 | 
			
		||||
        require "formulary"
 | 
			
		||||
@ -50,11 +67,17 @@ module Homebrew
 | 
			
		||||
          warn:               T::Boolean,
 | 
			
		||||
        ).returns(T::Array[T.any(Formula, Keg, Cask::Cask)])
 | 
			
		||||
      }
 | 
			
		||||
      def to_formulae_and_casks(only: parent&.only_formula_or_cask, ignore_unavailable: nil, method: nil, uniq: true,
 | 
			
		||||
                                warn: true)
 | 
			
		||||
      def to_formulae_and_casks(
 | 
			
		||||
        only: parent&.only_formula_or_cask,
 | 
			
		||||
        ignore_unavailable: nil,
 | 
			
		||||
        method: T.unsafe(nil),
 | 
			
		||||
        uniq: true,
 | 
			
		||||
        warn: T.unsafe(nil)
 | 
			
		||||
      )
 | 
			
		||||
        @to_formulae_and_casks ||= {}
 | 
			
		||||
        @to_formulae_and_casks[only] ||= downcased_unique_named.flat_map do |name|
 | 
			
		||||
          load_formula_or_cask(name, only: only, method: method, warn: warn)
 | 
			
		||||
          options = { warn: warn }.compact
 | 
			
		||||
          load_formula_or_cask(name, only: only, method: method, **options)
 | 
			
		||||
        rescue FormulaUnreadableError, FormulaClassUnavailableError,
 | 
			
		||||
               TapFormulaUnreadableError, TapFormulaClassUnavailableError,
 | 
			
		||||
               Cask::CaskUnreadableError
 | 
			
		||||
@ -88,14 +111,15 @@ module Homebrew
 | 
			
		||||
        end.uniq.freeze
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def load_formula_or_cask(name, only: nil, method: nil, warn: true)
 | 
			
		||||
      def load_formula_or_cask(name, only: nil, method: nil, warn: nil)
 | 
			
		||||
        unreadable_error = nil
 | 
			
		||||
 | 
			
		||||
        if only != :cask
 | 
			
		||||
          begin
 | 
			
		||||
            formula = case method
 | 
			
		||||
            when nil, :factory
 | 
			
		||||
              Formulary.factory(name, *spec, force_bottle: @force_bottle, flags: @flags, warn: warn)
 | 
			
		||||
              options = { warn: warn, force_bottle: @force_bottle, flags: @flags }.compact
 | 
			
		||||
              Formulary.factory(name, *@override_spec, **options)
 | 
			
		||||
            when :resolve
 | 
			
		||||
              resolve_formula(name)
 | 
			
		||||
            when :latest_kegs
 | 
			
		||||
@ -126,7 +150,8 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
          begin
 | 
			
		||||
            config = Cask::Config.from_args(@parent) if @cask_options
 | 
			
		||||
            cask = Cask::CaskLoader.load(name, config: config, warn: warn)
 | 
			
		||||
            options = { warn: warn }.compact
 | 
			
		||||
            cask = Cask::CaskLoader.load(name, config: config, **options)
 | 
			
		||||
 | 
			
		||||
            if unreadable_error.present?
 | 
			
		||||
              onoe <<~EOS
 | 
			
		||||
@ -177,7 +202,7 @@ module Homebrew
 | 
			
		||||
      private :load_formula_or_cask
 | 
			
		||||
 | 
			
		||||
      def resolve_formula(name)
 | 
			
		||||
        Formulary.resolve(name, spec: spec, force_bottle: @force_bottle, flags: @flags)
 | 
			
		||||
        Formulary.resolve(name, **{ spec: @override_spec, force_bottle: @force_bottle, flags: @flags }.compact)
 | 
			
		||||
      end
 | 
			
		||||
      private :resolve_formula
 | 
			
		||||
 | 
			
		||||
@ -306,11 +331,6 @@ module Homebrew
 | 
			
		||||
        end.uniq
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def spec
 | 
			
		||||
        @override_spec
 | 
			
		||||
      end
 | 
			
		||||
      private :spec
 | 
			
		||||
 | 
			
		||||
      def resolve_kegs(name)
 | 
			
		||||
        raise UsageError if name.blank?
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,12 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
        If <formula> is provided, display the file or directory used to cache <formula>.
 | 
			
		||||
      EOS
 | 
			
		||||
      flag   "--os=",
 | 
			
		||||
             description: "Show cache file for the given operating system." \
 | 
			
		||||
                          "(Pass `all` to show cache files for all operating systems.)"
 | 
			
		||||
      flag   "--arch=",
 | 
			
		||||
             description: "Show cache file for the given CPU architecture." \
 | 
			
		||||
                          "(Pass `all` to show cache files for all architectures.)"
 | 
			
		||||
      switch "-s", "--build-from-source",
 | 
			
		||||
             description: "Show the cache file used when building from source."
 | 
			
		||||
      switch "--force-bottle",
 | 
			
		||||
@ -31,6 +37,8 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      conflicts "--build-from-source", "--force-bottle", "--bottle-tag", "--HEAD", "--cask"
 | 
			
		||||
      conflicts "--formula", "--cask"
 | 
			
		||||
      conflicts "--os", "--bottle-tag"
 | 
			
		||||
      conflicts "--arch", "--bottle-tag"
 | 
			
		||||
 | 
			
		||||
      named_args [:formula, :cask]
 | 
			
		||||
    end
 | 
			
		||||
@ -46,21 +54,62 @@ module Homebrew
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    formulae_or_casks = args.named.to_formulae_and_casks
 | 
			
		||||
    os_arch_combinations = args.os_arch_combinations
 | 
			
		||||
 | 
			
		||||
    formulae_or_casks.each do |formula_or_cask|
 | 
			
		||||
      if formula_or_cask.is_a? Formula
 | 
			
		||||
        print_formula_cache formula_or_cask, args: args
 | 
			
		||||
      case formula_or_cask
 | 
			
		||||
      when Formula
 | 
			
		||||
        formula = T.cast(formula_or_cask, Formula)
 | 
			
		||||
        ref = formula.loaded_from_api? ? formula.full_name : formula.path
 | 
			
		||||
 | 
			
		||||
        os_arch_combinations.each do |os, arch|
 | 
			
		||||
          SimulateSystem.with os: os, arch: arch do
 | 
			
		||||
            Formulary.clear_cache
 | 
			
		||||
            formula = Formulary.factory(ref)
 | 
			
		||||
            print_formula_cache(formula, os: os, arch: arch, args: args)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      else
 | 
			
		||||
        print_cask_cache formula_or_cask
 | 
			
		||||
        cask = formula_or_cask
 | 
			
		||||
        ref = cask.loaded_from_api? ? cask.full_token : cask.sourcefile_path
 | 
			
		||||
 | 
			
		||||
        os_arch_combinations.each do |os, arch|
 | 
			
		||||
          next if os == :linux
 | 
			
		||||
 | 
			
		||||
          SimulateSystem.with os: os, arch: arch do
 | 
			
		||||
            cask = Cask::CaskLoader.load(ref)
 | 
			
		||||
            print_cask_cache(cask)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { params(formula: Formula, args: CLI::Args).void }
 | 
			
		||||
  def self.print_formula_cache(formula, args:)
 | 
			
		||||
    if fetch_bottle?(formula, force_bottle: args.force_bottle?, bottle_tag: args.bottle_tag&.to_sym,
 | 
			
		||||
                     build_from_source_formulae: args.build_from_source_formulae)
 | 
			
		||||
      puts formula.bottle_for_tag(args.bottle_tag&.to_sym)&.cached_download
 | 
			
		||||
  sig { params(formula: Formula, os: Symbol, arch: Symbol, args: CLI::Args).void }
 | 
			
		||||
  def self.print_formula_cache(formula, os:, arch:, args:)
 | 
			
		||||
    if fetch_bottle?(
 | 
			
		||||
      formula,
 | 
			
		||||
      force_bottle:               args.force_bottle?,
 | 
			
		||||
      bottle_tag:                 args.bottle_tag&.to_sym,
 | 
			
		||||
      build_from_source_formulae: args.build_from_source_formulae,
 | 
			
		||||
      os:                         args.os&.to_sym,
 | 
			
		||||
      arch:                       args.arch&.to_sym,
 | 
			
		||||
    )
 | 
			
		||||
      bottle_tag = if (bottle_tag = args.bottle_tag&.to_sym)
 | 
			
		||||
        # TODO: odeprecate "--bottle-tag"
 | 
			
		||||
        Utils::Bottles::Tag.from_symbol(bottle_tag)
 | 
			
		||||
      else
 | 
			
		||||
        Utils::Bottles::Tag.new(system: os, arch: arch)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      bottle = formula.bottle_for_tag(bottle_tag)
 | 
			
		||||
 | 
			
		||||
      if bottle.nil?
 | 
			
		||||
        opoo "Bottle for tag #{bottle_tag.to_sym.inspect} is unavailable."
 | 
			
		||||
        return
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      puts bottle.cached_download
 | 
			
		||||
    elsif args.HEAD?
 | 
			
		||||
      puts formula.head.cached_download
 | 
			
		||||
    else
 | 
			
		||||
 | 
			
		||||
@ -18,12 +18,14 @@ module Homebrew
 | 
			
		||||
        Download a bottle (if available) or source packages for <formula>e
 | 
			
		||||
        and binaries for <cask>s. For files, also print SHA-256 checksums.
 | 
			
		||||
      EOS
 | 
			
		||||
      # This is needed for downloading ARM casks in CI.
 | 
			
		||||
      flag "--arch=",
 | 
			
		||||
           description: "Download for the given CPU architecture.",
 | 
			
		||||
           hidden:      true
 | 
			
		||||
      flag "--bottle-tag=",
 | 
			
		||||
           description: "Download a bottle for given tag."
 | 
			
		||||
      flag   "--os=",
 | 
			
		||||
             description: "Download for the given operating system." \
 | 
			
		||||
                          "(Pass `all` to download for all operating systems.)"
 | 
			
		||||
      flag   "--arch=",
 | 
			
		||||
             description: "Download for the given CPU architecture." \
 | 
			
		||||
                          "(Pass `all` to download for all architectures.)"
 | 
			
		||||
      flag   "--bottle-tag=",
 | 
			
		||||
             description: "Download a bottle for given tag."
 | 
			
		||||
      switch "--HEAD",
 | 
			
		||||
             description: "Fetch HEAD version instead of stable version."
 | 
			
		||||
      switch "-f", "--force",
 | 
			
		||||
@ -60,6 +62,8 @@ module Homebrew
 | 
			
		||||
      conflicts "--cask", "--force-bottle"
 | 
			
		||||
      conflicts "--cask", "--bottle-tag"
 | 
			
		||||
      conflicts "--formula", "--cask"
 | 
			
		||||
      conflicts "--os", "--bottle-tag"
 | 
			
		||||
      conflicts "--arch", "--bottle-tag"
 | 
			
		||||
 | 
			
		||||
      named_args [:formula, :cask], min: 1
 | 
			
		||||
    end
 | 
			
		||||
@ -68,17 +72,14 @@ module Homebrew
 | 
			
		||||
  def self.fetch
 | 
			
		||||
    args = fetch_args.parse
 | 
			
		||||
 | 
			
		||||
    if (arch = args.arch)
 | 
			
		||||
      SimulateSystem.arch = arch.to_sym
 | 
			
		||||
    end
 | 
			
		||||
    Formulary.enable_factory_cache!
 | 
			
		||||
 | 
			
		||||
    bucket = if args.deps?
 | 
			
		||||
      args.named.to_formulae_and_casks.flat_map do |formula_or_cask|
 | 
			
		||||
        case formula_or_cask
 | 
			
		||||
        when Formula
 | 
			
		||||
          f = formula_or_cask
 | 
			
		||||
 | 
			
		||||
          [f, *f.recursive_dependencies.map(&:to_formula)]
 | 
			
		||||
          formula = formula_or_cask
 | 
			
		||||
          [formula, *formula.recursive_dependencies.map(&:to_formula)]
 | 
			
		||||
        else
 | 
			
		||||
          formula_or_cask
 | 
			
		||||
        end
 | 
			
		||||
@ -87,52 +88,92 @@ module Homebrew
 | 
			
		||||
      args.named.to_formulae_and_casks
 | 
			
		||||
    end.uniq
 | 
			
		||||
 | 
			
		||||
    os_arch_combinations = args.os_arch_combinations
 | 
			
		||||
 | 
			
		||||
    puts "Fetching: #{bucket * ", "}" if bucket.size > 1
 | 
			
		||||
    bucket.each do |formula_or_cask|
 | 
			
		||||
      case formula_or_cask
 | 
			
		||||
      when Formula
 | 
			
		||||
        f = formula_or_cask
 | 
			
		||||
        formula = T.cast(formula_or_cask, Formula)
 | 
			
		||||
        ref = formula.loaded_from_api? ? formula.full_name : formula.path
 | 
			
		||||
 | 
			
		||||
        f.print_tap_action verb: "Fetching"
 | 
			
		||||
        os_arch_combinations.each do |os, arch|
 | 
			
		||||
          SimulateSystem.with os: os, arch: arch do
 | 
			
		||||
            Formulary.clear_cache
 | 
			
		||||
            formula = Formulary.factory(ref)
 | 
			
		||||
 | 
			
		||||
        fetched_bottle = false
 | 
			
		||||
        if fetch_bottle?(f, force_bottle: args.force_bottle?, bottle_tag: args.bottle_tag&.to_sym,
 | 
			
		||||
                         build_from_source_formulae: args.build_from_source_formulae)
 | 
			
		||||
          begin
 | 
			
		||||
            f.clear_cache if args.force?
 | 
			
		||||
            f.fetch_bottle_tab
 | 
			
		||||
            fetch_formula(f.bottle_for_tag(args.bottle_tag&.to_sym), args: args)
 | 
			
		||||
          rescue Interrupt
 | 
			
		||||
            raise
 | 
			
		||||
          rescue => e
 | 
			
		||||
            raise if Homebrew::EnvConfig.developer?
 | 
			
		||||
            formula.print_tap_action verb: "Fetching"
 | 
			
		||||
 | 
			
		||||
            fetched_bottle = false
 | 
			
		||||
            onoe e.message
 | 
			
		||||
            opoo "Bottle fetch failed, fetching the source instead."
 | 
			
		||||
          else
 | 
			
		||||
            fetched_bottle = true
 | 
			
		||||
            if fetch_bottle?(
 | 
			
		||||
              formula,
 | 
			
		||||
              force_bottle:               args.force_bottle?,
 | 
			
		||||
              bottle_tag:                 args.bottle_tag&.to_sym,
 | 
			
		||||
              build_from_source_formulae: args.build_from_source_formulae,
 | 
			
		||||
              os:                         args.os&.to_sym,
 | 
			
		||||
              arch:                       args.arch&.to_sym,
 | 
			
		||||
            )
 | 
			
		||||
              begin
 | 
			
		||||
                formula.clear_cache if args.force?
 | 
			
		||||
 | 
			
		||||
                # TODO: Deprecate `--bottle-tag`.
 | 
			
		||||
                bottle_tag = if (bottle_tag = args.bottle_tag&.to_sym)
 | 
			
		||||
                  Utils::Bottles::Tag.from_symbol(bottle_tag)
 | 
			
		||||
                else
 | 
			
		||||
                  Utils::Bottles::Tag.new(system: os, arch: arch)
 | 
			
		||||
                end
 | 
			
		||||
 | 
			
		||||
                bottle = formula.bottle_for_tag(bottle_tag)
 | 
			
		||||
 | 
			
		||||
                if bottle.nil?
 | 
			
		||||
                  opoo "Bottle for tag #{bottle_tag.to_sym.inspect} is unavailable."
 | 
			
		||||
                  next
 | 
			
		||||
                end
 | 
			
		||||
 | 
			
		||||
                formula.fetch_bottle_tab
 | 
			
		||||
                fetch_formula(bottle, args: args)
 | 
			
		||||
              rescue Interrupt
 | 
			
		||||
                raise
 | 
			
		||||
              rescue => e
 | 
			
		||||
                raise if Homebrew::EnvConfig.developer?
 | 
			
		||||
 | 
			
		||||
                fetched_bottle = false
 | 
			
		||||
                onoe e.message
 | 
			
		||||
                opoo "Bottle fetch failed, fetching the source instead."
 | 
			
		||||
              else
 | 
			
		||||
                fetched_bottle = true
 | 
			
		||||
              end
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            next if fetched_bottle
 | 
			
		||||
 | 
			
		||||
            fetch_formula(formula, args: args)
 | 
			
		||||
 | 
			
		||||
            formula.resources.each do |r|
 | 
			
		||||
              fetch_resource(r, args: args)
 | 
			
		||||
              r.patches.each { |p| fetch_patch(p, args: args) if p.external? }
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            formula.patchlist.each { |p| fetch_patch(p, args: args) if p.external? }
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        next if fetched_bottle
 | 
			
		||||
 | 
			
		||||
        fetch_formula(f, args: args)
 | 
			
		||||
 | 
			
		||||
        f.resources.each do |r|
 | 
			
		||||
          fetch_resource(r, args: args)
 | 
			
		||||
          r.patches.each { |p| fetch_patch(p, args: args) if p.external? }
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        f.patchlist.each { |p| fetch_patch(p, args: args) if p.external? }
 | 
			
		||||
      else
 | 
			
		||||
        cask = formula_or_cask
 | 
			
		||||
        ref = cask.loaded_from_api? ? cask.full_token : cask.sourcefile_path
 | 
			
		||||
 | 
			
		||||
        quarantine = args.quarantine?
 | 
			
		||||
        quarantine = true if quarantine.nil?
 | 
			
		||||
        os_arch_combinations.each do |os, arch|
 | 
			
		||||
          next if os == :linux
 | 
			
		||||
 | 
			
		||||
        download = Cask::Download.new(cask, quarantine: quarantine)
 | 
			
		||||
        fetch_cask(download, args: args)
 | 
			
		||||
          SimulateSystem.with os: os, arch: arch do
 | 
			
		||||
            cask = Cask::CaskLoader.load(ref)
 | 
			
		||||
 | 
			
		||||
            quarantine = args.quarantine?
 | 
			
		||||
            quarantine = true if quarantine.nil?
 | 
			
		||||
 | 
			
		||||
            download = Cask::Download.new(cask, quarantine: quarantine)
 | 
			
		||||
            fetch_cask(download, args: args)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -29,10 +29,10 @@ module Homebrew
 | 
			
		||||
        locally available formulae and casks and skip style checks. Will exit with a
 | 
			
		||||
        non-zero status if any errors are found.
 | 
			
		||||
      EOS
 | 
			
		||||
      # This is needed for auditing ARM casks in CI.
 | 
			
		||||
      flag "--arch=",
 | 
			
		||||
           description: "Audit the given CPU architecture.",
 | 
			
		||||
           hidden:      true
 | 
			
		||||
      flag   "--os=",
 | 
			
		||||
             description: "Audit the given operating system. (Pass `all` to audit all operating systems.)"
 | 
			
		||||
      flag   "--arch=",
 | 
			
		||||
             description: "Audit the given CPU architecture. (Pass `all` to audit all architectures.)"
 | 
			
		||||
      switch "--strict",
 | 
			
		||||
             description: "Run additional, stricter style checks."
 | 
			
		||||
      switch "--git",
 | 
			
		||||
@ -106,9 +106,9 @@ module Homebrew
 | 
			
		||||
  def self.audit
 | 
			
		||||
    args = audit_args.parse
 | 
			
		||||
 | 
			
		||||
    if (arch = args.arch)
 | 
			
		||||
      SimulateSystem.arch = arch.to_sym
 | 
			
		||||
    end
 | 
			
		||||
    Formulary.enable_factory_cache!
 | 
			
		||||
 | 
			
		||||
    os_arch_combinations = args.os_arch_combinations
 | 
			
		||||
 | 
			
		||||
    Homebrew.auditing = true
 | 
			
		||||
    inject_dump_stats!(FormulaAuditor, /^audit_/) if args.audit_debug?
 | 
			
		||||
@ -200,7 +200,12 @@ module Homebrew
 | 
			
		||||
    spdx_license_data = SPDX.license_data
 | 
			
		||||
    spdx_exception_data = SPDX.exception_data
 | 
			
		||||
    new_formula_problem_lines = T.let([], T::Array[String])
 | 
			
		||||
    formula_results = audit_formulae.sort.to_h do |f|
 | 
			
		||||
 | 
			
		||||
    formula_results = {}
 | 
			
		||||
 | 
			
		||||
    audit_formulae.sort.each do |f|
 | 
			
		||||
      path = f.path
 | 
			
		||||
 | 
			
		||||
      only = only_cops ? ["style"] : args.only
 | 
			
		||||
      options = {
 | 
			
		||||
        new_formula:         new_formula,
 | 
			
		||||
@ -214,63 +219,83 @@ module Homebrew
 | 
			
		||||
        style_offenses:      style_offenses&.for_path(f.path),
 | 
			
		||||
      }.compact
 | 
			
		||||
 | 
			
		||||
      audit_proc = proc { FormulaAuditor.new(f, **options).tap(&:audit) }
 | 
			
		||||
      os_arch_combinations.each do |os, arch|
 | 
			
		||||
        SimulateSystem.with os: os, arch: arch do
 | 
			
		||||
          odebug "Auditing Formula #{f} on os #{os} and arch #{arch}"
 | 
			
		||||
 | 
			
		||||
      # Audit requires full Ruby source so disable API.
 | 
			
		||||
      # We shouldn't do this for taps however so that we don't unnecessarily require a full Homebrew/core clone.
 | 
			
		||||
      fa = if f.core_formula?
 | 
			
		||||
        without_api(&audit_proc)
 | 
			
		||||
      else
 | 
			
		||||
        audit_proc.call
 | 
			
		||||
      end
 | 
			
		||||
          Formulary.clear_cache
 | 
			
		||||
          f = Formulary.factory(path)
 | 
			
		||||
 | 
			
		||||
      if fa.problems.any? || fa.new_formula_problems.any?
 | 
			
		||||
        formula_count += 1
 | 
			
		||||
        problem_count += fa.problems.size
 | 
			
		||||
        problem_lines = format_problem_lines(fa.problems)
 | 
			
		||||
        corrected_problem_count += options.fetch(:style_offenses, []).count(&:corrected?)
 | 
			
		||||
        new_formula_problem_lines += format_problem_lines(fa.new_formula_problems)
 | 
			
		||||
        if args.display_filename?
 | 
			
		||||
          puts problem_lines.map { |s| "#{f.path}: #{s}" }
 | 
			
		||||
        else
 | 
			
		||||
          puts "#{f.full_name}:", problem_lines.map { |s| "  #{s}" }
 | 
			
		||||
          audit_proc = proc { FormulaAuditor.new(f, **options).tap(&:audit) }
 | 
			
		||||
 | 
			
		||||
          # Audit requires full Ruby source so disable API.
 | 
			
		||||
          # We shouldn't do this for taps however so that we don't unnecessarily require a full Homebrew/core clone.
 | 
			
		||||
          fa = if f.core_formula?
 | 
			
		||||
            without_api(&audit_proc)
 | 
			
		||||
          else
 | 
			
		||||
            audit_proc.call
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          if fa.problems.any? || fa.new_formula_problems.any?
 | 
			
		||||
            formula_count += 1
 | 
			
		||||
            problem_count += fa.problems.size
 | 
			
		||||
            problem_lines = format_problem_lines(fa.problems)
 | 
			
		||||
            corrected_problem_count += options.fetch(:style_offenses, []).count(&:corrected?)
 | 
			
		||||
            new_formula_problem_lines += format_problem_lines(fa.new_formula_problems)
 | 
			
		||||
            if args.display_filename?
 | 
			
		||||
              puts problem_lines.map { |s| "#{f.path}: #{s}" }
 | 
			
		||||
            else
 | 
			
		||||
              puts "#{f.full_name}:", problem_lines.map { |s| "  #{s}" }
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          formula_results.deep_merge!({ f.path => fa.problems + fa.new_formula_problems })
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      [f.path, fa.problems + fa.new_formula_problems]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    cask_results = if audit_casks.empty?
 | 
			
		||||
      {}
 | 
			
		||||
    else
 | 
			
		||||
    cask_results = {}
 | 
			
		||||
 | 
			
		||||
    if audit_casks.any?
 | 
			
		||||
      require "cask/auditor"
 | 
			
		||||
 | 
			
		||||
      if args.display_failures_only?
 | 
			
		||||
        odeprecated "`brew audit <cask> --display-failures-only`", "`brew audit <cask>` without the argument"
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
      require "cask/auditor"
 | 
			
		||||
    audit_casks.each do |cask|
 | 
			
		||||
      path = cask.sourcefile_path
 | 
			
		||||
 | 
			
		||||
      audit_casks.to_h do |cask|
 | 
			
		||||
        odebug "Auditing Cask #{cask}"
 | 
			
		||||
        errors = Cask::Auditor.audit(
 | 
			
		||||
          cask,
 | 
			
		||||
          # For switches, we add `|| nil` so that `nil` will be passed
 | 
			
		||||
          # instead of `false` if they aren't set.
 | 
			
		||||
          # This way, we can distinguish between "not set" and "set to false".
 | 
			
		||||
          audit_online:          (args.online? || nil),
 | 
			
		||||
          audit_strict:          (args.strict? || nil),
 | 
			
		||||
      os_arch_combinations.each do |os, arch|
 | 
			
		||||
        next if os == :linux
 | 
			
		||||
 | 
			
		||||
          # No need for `|| nil` for `--[no-]signing`
 | 
			
		||||
          # because boolean switches are already `nil` if not passed
 | 
			
		||||
          audit_signing:         args.signing?,
 | 
			
		||||
          audit_new_cask:        (args.new_cask? || nil),
 | 
			
		||||
          audit_token_conflicts: (args.token_conflicts? || nil),
 | 
			
		||||
          quarantine:            true,
 | 
			
		||||
          any_named_args:        !no_named_args,
 | 
			
		||||
          only:                  args.only,
 | 
			
		||||
          except:                args.except,
 | 
			
		||||
        )
 | 
			
		||||
        [cask.sourcefile_path, errors]
 | 
			
		||||
        SimulateSystem.with os: os, arch: arch do
 | 
			
		||||
          odebug "Auditing Cask #{cask} on os #{os} and arch #{arch}"
 | 
			
		||||
 | 
			
		||||
          cask = Cask::CaskLoader.load(path)
 | 
			
		||||
 | 
			
		||||
          errors = Cask::Auditor.audit(
 | 
			
		||||
            cask,
 | 
			
		||||
            # For switches, we add `|| nil` so that `nil` will be passed
 | 
			
		||||
            # instead of `false` if they aren't set.
 | 
			
		||||
            # This way, we can distinguish between "not set" and "set to false".
 | 
			
		||||
            audit_online:          (args.online? || nil),
 | 
			
		||||
            audit_strict:          (args.strict? || nil),
 | 
			
		||||
 | 
			
		||||
            # No need for `|| nil` for `--[no-]signing`
 | 
			
		||||
            # because boolean switches are already `nil` if not passed
 | 
			
		||||
            audit_signing:         args.signing?,
 | 
			
		||||
            audit_new_cask:        (args.new_cask? || nil),
 | 
			
		||||
            audit_token_conflicts: (args.token_conflicts? || nil),
 | 
			
		||||
            quarantine:            true,
 | 
			
		||||
            any_named_args:        !no_named_args,
 | 
			
		||||
            only:                  args.only,
 | 
			
		||||
            except:                args.except,
 | 
			
		||||
          )
 | 
			
		||||
 | 
			
		||||
          cask_results.deep_merge!({ cask.sourcefile_path => errors })
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ require "cli/parser"
 | 
			
		||||
 | 
			
		||||
class String
 | 
			
		||||
  def f(*args)
 | 
			
		||||
    require "formula"
 | 
			
		||||
    Formulary.factory(self, *args)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -343,7 +343,7 @@ module Homebrew
 | 
			
		||||
          nil
 | 
			
		||||
        end
 | 
			
		||||
        if libiconv&.linked_keg&.directory?
 | 
			
		||||
          unless libiconv.keg_only?
 | 
			
		||||
          unless libiconv&.keg_only?
 | 
			
		||||
            <<~EOS
 | 
			
		||||
              A libiconv formula is installed and linked.
 | 
			
		||||
              This will break stuff. For serious. Unlink it.
 | 
			
		||||
 | 
			
		||||
@ -4,13 +4,16 @@
 | 
			
		||||
module Utils
 | 
			
		||||
  module Bottles
 | 
			
		||||
    class << self
 | 
			
		||||
      undef tag
 | 
			
		||||
      module MacOSOverride
 | 
			
		||||
        sig { params(tag: T.nilable(T.any(Symbol, Tag))).returns(Tag) }
 | 
			
		||||
        def tag(tag = nil)
 | 
			
		||||
          return Tag.new(system: MacOS.version.to_sym, arch: Hardware::CPU.arch) if tag.nil?
 | 
			
		||||
 | 
			
		||||
      def tag(symbol = nil)
 | 
			
		||||
        return Utils::Bottles::Tag.from_symbol(symbol) if symbol.present?
 | 
			
		||||
 | 
			
		||||
        Utils::Bottles::Tag.new(system: MacOS.version.to_sym, arch: Hardware::CPU.arch)
 | 
			
		||||
          super
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      prepend MacOSOverride
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    class Collector
 | 
			
		||||
 | 
			
		||||
@ -10,12 +10,16 @@ module Homebrew
 | 
			
		||||
        force_bottle:               T::Boolean,
 | 
			
		||||
        bottle_tag:                 T.nilable(Symbol),
 | 
			
		||||
        build_from_source_formulae: T::Array[String],
 | 
			
		||||
        os:                         T.nilable(Symbol),
 | 
			
		||||
        arch:                       T.nilable(Symbol),
 | 
			
		||||
      ).returns(T::Boolean)
 | 
			
		||||
    }
 | 
			
		||||
    def fetch_bottle?(formula, force_bottle:, bottle_tag:, build_from_source_formulae:)
 | 
			
		||||
    def fetch_bottle?(formula, force_bottle:, bottle_tag:, build_from_source_formulae:, os:, arch:)
 | 
			
		||||
      bottle = formula.bottle
 | 
			
		||||
 | 
			
		||||
      return true if force_bottle && bottle.present?
 | 
			
		||||
      return true if os.present?
 | 
			
		||||
      return true if arch.present?
 | 
			
		||||
      return true if bottle_tag.present? && formula.bottled?(bottle_tag)
 | 
			
		||||
 | 
			
		||||
      bottle.present? &&
 | 
			
		||||
 | 
			
		||||
@ -385,7 +385,7 @@ class Formula
 | 
			
		||||
 | 
			
		||||
  # The Bottle object for given tag.
 | 
			
		||||
  # @private
 | 
			
		||||
  sig { params(tag: T.nilable(Symbol)).returns(T.nilable(Bottle)) }
 | 
			
		||||
  sig { params(tag: T.nilable(Utils::Bottles::Tag)).returns(T.nilable(Bottle)) }
 | 
			
		||||
  def bottle_for_tag(tag = nil)
 | 
			
		||||
    Bottle.new(self, bottle_specification, tag) if bottled?(tag)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -165,7 +165,7 @@ class FormulaInstaller
 | 
			
		||||
 | 
			
		||||
    return true if formula.local_bottle_path.present?
 | 
			
		||||
 | 
			
		||||
    bottle = formula.bottle_for_tag(Utils::Bottles.tag.to_sym)
 | 
			
		||||
    bottle = formula.bottle_for_tag(Utils::Bottles.tag)
 | 
			
		||||
    return false if bottle.nil?
 | 
			
		||||
 | 
			
		||||
    unless bottle.compatible_locations?
 | 
			
		||||
 | 
			
		||||
@ -38,11 +38,17 @@ class FormulaVersions
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { params(rev: String).returns(String) }
 | 
			
		||||
  def file_contents_at_revision(rev)
 | 
			
		||||
    repository.cd { Utils.popen_read("git", "cat-file", "blob", "#{rev}:#{entry_name}") }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def formula_at_revision(rev)
 | 
			
		||||
  sig {
 | 
			
		||||
    type_parameters(:U)
 | 
			
		||||
      .params(rev: String, _block: T.proc.params(arg0: Formula).returns(T.type_parameter(:U)))
 | 
			
		||||
      .returns(T.nilable(T.type_parameter(:U)))
 | 
			
		||||
  }
 | 
			
		||||
  def formula_at_revision(rev, &_block)
 | 
			
		||||
    Homebrew.raise_deprecation_exceptions = true
 | 
			
		||||
 | 
			
		||||
    yield @formula_at_revision[rev] ||= begin
 | 
			
		||||
 | 
			
		||||
@ -51,7 +51,12 @@ module Formulary
 | 
			
		||||
      next if type == :formulary_factory
 | 
			
		||||
 | 
			
		||||
      cached_objects.each_value do |klass|
 | 
			
		||||
        namespace = Utils.deconstantize(klass.name)
 | 
			
		||||
        class_name = klass.name
 | 
			
		||||
 | 
			
		||||
        # Already removed from namespace.
 | 
			
		||||
        next if class_name.nil?
 | 
			
		||||
 | 
			
		||||
        namespace = Utils.deconstantize(class_name)
 | 
			
		||||
        next if Utils.deconstantize(namespace) != name
 | 
			
		||||
 | 
			
		||||
        remove_const(Utils.demodulize(namespace).to_sym)
 | 
			
		||||
@ -119,6 +124,10 @@ module Formulary
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig {
 | 
			
		||||
    params(name: String, path: Pathname, flags: T::Array[String], ignore_errors: T::Boolean)
 | 
			
		||||
      .returns(T.class_of(Formula))
 | 
			
		||||
  }
 | 
			
		||||
  def self.load_formula_from_path(name, path, flags:, ignore_errors:)
 | 
			
		||||
    contents = path.open("r") { |f| ensure_utf8_encoding(f).read }
 | 
			
		||||
    namespace = "FormulaNamespace#{Digest::MD5.hexdigest(path.to_s)}"
 | 
			
		||||
@ -127,6 +136,7 @@ module Formulary
 | 
			
		||||
    cache[:path][path] = klass
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { params(name: String, flags: T::Array[String]).returns(T.class_of(Formula)) }
 | 
			
		||||
  def self.load_formula_from_api(name, flags:)
 | 
			
		||||
    namespace = :"FormulaNamespaceAPI#{Digest::MD5.hexdigest(name)}"
 | 
			
		||||
 | 
			
		||||
@ -313,15 +323,27 @@ module Formulary
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    klass = T.cast(klass, T.class_of(Formula))
 | 
			
		||||
    mod.const_set(class_name, klass)
 | 
			
		||||
 | 
			
		||||
    cache[:api] ||= {}
 | 
			
		||||
    cache[:api][name] = klass
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def self.resolve(name, spec: nil, force_bottle: false, flags: [])
 | 
			
		||||
  sig { params(name: String, spec: Symbol, force_bottle: T::Boolean, flags: T::Array[String]).returns(Formula) }
 | 
			
		||||
  def self.resolve(
 | 
			
		||||
    name,
 | 
			
		||||
    spec: T.unsafe(nil),
 | 
			
		||||
    force_bottle: T.unsafe(nil),
 | 
			
		||||
    flags: T.unsafe(nil)
 | 
			
		||||
  )
 | 
			
		||||
    options = {
 | 
			
		||||
      force_bottle: force_bottle,
 | 
			
		||||
      flags:        flags,
 | 
			
		||||
    }.compact
 | 
			
		||||
 | 
			
		||||
    if name.include?("/") || File.exist?(name)
 | 
			
		||||
      f = factory(name, *spec, force_bottle: force_bottle, flags: flags)
 | 
			
		||||
      f = factory(name, *spec, **options)
 | 
			
		||||
      if f.any_version_installed?
 | 
			
		||||
        tab = Tab.for_formula(f)
 | 
			
		||||
        resolved_spec = spec || tab.spec
 | 
			
		||||
@ -334,8 +356,10 @@ module Formulary
 | 
			
		||||
      end
 | 
			
		||||
    else
 | 
			
		||||
      rack = to_rack(name)
 | 
			
		||||
      alias_path = factory(name, force_bottle: force_bottle, flags: flags).alias_path
 | 
			
		||||
      f = from_rack(rack, *spec, alias_path: alias_path, force_bottle: force_bottle, flags: flags)
 | 
			
		||||
      if (alias_path = factory(name, **options).alias_path)
 | 
			
		||||
        options[:alias_path] = alias_path
 | 
			
		||||
      end
 | 
			
		||||
      f = from_rack(rack, *spec, **options)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # If this formula was installed with an alias that has since changed,
 | 
			
		||||
@ -524,12 +548,12 @@ module Formulary
 | 
			
		||||
 | 
			
		||||
  # Loads tapped formulae.
 | 
			
		||||
  class TapLoader < FormulaLoader
 | 
			
		||||
    def initialize(tapped_name, from: nil, warn: true)
 | 
			
		||||
    def initialize(tapped_name, from:, warn:)
 | 
			
		||||
      name, path, tap = formula_name_path(tapped_name, warn: warn)
 | 
			
		||||
      super name, path, tap: tap
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def formula_name_path(tapped_name, warn: true)
 | 
			
		||||
    def formula_name_path(tapped_name, warn:)
 | 
			
		||||
      user, repo, name = tapped_name.split("/", 3).map(&:downcase)
 | 
			
		||||
      tap = Tap.fetch user, repo
 | 
			
		||||
      path = find_formula_from_name(name, tap)
 | 
			
		||||
@ -648,25 +672,46 @@ module Formulary
 | 
			
		||||
  # * a formula pathname
 | 
			
		||||
  # * a formula URL
 | 
			
		||||
  # * a local bottle reference
 | 
			
		||||
  sig {
 | 
			
		||||
    params(
 | 
			
		||||
      ref:           T.nilable(T.any(Pathname, String)),
 | 
			
		||||
      spec:          Symbol,
 | 
			
		||||
      alias_path:    Pathname,
 | 
			
		||||
      from:          Symbol,
 | 
			
		||||
      warn:          T::Boolean,
 | 
			
		||||
      force_bottle:  T::Boolean,
 | 
			
		||||
      flags:         T::Array[String],
 | 
			
		||||
      ignore_errors: T::Boolean,
 | 
			
		||||
    ).returns(Formula)
 | 
			
		||||
  }
 | 
			
		||||
  def self.factory(
 | 
			
		||||
    ref, spec = :stable, alias_path: nil, from: nil, warn: true,
 | 
			
		||||
    force_bottle: false, flags: [], ignore_errors: false
 | 
			
		||||
    ref,
 | 
			
		||||
    spec = :stable,
 | 
			
		||||
    alias_path: T.unsafe(nil),
 | 
			
		||||
    from: T.unsafe(nil),
 | 
			
		||||
    warn: T.unsafe(nil),
 | 
			
		||||
    force_bottle: T.unsafe(nil),
 | 
			
		||||
    flags: T.unsafe(nil),
 | 
			
		||||
    ignore_errors: T.unsafe(nil)
 | 
			
		||||
  )
 | 
			
		||||
    raise ArgumentError, "Formulae must have a ref!" unless ref
 | 
			
		||||
 | 
			
		||||
    cache_key = "#{ref}-#{spec}-#{alias_path}-#{from}"
 | 
			
		||||
    if factory_cached? && cache[:formulary_factory] &&
 | 
			
		||||
       cache[:formulary_factory][cache_key]
 | 
			
		||||
      return cache[:formulary_factory][cache_key]
 | 
			
		||||
    end
 | 
			
		||||
    return cache[:formulary_factory][cache_key] if factory_cached? && cache[:formulary_factory]&.key?(cache_key)
 | 
			
		||||
 | 
			
		||||
    loader_options = { from: from, warn: warn }.compact
 | 
			
		||||
    formula_options = { alias_path:    alias_path,
 | 
			
		||||
                        force_bottle:  force_bottle,
 | 
			
		||||
                        flags:         flags,
 | 
			
		||||
                        ignore_errors: ignore_errors }.compact
 | 
			
		||||
    formula = loader_for(ref, **loader_options)
 | 
			
		||||
              .get_formula(spec, **formula_options)
 | 
			
		||||
 | 
			
		||||
    formula = loader_for(ref, from: from, warn: warn).get_formula(spec, alias_path: alias_path,
 | 
			
		||||
                                                      force_bottle: force_bottle, flags: flags,
 | 
			
		||||
                                                      ignore_errors: ignore_errors)
 | 
			
		||||
    if factory_cached?
 | 
			
		||||
      cache[:formulary_factory] ||= {}
 | 
			
		||||
      cache[:formulary_factory][cache_key] ||= formula
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    formula
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -676,15 +721,35 @@ module Formulary
 | 
			
		||||
  # @param :alias_path 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, force_bottle: false, flags: [])
 | 
			
		||||
  sig {
 | 
			
		||||
    params(
 | 
			
		||||
      rack:         Pathname,
 | 
			
		||||
      # Automatically resolves the formula's spec if not specified.
 | 
			
		||||
      spec:         Symbol,
 | 
			
		||||
      alias_path:   Pathname,
 | 
			
		||||
      force_bottle: T::Boolean,
 | 
			
		||||
      flags:        T::Array[String],
 | 
			
		||||
    ).returns(Formula)
 | 
			
		||||
  }
 | 
			
		||||
  def self.from_rack(
 | 
			
		||||
    rack, spec = T.unsafe(nil),
 | 
			
		||||
    alias_path: T.unsafe(nil),
 | 
			
		||||
    force_bottle: T.unsafe(nil),
 | 
			
		||||
    flags: T.unsafe(nil)
 | 
			
		||||
  )
 | 
			
		||||
    kegs = rack.directory? ? rack.subdirs.map { |d| Keg.new(d) } : []
 | 
			
		||||
    keg = kegs.find(&:linked?) || kegs.find(&:optlinked?) || kegs.max_by(&:version)
 | 
			
		||||
 | 
			
		||||
    options = {
 | 
			
		||||
      alias_path:   alias_path,
 | 
			
		||||
      force_bottle: force_bottle,
 | 
			
		||||
      flags:        flags,
 | 
			
		||||
    }.compact
 | 
			
		||||
 | 
			
		||||
    if keg
 | 
			
		||||
      from_keg(keg, spec, alias_path: alias_path, force_bottle: force_bottle, flags: flags)
 | 
			
		||||
      from_keg(keg, *spec, **options)
 | 
			
		||||
    else
 | 
			
		||||
      factory(rack.basename.to_s, spec || :stable, alias_path: alias_path, from: :rack, warn: false,
 | 
			
		||||
              force_bottle: force_bottle, flags: flags)
 | 
			
		||||
      factory(rack.basename.to_s, *spec, from: :rack, warn: false, **options)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -696,24 +761,45 @@ module Formulary
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Return a {Formula} instance for the given keg.
 | 
			
		||||
  #
 | 
			
		||||
  # @param spec when nil, will auto resolve the formula's spec.
 | 
			
		||||
  def self.from_keg(keg, spec = nil, alias_path: nil, force_bottle: false, flags: [])
 | 
			
		||||
  sig {
 | 
			
		||||
    params(
 | 
			
		||||
      keg:          Keg,
 | 
			
		||||
      # Automatically resolves the formula's spec if not specified.
 | 
			
		||||
      spec:         Symbol,
 | 
			
		||||
      alias_path:   Pathname,
 | 
			
		||||
      force_bottle: T::Boolean,
 | 
			
		||||
      flags:        T::Array[String],
 | 
			
		||||
    ).returns(Formula)
 | 
			
		||||
  }
 | 
			
		||||
  def self.from_keg(
 | 
			
		||||
    keg,
 | 
			
		||||
    spec = T.unsafe(nil),
 | 
			
		||||
    alias_path: T.unsafe(nil),
 | 
			
		||||
    force_bottle: T.unsafe(nil),
 | 
			
		||||
    flags: T.unsafe(nil)
 | 
			
		||||
  )
 | 
			
		||||
    tab = Tab.for_keg(keg)
 | 
			
		||||
    tap = tab.tap
 | 
			
		||||
    spec ||= tab.spec
 | 
			
		||||
 | 
			
		||||
    formula_name = keg.rack.basename.to_s
 | 
			
		||||
 | 
			
		||||
    options = {
 | 
			
		||||
      alias_path:   alias_path,
 | 
			
		||||
      from:         :keg,
 | 
			
		||||
      warn:         false,
 | 
			
		||||
      force_bottle: force_bottle,
 | 
			
		||||
      flags:        flags,
 | 
			
		||||
    }.compact
 | 
			
		||||
 | 
			
		||||
    f = if tap.nil?
 | 
			
		||||
      factory(keg.rack.basename.to_s, spec, alias_path: alias_path, from: :keg, warn: false,
 | 
			
		||||
              force_bottle: force_bottle, flags: flags)
 | 
			
		||||
      factory(formula_name, spec, **options)
 | 
			
		||||
    else
 | 
			
		||||
      begin
 | 
			
		||||
        factory("#{tap}/#{keg.rack.basename}", spec, alias_path: alias_path, from: :keg, warn: false,
 | 
			
		||||
                force_bottle: force_bottle, flags: flags)
 | 
			
		||||
        factory("#{tap}/#{formula_name}", spec, **options)
 | 
			
		||||
      rescue FormulaUnavailableError
 | 
			
		||||
        # formula may be migrated to different tap. Try to search in core and all taps.
 | 
			
		||||
        factory(keg.rack.basename.to_s, spec, alias_path: alias_path, from: :keg, warn: false,
 | 
			
		||||
                force_bottle: force_bottle, flags: flags)
 | 
			
		||||
        factory(formula_name, spec, **options)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
    f.build = tab
 | 
			
		||||
@ -723,13 +809,35 @@ module Formulary
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Return a {Formula} instance directly from contents.
 | 
			
		||||
  sig {
 | 
			
		||||
    params(
 | 
			
		||||
      name:          String,
 | 
			
		||||
      path:          Pathname,
 | 
			
		||||
      contents:      String,
 | 
			
		||||
      spec:          Symbol,
 | 
			
		||||
      alias_path:    Pathname,
 | 
			
		||||
      force_bottle:  T::Boolean,
 | 
			
		||||
      flags:         T::Array[String],
 | 
			
		||||
      ignore_errors: T::Boolean,
 | 
			
		||||
    ).returns(Formula)
 | 
			
		||||
  }
 | 
			
		||||
  def self.from_contents(
 | 
			
		||||
    name, path, contents, spec = :stable, alias_path: nil,
 | 
			
		||||
    force_bottle: false, flags: [], ignore_errors: false
 | 
			
		||||
    name,
 | 
			
		||||
    path,
 | 
			
		||||
    contents,
 | 
			
		||||
    spec = :stable,
 | 
			
		||||
    alias_path: T.unsafe(nil),
 | 
			
		||||
    force_bottle: T.unsafe(nil),
 | 
			
		||||
    flags: T.unsafe(nil),
 | 
			
		||||
    ignore_errors: T.unsafe(nil)
 | 
			
		||||
  )
 | 
			
		||||
    FormulaContentsLoader.new(name, path, contents)
 | 
			
		||||
                         .get_formula(spec, alias_path: alias_path, force_bottle: force_bottle,
 | 
			
		||||
                                      flags: flags, ignore_errors: ignore_errors)
 | 
			
		||||
    options = {
 | 
			
		||||
      alias_path:    alias_path,
 | 
			
		||||
      force_bottle:  force_bottle,
 | 
			
		||||
      flags:         flags,
 | 
			
		||||
      ignore_errors: ignore_errors,
 | 
			
		||||
    }.compact
 | 
			
		||||
    FormulaContentsLoader.new(name, path, contents).get_formula(spec, **options)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def self.to_rack(ref)
 | 
			
		||||
 | 
			
		||||
@ -71,16 +71,37 @@ class Attr < Parlour::Plugin
 | 
			
		||||
      tree << element
 | 
			
		||||
    elsif node.type == :send && children.shift.nil?
 | 
			
		||||
      method_name = children.shift
 | 
			
		||||
      if [:attr_rw, :attr_predicate].include?(method_name)
 | 
			
		||||
 | 
			
		||||
      case method_name
 | 
			
		||||
      when :attr_rw, :attr_predicate
 | 
			
		||||
        children.each do |name_node|
 | 
			
		||||
          tree << [method_name, name_node.children.first.to_s]
 | 
			
		||||
        end
 | 
			
		||||
      when :delegate
 | 
			
		||||
        children.each do |name_node|
 | 
			
		||||
          name_node.children.each do |pair|
 | 
			
		||||
            delegated_method = pair.children.first
 | 
			
		||||
            delegated_methods = if delegated_method.type == :array
 | 
			
		||||
              delegated_method.children
 | 
			
		||||
            else
 | 
			
		||||
              [delegated_method]
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            delegated_methods.each do |delegated_method_sym|
 | 
			
		||||
              tree << [method_name, delegated_method_sym.children.first.to_s]
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    tree
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  ARRAY_METHODS = T.let(["to_a", "to_ary"].freeze, T::Array[String])
 | 
			
		||||
  HASH_METHODS = T.let(["to_h", "to_hash"].freeze, T::Array[String])
 | 
			
		||||
  STRING_METHODS = T.let(["to_s", "to_str", "to_json"].freeze, T::Array[String])
 | 
			
		||||
 | 
			
		||||
  sig { params(tree: T::Array[T.untyped], namespace: Parlour::RbiGenerator::Namespace, sclass: T::Boolean).void }
 | 
			
		||||
  def process_custom_attr(tree, namespace, sclass: false)
 | 
			
		||||
    tree.each do |node|
 | 
			
		||||
@ -107,6 +128,32 @@ class Attr < Parlour::Plugin
 | 
			
		||||
        name = node.shift
 | 
			
		||||
        name = "self.#{name}" if sclass
 | 
			
		||||
        namespace.create_method(name, return_type: "T::Boolean")
 | 
			
		||||
      when :delegate
 | 
			
		||||
        name = node.shift
 | 
			
		||||
 | 
			
		||||
        return_type = if name.end_with?("?")
 | 
			
		||||
          "T::Boolean"
 | 
			
		||||
        elsif ARRAY_METHODS.include?(name)
 | 
			
		||||
          "Array"
 | 
			
		||||
        elsif HASH_METHODS.include?(name)
 | 
			
		||||
          "Hash"
 | 
			
		||||
        elsif STRING_METHODS.include?(name)
 | 
			
		||||
          "String"
 | 
			
		||||
        else
 | 
			
		||||
          "T.untyped"
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        name = "self.#{name}" if sclass
 | 
			
		||||
 | 
			
		||||
        namespace.create_method(
 | 
			
		||||
          name,
 | 
			
		||||
          parameters:  [
 | 
			
		||||
            Parlour::RbiGenerator::Parameter.new("*args"),
 | 
			
		||||
            Parlour::RbiGenerator::Parameter.new("**options"),
 | 
			
		||||
            Parlour::RbiGenerator::Parameter.new("&block"),
 | 
			
		||||
          ],
 | 
			
		||||
          return_type: return_type,
 | 
			
		||||
        )
 | 
			
		||||
      else
 | 
			
		||||
        raise "Malformed tree."
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -4,17 +4,17 @@ require "cli/named_args"
 | 
			
		||||
 | 
			
		||||
def setup_unredable_formula(name)
 | 
			
		||||
  error = FormulaUnreadableError.new(name, RuntimeError.new("testing"))
 | 
			
		||||
  allow(Formulary).to receive(:factory).with(name, force_bottle: false, flags: [], warn: true).and_raise(error)
 | 
			
		||||
  allow(Formulary).to receive(:factory).with(name, {}).and_raise(error)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
def setup_unredable_cask(name)
 | 
			
		||||
  error = Cask::CaskUnreadableError.new(name, "testing")
 | 
			
		||||
  allow(Cask::CaskLoader).to receive(:load).with(name).and_raise(error)
 | 
			
		||||
  allow(Cask::CaskLoader).to receive(:load).with(name, config: nil, warn: true).and_raise(error)
 | 
			
		||||
  allow(Cask::CaskLoader).to receive(:load).with(name, config: nil).and_raise(error)
 | 
			
		||||
 | 
			
		||||
  config = instance_double(Cask::Config)
 | 
			
		||||
  allow(Cask::Config).to receive(:from_args).and_return(config)
 | 
			
		||||
  allow(Cask::CaskLoader).to receive(:load).with(name, config: config, warn: true).and_raise(error)
 | 
			
		||||
  allow(Cask::CaskLoader).to receive(:load).with(name, config: config).and_raise(error)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe Homebrew::CLI::NamedArgs do
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@ module Test
 | 
			
		||||
 | 
			
		||||
        loader = double(get_formula: formula)
 | 
			
		||||
        allow(Formulary).to receive(:loader_for).with(ref, from: :keg, warn: false).and_return(loader)
 | 
			
		||||
        allow(Formulary).to receive(:loader_for).with(ref, from: nil, warn: true).and_return(loader)
 | 
			
		||||
        allow(Formulary).to receive(:loader_for).with(ref, {}).and_return(loader)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -10,11 +10,19 @@ module Utils
 | 
			
		||||
  module Bottles
 | 
			
		||||
    class << self
 | 
			
		||||
      # Gets the tag for the running OS.
 | 
			
		||||
      def tag(symbol = nil)
 | 
			
		||||
        return Tag.from_symbol(symbol) if symbol.present?
 | 
			
		||||
 | 
			
		||||
        @tag ||= Tag.new(system: HOMEBREW_SYSTEM.downcase.to_sym,
 | 
			
		||||
                         arch:   HOMEBREW_PROCESSOR.downcase.to_sym)
 | 
			
		||||
      sig { params(tag: T.nilable(T.any(Symbol, Tag))).returns(Tag) }
 | 
			
		||||
      def tag(tag = nil)
 | 
			
		||||
        case tag
 | 
			
		||||
        when Symbol
 | 
			
		||||
          Tag.from_symbol(tag)
 | 
			
		||||
        when Tag
 | 
			
		||||
          tag
 | 
			
		||||
        else
 | 
			
		||||
          @tag ||= Tag.new(
 | 
			
		||||
            system: HOMEBREW_SYSTEM.downcase.to_sym,
 | 
			
		||||
            arch:   HOMEBREW_PROCESSOR.downcase.to_sym,
 | 
			
		||||
          )
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def built_as?(formula)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user