Merge branch 'master' into appcast-configuration-match
This commit is contained in:
		
						commit
						446ef2c85f
					
				
							
								
								
									
										2
									
								
								.github/ISSUE_TEMPLATE/feature.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/ISSUE_TEMPLATE/feature.md
									
									
									
									
										vendored
									
									
								
							@ -4,6 +4,8 @@ about: Request our thoughts on your suggestion for a new feature for Homebrew.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Please note we will close your issue without comment if you delete, do not read or do not fill out the issue checklist below and provide ALL the requested information. If you repeatedly fail to use the issue template, we will block you from ever submitting issues to Homebrew again.
 | 
			
		||||
 | 
			
		||||
<!-- Please fill these sections with the relevant information: -->
 | 
			
		||||
 | 
			
		||||
# A detailed description of the proposed feature
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								.github/workflows/docker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								.github/workflows/docker.yml
									
									
									
									
										vendored
									
									
								
							@ -12,7 +12,7 @@ jobs:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    strategy:
 | 
			
		||||
      matrix:
 | 
			
		||||
        version: ["18.04", "20.04"]
 | 
			
		||||
        version: ["16.04", "18.04", "20.04"]
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@master
 | 
			
		||||
@ -33,9 +33,24 @@ jobs:
 | 
			
		||||
          docker login docker.pkg.github.com -u BrewTestBot -p ${{secrets.GITHUB_TOKEN}}
 | 
			
		||||
          docker tag brew "docker.pkg.github.com/homebrew/brew/ubuntu${{matrix.version}}:$brew_version"
 | 
			
		||||
          docker push "docker.pkg.github.com/homebrew/brew/ubuntu${{matrix.version}}:$brew_version"
 | 
			
		||||
          docker tag brew "docker.pkg.github.com/homebrew/brew/ubuntu${{matrix.version}}:latest"
 | 
			
		||||
          docker push "docker.pkg.github.com/homebrew/brew/ubuntu${{matrix.version}}:latest"
 | 
			
		||||
      - name: Deploy the tagged Docker image to Docker Hub
 | 
			
		||||
        if: startsWith(github.ref, 'refs/tags/')
 | 
			
		||||
        run: |
 | 
			
		||||
          docker login -u brewtestbot -p ${{secrets.DOCKER_TOKEN}}
 | 
			
		||||
          docker tag brew "homebrew/ubuntu${{matrix.version}}:$brew_version"
 | 
			
		||||
          docker push "homebrew/ubuntu${{matrix.version}}:$brew_version"
 | 
			
		||||
          docker tag brew "homebrew/ubuntu${{matrix.version}}:latest"
 | 
			
		||||
          docker push "homebrew/ubuntu${{matrix.version}}:latest"
 | 
			
		||||
      - name: Deploy the homebrew/brew Docker image to GitHub and Docker Hub
 | 
			
		||||
        if: startsWith(github.ref, 'refs/tags/') && matrix.version == '20.04'
 | 
			
		||||
        run: |
 | 
			
		||||
          docker tag brew "docker.pkg.github.com/homebrew/brew/brew:$brew_version"
 | 
			
		||||
          docker push "docker.pkg.github.com/homebrew/brew/brew:$brew_version"
 | 
			
		||||
          docker tag brew "docker.pkg.github.com/homebrew/brew/brew:latest"
 | 
			
		||||
          docker push "docker.pkg.github.com/homebrew/brew/brew:latest"
 | 
			
		||||
          docker tag brew "homebrew/brew:$brew_version"
 | 
			
		||||
          docker push "homebrew/brew:$brew_version"
 | 
			
		||||
          docker tag brew "homebrew/brew:latest"
 | 
			
		||||
          docker push "homebrew/brew:latest"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										23
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							@ -3,9 +3,6 @@ on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches: master
 | 
			
		||||
  pull_request: []
 | 
			
		||||
  release:
 | 
			
		||||
    types:
 | 
			
		||||
      - published
 | 
			
		||||
env:
 | 
			
		||||
  HOMEBREW_GITHUB_ACTIONS: 1
 | 
			
		||||
  HOMEBREW_NO_AUTO_UPDATE: 1
 | 
			
		||||
@ -71,6 +68,9 @@ jobs:
 | 
			
		||||
        else
 | 
			
		||||
          # Link old gettext (otherwise `brew doctor` is sad)
 | 
			
		||||
          brew link gettext
 | 
			
		||||
 | 
			
		||||
          # remove deleted formula
 | 
			
		||||
          brew uninstall --force python@2
 | 
			
		||||
        fi
 | 
			
		||||
        brew doctor
 | 
			
		||||
 | 
			
		||||
@ -173,7 +173,7 @@ jobs:
 | 
			
		||||
 | 
			
		||||
    - name: Build Docker image
 | 
			
		||||
      if: matrix.os == 'ubuntu-latest'
 | 
			
		||||
      run: docker build -t brew .
 | 
			
		||||
      run: docker build -t brew --build-arg=version=16.04 .
 | 
			
		||||
 | 
			
		||||
    - name: Run brew test-bot
 | 
			
		||||
      run: |
 | 
			
		||||
@ -184,16 +184,11 @@ jobs:
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
    - name: Deploy the Docker image to GitHub and Docker Hub
 | 
			
		||||
      if: matrix.os == 'ubuntu-latest' && (github.ref == 'refs/heads/master' || github.event_name == 'release')
 | 
			
		||||
      if: matrix.os == 'ubuntu-latest' && github.ref == 'refs/heads/master'
 | 
			
		||||
      run: |
 | 
			
		||||
        case $GITHUB_REF in
 | 
			
		||||
          refs/heads/master) v=latest ;;
 | 
			
		||||
          refs/tags/*) v=${GITHUB_REF:10} ;;
 | 
			
		||||
          *) echo Error: unexpected GITHUB_REF: $GITHUB_REF; exit 1 ;;
 | 
			
		||||
        esac
 | 
			
		||||
        docker login docker.pkg.github.com -u BrewTestBot -p ${{secrets.GITHUB_TOKEN}}
 | 
			
		||||
        docker tag brew "docker.pkg.github.com/homebrew/brew/brew:$v"
 | 
			
		||||
        docker push "docker.pkg.github.com/homebrew/brew/brew:$v"
 | 
			
		||||
        docker tag brew "docker.pkg.github.com/homebrew/brew/ubuntu16.04:master"
 | 
			
		||||
        docker push "docker.pkg.github.com/homebrew/brew/ubuntu16.04:master"
 | 
			
		||||
        docker login -u brewtestbot -p ${{secrets.DOCKER_TOKEN}}
 | 
			
		||||
        docker tag brew "homebrew/brew:$v"
 | 
			
		||||
        docker push "homebrew/brew:$v"
 | 
			
		||||
        docker tag brew "homebrew/ubuntu16.04:master"
 | 
			
		||||
        docker push "homebrew/ubuntu16.04:master"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -110,6 +110,7 @@
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/pry-*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/rainbow-*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/rdiscount-*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/regexp_parser-*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/ronn-*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/rspec-*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/rspec-core-*/
 | 
			
		||||
@ -120,6 +121,7 @@
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/rspec-support-*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/rspec-wait-*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/rubocop-0*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/rubocop-ast-*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/ruby-prof-*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/ruby-progressbar-*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/simplecov-*/
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
ARG version=16.04
 | 
			
		||||
ARG version=20.04
 | 
			
		||||
FROM ubuntu:$version
 | 
			
		||||
ARG DEBIAN_FRONTEND=noninteractive
 | 
			
		||||
 | 
			
		||||
@ -42,6 +42,8 @@ RUN cd /home/linuxbrew/.linuxbrew \
 | 
			
		||||
  && HOMEBREW_NO_ANALYTICS=1 HOMEBREW_NO_AUTO_UPDATE=1 brew tap homebrew/core \
 | 
			
		||||
  && brew install-bundler-gems \
 | 
			
		||||
  && brew cleanup \
 | 
			
		||||
  && { git -C /home/linuxbrew/.linuxbrew/Homebrew config --unset gc.auto; true; } \
 | 
			
		||||
  && { git -C /home/linuxbrew/.linuxbrew/Homebrew config --unset homebrew.devcmdrun; true; } \
 | 
			
		||||
  && rm -rf ~/.cache \
 | 
			
		||||
  && chown -R linuxbrew: /home/linuxbrew/.linuxbrew \
 | 
			
		||||
  && chmod -R g+w,o-w /home/linuxbrew/.linuxbrew
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@ AllCops:
 | 
			
		||||
 | 
			
		||||
# Use `<<~` for heredocs.
 | 
			
		||||
Layout/HeredocIndentation:
 | 
			
		||||
  EnforcedStyle: squiggly
 | 
			
		||||
  Enabled: true
 | 
			
		||||
 | 
			
		||||
# Not useful in casks and formulae.
 | 
			
		||||
Metrics/BlockLength:
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,7 @@ GEM
 | 
			
		||||
    ast (2.4.0)
 | 
			
		||||
    byebug (11.1.3)
 | 
			
		||||
    concurrent-ruby (1.1.6)
 | 
			
		||||
    connection_pool (2.2.2)
 | 
			
		||||
    connection_pool (2.2.3)
 | 
			
		||||
    coveralls (0.8.23)
 | 
			
		||||
      json (>= 1.8, < 3)
 | 
			
		||||
      simplecov (~> 0.16.1)
 | 
			
		||||
@ -24,7 +24,7 @@ GEM
 | 
			
		||||
    hpricot (0.8.6)
 | 
			
		||||
    http-cookie (1.0.3)
 | 
			
		||||
      domain_name (~> 0.5)
 | 
			
		||||
    i18n (1.8.2)
 | 
			
		||||
    i18n (1.8.3)
 | 
			
		||||
      concurrent-ruby (~> 1.0)
 | 
			
		||||
    json (2.3.0)
 | 
			
		||||
    mechanize (2.7.6)
 | 
			
		||||
@ -51,11 +51,12 @@ GEM
 | 
			
		||||
    parallel (1.19.1)
 | 
			
		||||
    parallel_tests (2.32.0)
 | 
			
		||||
      parallel
 | 
			
		||||
    parser (2.7.1.2)
 | 
			
		||||
    parser (2.7.1.3)
 | 
			
		||||
      ast (~> 2.4.0)
 | 
			
		||||
    plist (3.5.0)
 | 
			
		||||
    rainbow (3.0.0)
 | 
			
		||||
    rdiscount (2.2.0.1)
 | 
			
		||||
    regexp_parser (1.7.0)
 | 
			
		||||
    rexml (3.2.4)
 | 
			
		||||
    ronn (0.7.3)
 | 
			
		||||
      hpricot (>= 0.8.2)
 | 
			
		||||
@ -81,14 +82,18 @@ GEM
 | 
			
		||||
    rspec-support (3.9.3)
 | 
			
		||||
    rspec-wait (0.0.9)
 | 
			
		||||
      rspec (>= 3, < 4)
 | 
			
		||||
    rubocop (0.83.0)
 | 
			
		||||
    rubocop (0.85.0)
 | 
			
		||||
      parallel (~> 1.10)
 | 
			
		||||
      parser (>= 2.7.0.1)
 | 
			
		||||
      rainbow (>= 2.2.2, < 4.0)
 | 
			
		||||
      regexp_parser (>= 1.7)
 | 
			
		||||
      rexml
 | 
			
		||||
      rubocop-ast (>= 0.0.3)
 | 
			
		||||
      ruby-progressbar (~> 1.7)
 | 
			
		||||
      unicode-display_width (>= 1.4.0, < 2.0)
 | 
			
		||||
    rubocop-performance (1.5.2)
 | 
			
		||||
    rubocop-ast (0.0.3)
 | 
			
		||||
      parser (>= 2.7.0.1)
 | 
			
		||||
    rubocop-performance (1.6.1)
 | 
			
		||||
      rubocop (>= 0.71.0)
 | 
			
		||||
    rubocop-rspec (1.39.0)
 | 
			
		||||
      rubocop (>= 0.68.1)
 | 
			
		||||
 | 
			
		||||
@ -50,7 +50,7 @@ begin
 | 
			
		||||
  help_flag = !ENV["HOMEBREW_HELP"].nil?
 | 
			
		||||
  cmd = nil
 | 
			
		||||
 | 
			
		||||
  ARGV.dup.each_with_index do |arg, i|
 | 
			
		||||
  ARGV.each_with_index do |arg, i|
 | 
			
		||||
    break if help_flag && cmd
 | 
			
		||||
 | 
			
		||||
    if arg == "help" && !cmd
 | 
			
		||||
@ -139,8 +139,8 @@ rescue UsageError => e
 | 
			
		||||
  require "help"
 | 
			
		||||
  Homebrew::Help.help cmd, usage_error: e.message
 | 
			
		||||
rescue SystemExit => e
 | 
			
		||||
  onoe "Kernel.exit" if ARGV.debug? && !e.success?
 | 
			
		||||
  $stderr.puts e.backtrace if ARGV.debug?
 | 
			
		||||
  onoe "Kernel.exit" if Homebrew.args.debug? && !e.success?
 | 
			
		||||
  $stderr.puts e.backtrace if Homebrew.args.debug?
 | 
			
		||||
  raise
 | 
			
		||||
rescue Interrupt
 | 
			
		||||
  $stderr.puts # seemingly a newline is typical
 | 
			
		||||
@ -156,7 +156,7 @@ rescue RuntimeError, SystemCallError => e
 | 
			
		||||
  raise if e.message.empty?
 | 
			
		||||
 | 
			
		||||
  onoe e
 | 
			
		||||
  $stderr.puts e.backtrace if ARGV.debug?
 | 
			
		||||
  $stderr.puts e.backtrace if Homebrew.args.debug?
 | 
			
		||||
 | 
			
		||||
  output_unsupported_error if Homebrew.args.HEAD?
 | 
			
		||||
 | 
			
		||||
@ -167,7 +167,7 @@ rescue MethodDeprecatedError => e
 | 
			
		||||
    $stderr.puts "If reporting this issue please do so at (not Homebrew/brew or Homebrew/core):"
 | 
			
		||||
    $stderr.puts "  #{Formatter.url(e.issues_url)}"
 | 
			
		||||
  end
 | 
			
		||||
  $stderr.puts e.backtrace if ARGV.debug?
 | 
			
		||||
  $stderr.puts e.backtrace if Homebrew.args.debug?
 | 
			
		||||
  exit 1
 | 
			
		||||
rescue Exception => e # rubocop:disable Lint/RescueException
 | 
			
		||||
  onoe e
 | 
			
		||||
 | 
			
		||||
@ -52,6 +52,8 @@ class Build
 | 
			
		||||
        Requirement.prune
 | 
			
		||||
      elsif req.prune_if_build_and_not_dependent?(dependent, formula)
 | 
			
		||||
        Requirement.prune
 | 
			
		||||
      elsif req.test?
 | 
			
		||||
        Requirement.prune
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
@ -65,6 +67,8 @@ class Build
 | 
			
		||||
        Dependency.prune
 | 
			
		||||
      elsif dep.build?
 | 
			
		||||
        Dependency.keep_but_prune_recursive_deps
 | 
			
		||||
      elsif dep.test?
 | 
			
		||||
        Dependency.prune
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
@ -112,7 +116,7 @@ class Build
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    with_env(new_env) do
 | 
			
		||||
      formula.extend(Debrew::Formula) if ARGV.debug?
 | 
			
		||||
      formula.extend(Debrew::Formula) if Homebrew.args.debug?
 | 
			
		||||
 | 
			
		||||
      formula.update_head_version
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -89,7 +89,7 @@ module Cask
 | 
			
		||||
              args: ["list", service],
 | 
			
		||||
              sudo: with_sudo, print_stderr: false
 | 
			
		||||
            ).stdout
 | 
			
		||||
            if plist_status.match?(/^\{/)
 | 
			
		||||
            if plist_status.start_with?("{")
 | 
			
		||||
              command.run!("/bin/launchctl", args: ["remove", service], sudo: with_sudo)
 | 
			
		||||
              sleep 1
 | 
			
		||||
            end
 | 
			
		||||
@ -326,7 +326,14 @@ module Cask
 | 
			
		||||
            next
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          yield path, Pathname.glob(resolved_path)
 | 
			
		||||
          begin
 | 
			
		||||
            yield path, Pathname.glob(resolved_path)
 | 
			
		||||
          rescue Errno::EPERM
 | 
			
		||||
            raise if File.readable?(File.expand_path("~/Library/Application Support/com.apple.TCC"))
 | 
			
		||||
 | 
			
		||||
            odie "Unable to remove some files. Please enable Full Disk Access for your terminal under " \
 | 
			
		||||
                 "System Preferences → Security & Privacy → Privacy → Full Disk Access."
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ require "cask/download"
 | 
			
		||||
require "digest"
 | 
			
		||||
require "utils/curl"
 | 
			
		||||
require "utils/git"
 | 
			
		||||
require "utils/notability"
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  class Audit
 | 
			
		||||
@ -14,22 +15,22 @@ module Cask
 | 
			
		||||
 | 
			
		||||
    attr_reader :cask, :commit_range, :download
 | 
			
		||||
 | 
			
		||||
    attr_predicate :check_appcast?
 | 
			
		||||
    attr_predicate :appcast?
 | 
			
		||||
 | 
			
		||||
    def initialize(cask, check_appcast: false, download: false, check_token_conflicts: false,
 | 
			
		||||
                   commit_range: nil, command: SystemCommand)
 | 
			
		||||
    def initialize(cask, appcast: false, download: false,
 | 
			
		||||
                   token_conflicts: false, online: false, strict: false,
 | 
			
		||||
                   new_cask: false, commit_range: nil, command: SystemCommand)
 | 
			
		||||
      @cask = cask
 | 
			
		||||
      @check_appcast = check_appcast
 | 
			
		||||
      @appcast = appcast
 | 
			
		||||
      @download = download
 | 
			
		||||
      @online = online
 | 
			
		||||
      @strict = strict
 | 
			
		||||
      @new_cask = new_cask
 | 
			
		||||
      @commit_range = commit_range
 | 
			
		||||
      @check_token_conflicts = check_token_conflicts
 | 
			
		||||
      @token_conflicts = token_conflicts
 | 
			
		||||
      @command = command
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def check_token_conflicts?
 | 
			
		||||
      @check_token_conflicts
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def run!
 | 
			
		||||
      check_blacklist
 | 
			
		||||
      check_required_stanzas
 | 
			
		||||
@ -48,6 +49,9 @@ module Cask
 | 
			
		||||
      check_latest_with_auto_updates
 | 
			
		||||
      check_stanza_requires_uninstall
 | 
			
		||||
      check_appcast_contains_version
 | 
			
		||||
      check_github_repository
 | 
			
		||||
      check_gitlab_repository
 | 
			
		||||
      check_bitbucket_repository
 | 
			
		||||
      self
 | 
			
		||||
    rescue => e
 | 
			
		||||
      odebug "#{e.message}\n#{e.backtrace.join("\n")}"
 | 
			
		||||
@ -255,7 +259,7 @@ module Cask
 | 
			
		||||
      bad_url_format?(/sourceforge/,
 | 
			
		||||
                      [
 | 
			
		||||
                        %r{\Ahttps://sourceforge\.net/projects/[^/]+/files/latest/download\Z},
 | 
			
		||||
                        %r{\Ahttps://downloads\.sourceforge\.net/(?!(project|sourceforge)\/)},
 | 
			
		||||
                        %r{\Ahttps://downloads\.sourceforge\.net/(?!(project|sourceforge)/)},
 | 
			
		||||
                      ])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -272,7 +276,7 @@ module Cask
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def check_token_conflicts
 | 
			
		||||
      return unless check_token_conflicts?
 | 
			
		||||
      return unless @token_conflicts
 | 
			
		||||
      return unless core_formula_names.include?(cask.token)
 | 
			
		||||
 | 
			
		||||
      add_warning "possible duplicate, cask token conflicts with Homebrew core formula: #{core_formula_url}"
 | 
			
		||||
@ -301,7 +305,7 @@ module Cask
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def check_appcast_contains_version
 | 
			
		||||
      return unless check_appcast?
 | 
			
		||||
      return unless appcast?
 | 
			
		||||
      return if cask.appcast.to_s.empty?
 | 
			
		||||
      return if cask.appcast.must_contain == :no_check
 | 
			
		||||
 | 
			
		||||
@ -309,8 +313,8 @@ module Cask
 | 
			
		||||
      appcast_contents, = curl_output("--compressed", "--user-agent", HOMEBREW_USER_AGENT_FAKE_SAFARI, "--location",
 | 
			
		||||
                                      "--globoff", "--max-time", "5", appcast_stanza)
 | 
			
		||||
      version_stanza = cask.version.to_s
 | 
			
		||||
      adjusted_version_stanza = if cask.appcast.must_contain.blank?
 | 
			
		||||
        version_stanza.split(",")[0].split("-")[0].split("_")[0]
 | 
			
		||||
      adjusted_version_stanza = if cask.appcast.configuration.blank?
 | 
			
		||||
        version_stanza.match(/^[[:alnum:].]+/)[0]
 | 
			
		||||
      else
 | 
			
		||||
        cask.appcast.must_contain
 | 
			
		||||
      end
 | 
			
		||||
@ -322,6 +326,50 @@ module Cask
 | 
			
		||||
      add_error "appcast at URL '#{appcast_stanza}' offline or looping"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def check_github_repository
 | 
			
		||||
      user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*})
 | 
			
		||||
      return if user.nil?
 | 
			
		||||
 | 
			
		||||
      odebug "Auditing GitHub repo"
 | 
			
		||||
 | 
			
		||||
      error = SharedAudits.github(user, repo)
 | 
			
		||||
      add_error error if error
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def check_gitlab_repository
 | 
			
		||||
      user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*})
 | 
			
		||||
      return if user.nil?
 | 
			
		||||
 | 
			
		||||
      odebug "Auditing GitLab repo"
 | 
			
		||||
 | 
			
		||||
      error = SharedAudits.gitlab(user, repo)
 | 
			
		||||
      add_error error if error
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def check_bitbucket_repository
 | 
			
		||||
      user, repo = get_repo_data(%r{https?://bitbucket\.org/([^/]+)/([^/]+)/?.*})
 | 
			
		||||
      return if user.nil?
 | 
			
		||||
 | 
			
		||||
      odebug "Auditing Bitbucket repo"
 | 
			
		||||
 | 
			
		||||
      error = SharedAudits.bitbucket(user, repo)
 | 
			
		||||
      add_error error if error
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def get_repo_data(regex)
 | 
			
		||||
      return unless @online
 | 
			
		||||
      return unless @new_cask
 | 
			
		||||
 | 
			
		||||
      _, user, repo = *regex.match(cask.url.to_s)
 | 
			
		||||
      _, user, repo = *regex.match(cask.homepage) unless user
 | 
			
		||||
      _, user, repo = *regex.match(cask.appcast.to_s) unless user
 | 
			
		||||
      return if !user || !repo
 | 
			
		||||
 | 
			
		||||
      repo.gsub!(/.git$/, "")
 | 
			
		||||
 | 
			
		||||
      [user, repo]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def check_blacklist
 | 
			
		||||
      return if cask.tap&.user != "Homebrew"
 | 
			
		||||
      return unless reason = Blacklist.blacklisted_reason(cask.token)
 | 
			
		||||
 | 
			
		||||
@ -8,37 +8,40 @@ module Cask
 | 
			
		||||
    extend Predicable
 | 
			
		||||
 | 
			
		||||
    def self.audit(cask, audit_download: false, audit_appcast: false,
 | 
			
		||||
                   check_token_conflicts: false, quarantine: true, commit_range: nil)
 | 
			
		||||
                   audit_online: false, audit_strict: false,
 | 
			
		||||
                   audit_token_conflicts: false, audit_new_cask: false,
 | 
			
		||||
                   quarantine: true, commit_range: nil)
 | 
			
		||||
      new(cask, audit_download: audit_download,
 | 
			
		||||
                audit_appcast: audit_appcast,
 | 
			
		||||
                check_token_conflicts: check_token_conflicts,
 | 
			
		||||
                audit_online: audit_online,
 | 
			
		||||
                audit_new_cask: audit_new_cask,
 | 
			
		||||
                audit_strict: audit_strict,
 | 
			
		||||
                audit_token_conflicts: audit_token_conflicts,
 | 
			
		||||
                quarantine: quarantine, commit_range: commit_range).audit
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    attr_reader :cask, :commit_range
 | 
			
		||||
 | 
			
		||||
    def initialize(cask, audit_download: false, audit_appcast: false,
 | 
			
		||||
                   check_token_conflicts: false, quarantine: true, commit_range: nil)
 | 
			
		||||
                   audit_online: false, audit_strict: false,
 | 
			
		||||
                   audit_token_conflicts: false, audit_new_cask: false,
 | 
			
		||||
                   quarantine: true, commit_range: nil)
 | 
			
		||||
      @cask = cask
 | 
			
		||||
      @audit_download = audit_download
 | 
			
		||||
      @audit_appcast = audit_appcast
 | 
			
		||||
      @audit_online = audit_online
 | 
			
		||||
      @audit_strict = audit_strict
 | 
			
		||||
      @audit_new_cask = audit_new_cask
 | 
			
		||||
      @quarantine = quarantine
 | 
			
		||||
      @commit_range = commit_range
 | 
			
		||||
      @check_token_conflicts = check_token_conflicts
 | 
			
		||||
      @audit_token_conflicts = audit_token_conflicts
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def audit_download?
 | 
			
		||||
      @audit_download
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    attr_predicate :audit_appcast?, :quarantine?
 | 
			
		||||
 | 
			
		||||
    def check_token_conflicts?
 | 
			
		||||
      @check_token_conflicts
 | 
			
		||||
    end
 | 
			
		||||
    attr_predicate :audit_appcast?, :audit_download?, :audit_online?,
 | 
			
		||||
                   :audit_strict?, :audit_new_cask?, :audit_token_conflicts?, :quarantine?
 | 
			
		||||
 | 
			
		||||
    def audit
 | 
			
		||||
      if !ARGV.value("language") && language_blocks
 | 
			
		||||
      if !Homebrew.args.value("language") && language_blocks
 | 
			
		||||
        audit_all_languages
 | 
			
		||||
      else
 | 
			
		||||
        audit_cask_instance(cask)
 | 
			
		||||
@ -64,10 +67,13 @@ module Cask
 | 
			
		||||
 | 
			
		||||
    def audit_cask_instance(cask)
 | 
			
		||||
      download = audit_download? && Download.new(cask, quarantine: quarantine?)
 | 
			
		||||
      audit = Audit.new(cask, check_appcast:         audit_appcast?,
 | 
			
		||||
                              download:              download,
 | 
			
		||||
                              check_token_conflicts: check_token_conflicts?,
 | 
			
		||||
                              commit_range:          commit_range)
 | 
			
		||||
      audit = Audit.new(cask, appcast:         audit_appcast?,
 | 
			
		||||
                              online:          audit_online?,
 | 
			
		||||
                              strict:          audit_strict?,
 | 
			
		||||
                              new_cask:        audit_new_cask?,
 | 
			
		||||
                              token_conflicts: audit_token_conflicts?,
 | 
			
		||||
                              download:        download,
 | 
			
		||||
                              commit_range:    commit_range)
 | 
			
		||||
      audit.run!
 | 
			
		||||
      puts audit.summary
 | 
			
		||||
      audit.success?
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@ module Cask
 | 
			
		||||
  module Blacklist
 | 
			
		||||
    def self.blacklisted_reason(name)
 | 
			
		||||
      case name
 | 
			
		||||
      when /^adobe\-(after|illustrator|indesign|photoshop|premiere)/
 | 
			
		||||
      when /^adobe-(after|illustrator|indesign|photoshop|premiere)/
 | 
			
		||||
        "Adobe casks were removed because they are too difficult to maintain."
 | 
			
		||||
      when /^audacity$/
 | 
			
		||||
        "Audacity was removed because it is too difficult to download programmatically."
 | 
			
		||||
 | 
			
		||||
@ -145,13 +145,13 @@ module Cask
 | 
			
		||||
      command, args = detect_internal_command(*args) || detect_external_command(*args) || [NullCommand.new, args]
 | 
			
		||||
 | 
			
		||||
      if help?
 | 
			
		||||
        puts command.help
 | 
			
		||||
        Help.new(command.command_name).run
 | 
			
		||||
      else
 | 
			
		||||
        command.run(*args)
 | 
			
		||||
      end
 | 
			
		||||
    rescue CaskError, MethodDeprecatedError, ArgumentError, OptionParser::InvalidOption => e
 | 
			
		||||
      onoe e.message
 | 
			
		||||
      $stderr.puts e.backtrace if ARGV.debug?
 | 
			
		||||
      $stderr.puts e.backtrace if Homebrew.args.debug?
 | 
			
		||||
      exit 1
 | 
			
		||||
    rescue StandardError, ScriptError, NoMemoryError => e
 | 
			
		||||
      onoe e.message
 | 
			
		||||
@ -180,7 +180,7 @@ module Cask
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def process_options(*args)
 | 
			
		||||
      exclude_regex = /^\-\-#{Regexp.union(*Config::DEFAULT_DIRS.keys.map(&Regexp.public_method(:escape)))}=/
 | 
			
		||||
      exclude_regex = /^--#{Regexp.union(*Config::DEFAULT_DIRS.keys.map(&Regexp.public_method(:escape)))}=/
 | 
			
		||||
 | 
			
		||||
      non_options = []
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,32 +1,66 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "cli/parser"
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  class Cmd
 | 
			
		||||
    class Audit < AbstractCommand
 | 
			
		||||
      option "--download",        :download,        false
 | 
			
		||||
      option "--appcast",         :appcast,         false
 | 
			
		||||
      option "--token-conflicts", :token_conflicts, false
 | 
			
		||||
      option "--download",        :download_arg,        false
 | 
			
		||||
      option "--appcast",         :appcast_arg,         false
 | 
			
		||||
      option "--token-conflicts", :token_conflicts_arg, false
 | 
			
		||||
      option "--strict",          :strict_arg,          false
 | 
			
		||||
      option "--online",          :online_arg,          false
 | 
			
		||||
      option "--new-cask",        :new_cask_arg,        false
 | 
			
		||||
 | 
			
		||||
      def self.usage
 | 
			
		||||
        <<~EOS
 | 
			
		||||
          `cask audit` [<options>] [<cask>]
 | 
			
		||||
 | 
			
		||||
          --strict          - Run additional, stricter style checks.
 | 
			
		||||
          --online          - Run additional, slower style checks that require a network connection.
 | 
			
		||||
          --new-cask        - Run various additional style checks to determine if a new cask is eligible
 | 
			
		||||
                              for Homebrew. This should be used when creating new casks and implies
 | 
			
		||||
                              `--strict` and `--online`.
 | 
			
		||||
          --download        - Audit the downloaded file
 | 
			
		||||
          --appcast         - Audit the appcast
 | 
			
		||||
          --token-conflicts - Audit for token conflicts
 | 
			
		||||
 | 
			
		||||
          Check <cask> for Homebrew coding style violations. This should be run before
 | 
			
		||||
          submitting a new cask. If no <casks> are provided, check all locally
 | 
			
		||||
          available casks. Will exit with a non-zero status if any errors are
 | 
			
		||||
          found, which can be useful for implementing pre-commit hooks.
 | 
			
		||||
        EOS
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.help
 | 
			
		||||
        "verifies installability of Casks"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def run
 | 
			
		||||
        Homebrew.auditing = true
 | 
			
		||||
        strict = new_cask_arg? || strict_arg?
 | 
			
		||||
        token_conflicts = strict || token_conflicts_arg?
 | 
			
		||||
 | 
			
		||||
        online = new_cask_arg? || online_arg?
 | 
			
		||||
        download = online || download_arg?
 | 
			
		||||
        appcast = online || appcast_arg?
 | 
			
		||||
 | 
			
		||||
        failed_casks = casks(alternative: -> { Cask.to_a })
 | 
			
		||||
                       .reject { |cask| audit(cask) }
 | 
			
		||||
                       .reject do |cask|
 | 
			
		||||
          odebug "Auditing Cask #{cask}"
 | 
			
		||||
          Auditor.audit(cask, audit_download:        download,
 | 
			
		||||
                              audit_appcast:         appcast,
 | 
			
		||||
                              audit_online:          online,
 | 
			
		||||
                              audit_strict:          strict,
 | 
			
		||||
                              audit_new_cask:        new_cask_arg?,
 | 
			
		||||
                              audit_token_conflicts: token_conflicts,
 | 
			
		||||
                              quarantine:            quarantine?)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        return if failed_casks.empty?
 | 
			
		||||
 | 
			
		||||
        raise CaskError, "audit failed for casks: #{failed_casks.join(" ")}"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def audit(cask)
 | 
			
		||||
        odebug "Auditing Cask #{cask}"
 | 
			
		||||
        Auditor.audit(cask, audit_download:        download?,
 | 
			
		||||
                            audit_appcast:         appcast?,
 | 
			
		||||
                            check_token_conflicts: token_conflicts?,
 | 
			
		||||
                            quarantine:            quarantine?)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -3,17 +3,26 @@
 | 
			
		||||
module Cask
 | 
			
		||||
  class Cmd
 | 
			
		||||
    class Help < AbstractCommand
 | 
			
		||||
      def initialize(*)
 | 
			
		||||
        super
 | 
			
		||||
        return if args.empty?
 | 
			
		||||
 | 
			
		||||
        raise ArgumentError, "#{self.class.command_name} does not take arguments."
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def run
 | 
			
		||||
        puts self.class.purpose
 | 
			
		||||
        puts
 | 
			
		||||
        puts self.class.usage
 | 
			
		||||
        if args.empty?
 | 
			
		||||
          puts self.class.purpose
 | 
			
		||||
          puts
 | 
			
		||||
          puts self.class.usage
 | 
			
		||||
        elsif args.count == 1
 | 
			
		||||
          command_name = args.first
 | 
			
		||||
 | 
			
		||||
          unless command = self.class.commands[command_name]
 | 
			
		||||
            raise "No help information found for command '#{command_name}'."
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          if command.respond_to?(:usage)
 | 
			
		||||
            puts command.usage
 | 
			
		||||
          else
 | 
			
		||||
            puts command.help
 | 
			
		||||
          end
 | 
			
		||||
        else
 | 
			
		||||
          raise ArgumentError, "#{self.class.command_name} only takes up to one argument."
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.purpose
 | 
			
		||||
@ -23,6 +32,10 @@ module Cask
 | 
			
		||||
        EOS
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.commands
 | 
			
		||||
        Cmd.command_classes.select(&:visible?).map { |klass| [klass.command_name, klass] }.to_h
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.usage
 | 
			
		||||
        max_command_len = Cmd.commands.map(&:length).max
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -46,6 +46,7 @@ module Cask
 | 
			
		||||
 | 
			
		||||
      def self.info(cask)
 | 
			
		||||
        puts get_info(cask)
 | 
			
		||||
        ::Utils::Analytics.cask_output(cask)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def self.title_info(cask)
 | 
			
		||||
 | 
			
		||||
@ -46,7 +46,7 @@ module Cask
 | 
			
		||||
          next if self.class.options.nil?
 | 
			
		||||
 | 
			
		||||
          self.class.options.each do |option_name, option_method|
 | 
			
		||||
            option_type = case option_name.split(/(\ |\=)/).last
 | 
			
		||||
            option_type = case option_name.split(/(\ |=)/).last
 | 
			
		||||
            when "PATH"
 | 
			
		||||
              Pathname
 | 
			
		||||
            when /\w+(,\w+)+/
 | 
			
		||||
 | 
			
		||||
@ -86,7 +86,7 @@ module Cask
 | 
			
		||||
        Shellwords.shellsplit(ENV.fetch("HOMEBREW_CASK_OPTS", ""))
 | 
			
		||||
                  .select { |arg| arg.include?("=") }
 | 
			
		||||
                  .map { |arg| arg.split("=", 2) }
 | 
			
		||||
                  .map { |(flag, value)| [flag.sub(/^\-\-/, ""), value] },
 | 
			
		||||
                  .map { |(flag, value)| [flag.sub(/^--/, ""), value] },
 | 
			
		||||
      )
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -58,6 +58,19 @@ module Cask
 | 
			
		||||
        EOS
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      caveat :unsigned_accessibility do |access = "Accessibility"|
 | 
			
		||||
        # access: the category in System Preferences -> Security & Privacy -> Privacy the app requires.
 | 
			
		||||
 | 
			
		||||
        <<~EOS
 | 
			
		||||
          #{@cask} is not signed and requires Accessibility access,
 | 
			
		||||
          so you will need to re-grant Accessibility access every time the app is updated.
 | 
			
		||||
 | 
			
		||||
          Enable or re-enable it in:
 | 
			
		||||
            System Preferences → Security & Privacy → Privacy -> #{access}
 | 
			
		||||
          To re-enable untick and retick #{@cask}.app.
 | 
			
		||||
        EOS
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      caveat :path_environment_variable do |path|
 | 
			
		||||
        <<~EOS
 | 
			
		||||
          To use #{@cask}, you may need to add the #{path} directory
 | 
			
		||||
 | 
			
		||||
@ -11,9 +11,9 @@ module Cask
 | 
			
		||||
 | 
			
		||||
      DIVIDER_REGEX = /(#{DIVIDERS.keys.map { |v| Regexp.quote(v) }.join('|')})/.freeze
 | 
			
		||||
 | 
			
		||||
      MAJOR_MINOR_PATCH_REGEX = /^([^.,:]+)(?:\.([^.,:]+)(?:\.([^.,:]+))?)?/.freeze
 | 
			
		||||
      MAJOR_MINOR_PATCH_REGEX = /^([^.,:]+)(?:.([^.,:]+)(?:.([^.,:]+))?)?/.freeze
 | 
			
		||||
 | 
			
		||||
      INVALID_CHARACTERS = /[^0-9a-zA-Z\.\,\:\-\_]/.freeze
 | 
			
		||||
      INVALID_CHARACTERS = /[^0-9a-zA-Z.,:\-_]/.freeze
 | 
			
		||||
 | 
			
		||||
      class << self
 | 
			
		||||
        private
 | 
			
		||||
@ -75,7 +75,7 @@ module Cask
 | 
			
		||||
        s = downcase.delete(".").gsub(/[^a-z\d]+/, "-")
 | 
			
		||||
 | 
			
		||||
        return true if s.match?(/(\d+|\b)(alpha|beta|preview|rc|dev|canary|snapshot)(\d+|\b)/i)
 | 
			
		||||
        return true if s.match?(/\A[a-z\d]+(\-\d+)*\-?(a|b|pre)(\d+|\b)/i)
 | 
			
		||||
        return true if s.match?(/\A[a-z\d]+(-\d+)*-?(a|b|pre)(\d+|\b)/i)
 | 
			
		||||
 | 
			
		||||
        false
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -368,8 +368,8 @@ module Cask
 | 
			
		||||
            fi.installed_on_request = false
 | 
			
		||||
            fi.show_header = true
 | 
			
		||||
            fi.verbose = verbose?
 | 
			
		||||
            fi.fetch
 | 
			
		||||
            fi.prelude
 | 
			
		||||
            fi.fetch
 | 
			
		||||
            fi.install
 | 
			
		||||
            fi.finish
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
@ -109,7 +109,7 @@ class Cleaner
 | 
			
		||||
        else
 | 
			
		||||
          0444
 | 
			
		||||
        end
 | 
			
		||||
        if ARGV.debug?
 | 
			
		||||
        if Homebrew.args.debug?
 | 
			
		||||
          old_perms = path.stat.mode & 0777
 | 
			
		||||
          odebug "Fixing #{path} permissions from #{old_perms.to_s(8)} to #{perms.to_s(8)}" if perms != old_perms
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
@ -56,14 +56,14 @@ module CleanupRefinement
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      version ||= basename.to_s[/\A.*(?:\-\-.*?)*\-\-(.*?)#{Regexp.escape(extname)}\Z/, 1]
 | 
			
		||||
      version ||= basename.to_s[/\A.*\-\-?(.*?)#{Regexp.escape(extname)}\Z/, 1]
 | 
			
		||||
      version ||= basename.to_s[/\A.*(?:--.*?)*--(.*?)#{Regexp.escape(extname)}\Z/, 1]
 | 
			
		||||
      version ||= basename.to_s[/\A.*--?(.*?)#{Regexp.escape(extname)}\Z/, 1]
 | 
			
		||||
 | 
			
		||||
      return false unless version
 | 
			
		||||
 | 
			
		||||
      version = Version.new(version)
 | 
			
		||||
 | 
			
		||||
      return false unless formula_name = basename.to_s[/\A(.*?)(?:\-\-.*?)*\-\-?(?:#{Regexp.escape(version)})/, 1]
 | 
			
		||||
      return false unless formula_name = basename.to_s[/\A(.*?)(?:--.*?)*--?(?:#{Regexp.escape(version)})/, 1]
 | 
			
		||||
 | 
			
		||||
      formula = begin
 | 
			
		||||
        Formulary.from_rack(HOMEBREW_CELLAR/formula_name)
 | 
			
		||||
@ -71,7 +71,7 @@ module CleanupRefinement
 | 
			
		||||
        return false
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      resource_name = basename.to_s[/\A.*?\-\-(.*?)\-\-?(?:#{Regexp.escape(version)})/, 1]
 | 
			
		||||
      resource_name = basename.to_s[/\A.*?--(.*?)--?(?:#{Regexp.escape(version)})/, 1]
 | 
			
		||||
 | 
			
		||||
      if resource_name == "patch"
 | 
			
		||||
        patch_hashes = formula.stable&.patches&.select(&:external?)&.map(&:resource)&.map(&:version)
 | 
			
		||||
@ -84,7 +84,7 @@ module CleanupRefinement
 | 
			
		||||
        return true
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      return true if scrub && !formula.installed?
 | 
			
		||||
      return true if scrub && !formula.latest_version_installed?
 | 
			
		||||
 | 
			
		||||
      return true if Utils::Bottles.file_outdated?(formula, self)
 | 
			
		||||
 | 
			
		||||
@ -92,7 +92,7 @@ module CleanupRefinement
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def stale_cask?(scrub)
 | 
			
		||||
      return false unless name = basename.to_s[/\A(.*?)\-\-/, 1]
 | 
			
		||||
      return false unless name = basename.to_s[/\A(.*?)--/, 1]
 | 
			
		||||
 | 
			
		||||
      cask = begin
 | 
			
		||||
        Cask::CaskLoader.load(name)
 | 
			
		||||
@ -100,7 +100,7 @@ module CleanupRefinement
 | 
			
		||||
        return false
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      return true unless basename.to_s.match?(/\A#{Regexp.escape(name)}\-\-#{Regexp.escape(cask.version)}\b/)
 | 
			
		||||
      return true unless basename.to_s.match?(/\A#{Regexp.escape(name)}--#{Regexp.escape(cask.version)}\b/)
 | 
			
		||||
 | 
			
		||||
      return true if scrub && !cask.versions.include?(cask.version)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,7 @@ module Homebrew
 | 
			
		||||
      # undefine tap to allow --tap argument
 | 
			
		||||
      undef tap
 | 
			
		||||
 | 
			
		||||
      def initialize(argv = ARGV.dup.freeze, set_default_args: false)
 | 
			
		||||
      def initialize(argv = ARGV.freeze, set_default_args: false)
 | 
			
		||||
        super()
 | 
			
		||||
 | 
			
		||||
        @processed_options = []
 | 
			
		||||
@ -84,11 +84,7 @@ module Homebrew
 | 
			
		||||
        require "formula"
 | 
			
		||||
 | 
			
		||||
        @formulae ||= (downcased_unique_named - casks).map do |name|
 | 
			
		||||
          if name.include?("/") || File.exist?(name)
 | 
			
		||||
            Formulary.factory(name, spec)
 | 
			
		||||
          else
 | 
			
		||||
            Formulary.find_with_priority(name, spec)
 | 
			
		||||
          end
 | 
			
		||||
          Formulary.factory(name, spec)
 | 
			
		||||
        end.uniq(&:name).freeze
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -175,6 +171,20 @@ module Homebrew
 | 
			
		||||
        formulae.any? { |args_f| args_f.full_name == f.full_name }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def include_formula_test_deps?(f)
 | 
			
		||||
        return false unless include_test?
 | 
			
		||||
 | 
			
		||||
        formulae.any? { |args_f| args_f.full_name == f.full_name }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def value(name)
 | 
			
		||||
        arg_prefix = "--#{name}="
 | 
			
		||||
        flag_with_value = flags_only.find { |arg| arg.start_with?(arg_prefix) }
 | 
			
		||||
        return unless flag_with_value
 | 
			
		||||
 | 
			
		||||
        flag_with_value.delete_prefix(arg_prefix)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      def option_to_name(option)
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,7 @@ module Homebrew
 | 
			
		||||
    class Parser
 | 
			
		||||
      attr_reader :processed_options, :hide_from_man_page
 | 
			
		||||
 | 
			
		||||
      def self.parse(argv = ARGV.dup.freeze, allow_no_named_args: false, &block)
 | 
			
		||||
      def self.parse(argv = ARGV.freeze, allow_no_named_args: false, &block)
 | 
			
		||||
        new(argv, &block).parse(allow_no_named_args: allow_no_named_args)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -38,7 +38,7 @@ module Homebrew
 | 
			
		||||
        }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def initialize(argv = ARGV.dup.freeze, &block)
 | 
			
		||||
      def initialize(argv = ARGV.freeze, &block)
 | 
			
		||||
        @parser = OptionParser.new
 | 
			
		||||
        @argv = argv
 | 
			
		||||
        @args = Homebrew::CLI::Args.new(@argv)
 | 
			
		||||
@ -359,11 +359,7 @@ module Homebrew
 | 
			
		||||
        named_args.map do |arg|
 | 
			
		||||
          next if arg.match?(HOMEBREW_CASK_TAP_CASK_REGEX)
 | 
			
		||||
 | 
			
		||||
          if arg.include?("/") || arg.end_with?(".tar.gz") || File.exist?(arg)
 | 
			
		||||
            Formulary.factory(arg, spec)
 | 
			
		||||
          else
 | 
			
		||||
            Formulary.find_with_priority(arg.downcase, spec)
 | 
			
		||||
          end
 | 
			
		||||
          Formulary.factory(arg, spec)
 | 
			
		||||
        end.compact.uniq(&:name)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -36,7 +36,6 @@ module Homebrew
 | 
			
		||||
    shell = if args.plain?
 | 
			
		||||
      nil
 | 
			
		||||
    elsif args.shell.nil?
 | 
			
		||||
      # legacy behavior
 | 
			
		||||
      :bash unless $stdout.tty?
 | 
			
		||||
    elsif args.shell == "auto"
 | 
			
		||||
      Utils::Shell.parent || Utils::Shell.preferred
 | 
			
		||||
 | 
			
		||||
@ -105,11 +105,7 @@ module Homebrew
 | 
			
		||||
      args.named.each_with_index do |f, i|
 | 
			
		||||
        puts unless i.zero?
 | 
			
		||||
        begin
 | 
			
		||||
          formula = if f.include?("/") || File.exist?(f)
 | 
			
		||||
            Formulary.factory(f)
 | 
			
		||||
          else
 | 
			
		||||
            Formulary.find_with_priority(f)
 | 
			
		||||
          end
 | 
			
		||||
          formula = Formulary.factory(f)
 | 
			
		||||
          if args.analytics?
 | 
			
		||||
            Utils::Analytics.formula_output(formula)
 | 
			
		||||
          else
 | 
			
		||||
 | 
			
		||||
@ -325,8 +325,8 @@ module Homebrew
 | 
			
		||||
    fi.build_bottle         = args.build_bottle?
 | 
			
		||||
    fi.interactive          = args.interactive?
 | 
			
		||||
    fi.git                  = args.git?
 | 
			
		||||
    fi.fetch
 | 
			
		||||
    fi.prelude
 | 
			
		||||
    fi.fetch
 | 
			
		||||
    fi.install
 | 
			
		||||
    fi.finish
 | 
			
		||||
  rescue FormulaInstallationAlreadyAttemptedError
 | 
			
		||||
 | 
			
		||||
@ -20,8 +20,8 @@ homebrew-shellenv() {
 | 
			
		||||
      echo "setenv HOMEBREW_CELLAR $HOMEBREW_CELLAR;"
 | 
			
		||||
      echo "setenv HOMEBREW_REPOSITORY $HOMEBREW_REPOSITORY;"
 | 
			
		||||
      echo "setenv PATH $HOMEBREW_PREFIX/bin:$HOMEBREW_PREFIX/sbin:\$PATH;"
 | 
			
		||||
      echo "setenv MANPATH $HOMEBREW_PREFIX/share/man:\$MANPATH;"
 | 
			
		||||
      echo "setenv INFOPATH $HOMEBREW_PREFIX/share/info:\$INFOPATH;"
 | 
			
		||||
      echo "setenv MANPATH $HOMEBREW_PREFIX/share/man\`[ \${?MANPATH} == 1 ] && echo \":\${MANPATH}\"\`:;"
 | 
			
		||||
      echo "setenv INFOPATH $HOMEBREW_PREFIX/share/info\`[ \${?INFOPATH} == 1 ] && echo \":\${INFOPATH}\"\`;"
 | 
			
		||||
      ;;
 | 
			
		||||
    *)
 | 
			
		||||
      echo "export HOMEBREW_PREFIX=\"$HOMEBREW_PREFIX\";"
 | 
			
		||||
 | 
			
		||||
@ -1,18 +0,0 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "cli/parser"
 | 
			
		||||
 | 
			
		||||
module Homebrew
 | 
			
		||||
  module_function
 | 
			
		||||
 | 
			
		||||
  def tap_pin_args
 | 
			
		||||
    Homebrew::CLI::Parser.new do
 | 
			
		||||
      hide_from_man_page!
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def tap_pin
 | 
			
		||||
    odisabled "the brew tap-pin command",
 | 
			
		||||
              "fully-scoped user/tap/formula naming when installing and in dependency references"
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -1,18 +0,0 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "cli/parser"
 | 
			
		||||
 | 
			
		||||
module Homebrew
 | 
			
		||||
  module_function
 | 
			
		||||
 | 
			
		||||
  def tap_unpin_args
 | 
			
		||||
    Homebrew::CLI::Parser.new do
 | 
			
		||||
      hide_from_man_page!
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def tap_unpin
 | 
			
		||||
    odisabled "the brew tap-unpin command",
 | 
			
		||||
              "fully-scoped user/tap/formula naming when installing and in dependency references"
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -599,7 +599,6 @@ EOS
 | 
			
		||||
        -d "$HOMEBREW_LIBRARY/LinkedKegs" ||
 | 
			
		||||
        (-n "$HOMEBREW_DEVELOPER" && -z "$HOMEBREW_UPDATE_PREINSTALL") ]]
 | 
			
		||||
  then
 | 
			
		||||
    unset HOMEBREW_RUBY_PATH
 | 
			
		||||
    brew update-report "$@"
 | 
			
		||||
    return $?
 | 
			
		||||
  elif [[ -z "$HOMEBREW_UPDATE_PREINSTALL" ]]
 | 
			
		||||
 | 
			
		||||
@ -191,8 +191,8 @@ module Homebrew
 | 
			
		||||
    end
 | 
			
		||||
    oh1 "Upgrading #{Formatter.identifier(f.full_specified_name)} #{upgrade_version} #{fi.options.to_a.join(" ")}"
 | 
			
		||||
 | 
			
		||||
    fi.fetch
 | 
			
		||||
    fi.prelude
 | 
			
		||||
    fi.fetch
 | 
			
		||||
 | 
			
		||||
    # 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
 | 
			
		||||
@ -216,7 +216,7 @@ module Homebrew
 | 
			
		||||
  ensure
 | 
			
		||||
    # restore previous installation state if build failed
 | 
			
		||||
    begin
 | 
			
		||||
      linked_kegs.each(&:link) unless f.installed?
 | 
			
		||||
      linked_kegs.each(&:link) unless f.latest_version_installed?
 | 
			
		||||
    rescue
 | 
			
		||||
      nil
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -101,7 +101,7 @@ module Commands
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def official_external_commands_paths
 | 
			
		||||
    %w[bundle services].map do |cmd|
 | 
			
		||||
    %w[bundle services test-bot].map do |cmd|
 | 
			
		||||
      tap = Tap.fetch("Homebrew/#{cmd}")
 | 
			
		||||
      tap.install unless tap.installed?
 | 
			
		||||
      external_ruby_v2_cmd_path(cmd)
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "compat/cask/dsl/version"
 | 
			
		||||
require "compat/language/python"
 | 
			
		||||
require "compat/requirements/macos_requirement"
 | 
			
		||||
require "compat/extend/nil"
 | 
			
		||||
require "compat/extend/string"
 | 
			
		||||
require "compat/formula"
 | 
			
		||||
require "compat/language/python"
 | 
			
		||||
require "compat/os/mac" if OS.mac?
 | 
			
		||||
 | 
			
		||||
@ -1,23 +0,0 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  class DSL
 | 
			
		||||
    class Version < ::String
 | 
			
		||||
      module Compat
 | 
			
		||||
        def dots_to_slashes
 | 
			
		||||
          odisabled "#dots_to_slashes"
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        def hyphens_to_slashes
 | 
			
		||||
          odisabled "#hyphens_to_slashes"
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        def underscores_to_slashes
 | 
			
		||||
          odisabled "#underscores_to_slashes"
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      prepend Compat
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										11
									
								
								Library/Homebrew/compat/extend/nil.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Library/Homebrew/compat/extend/nil.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class NilClass
 | 
			
		||||
  module Compat
 | 
			
		||||
    def chuzzle
 | 
			
		||||
      odeprecated "chuzzle", "chomp.presence"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  prepend Compat
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										15
									
								
								Library/Homebrew/compat/extend/string.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Library/Homebrew/compat/extend/string.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class String
 | 
			
		||||
  module Compat
 | 
			
		||||
    # String.chomp, but if result is empty: returns nil instead.
 | 
			
		||||
    # Allows `chuzzle || foo` short-circuits.
 | 
			
		||||
    def chuzzle
 | 
			
		||||
      odeprecated "chuzzle", "chomp.presence"
 | 
			
		||||
      s = chomp
 | 
			
		||||
      s unless s.empty?
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  prepend Compat
 | 
			
		||||
end
 | 
			
		||||
@ -3,10 +3,19 @@
 | 
			
		||||
class Formula
 | 
			
		||||
  module Compat
 | 
			
		||||
    def installed?
 | 
			
		||||
      # odeprecated "Formula#installed?",
 | 
			
		||||
      #             "Formula#latest_version_installed? (or Formula#any_version_installed? )"
 | 
			
		||||
      odeprecated "Formula#installed?",
 | 
			
		||||
                  "Formula#latest_version_installed? (or Formula#any_version_installed? )"
 | 
			
		||||
      latest_version_installed?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def prepare_patches
 | 
			
		||||
      if respond_to?(:patches)
 | 
			
		||||
        active_spec.add_legacy_patches(patches)
 | 
			
		||||
        odeprecated "patches", "patch do"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      super
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  prepend Compat
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ module Language
 | 
			
		||||
    module Cabal
 | 
			
		||||
      module Compat
 | 
			
		||||
        def cabal_sandbox(options = {})
 | 
			
		||||
          # odeprecated "Language::Haskell::Cabal.cabal_sandbox"
 | 
			
		||||
          odeprecated "Language::Haskell::Cabal.cabal_sandbox"
 | 
			
		||||
 | 
			
		||||
          pwd = Pathname.pwd
 | 
			
		||||
          home = options[:home] || pwd
 | 
			
		||||
@ -41,14 +41,14 @@ module Language
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        def cabal_sandbox_add_source(*args)
 | 
			
		||||
          # odeprecated "Language::Haskell::Cabal.cabal_sandbox_add_source"
 | 
			
		||||
          odeprecated "Language::Haskell::Cabal.cabal_sandbox_add_source"
 | 
			
		||||
 | 
			
		||||
          system "cabal", "v1-sandbox", "add-source", *args
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        def cabal_install(*args)
 | 
			
		||||
          # odeprecated "Language::Haskell::Cabal.cabal_install",
 | 
			
		||||
          #             "cabal v2-install directly with std_cabal_v2_args"
 | 
			
		||||
          odeprecated "Language::Haskell::Cabal.cabal_install",
 | 
			
		||||
                      "cabal v2-install directly with std_cabal_v2_args"
 | 
			
		||||
 | 
			
		||||
          # cabal hardcodes 64 as the maximum number of parallel jobs
 | 
			
		||||
          # https://github.com/Homebrew/legacy-homebrew/issues/49509
 | 
			
		||||
@ -64,13 +64,13 @@ module Language
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        def cabal_configure(flags)
 | 
			
		||||
          # odeprecated "Language::Haskell::Cabal.cabal_configure"
 | 
			
		||||
          odeprecated "Language::Haskell::Cabal.cabal_configure"
 | 
			
		||||
 | 
			
		||||
          system "cabal", "v1-configure", flags
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        def cabal_install_tools(*tools)
 | 
			
		||||
          # odeprecated "Language::Haskell::Cabal.cabal_install_tools"
 | 
			
		||||
          odeprecated "Language::Haskell::Cabal.cabal_install_tools"
 | 
			
		||||
 | 
			
		||||
          # install tools sequentially, as some tools can depend on other tools
 | 
			
		||||
          tools.each { |tool| cabal_install tool }
 | 
			
		||||
@ -81,8 +81,8 @@ module Language
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        def install_cabal_package(*args, **options)
 | 
			
		||||
          # odeprecated "Language::Haskell::Cabal.install_cabal_package",
 | 
			
		||||
          #             "cabal v2-update directly followed by v2-install with std_cabal_v2_args"
 | 
			
		||||
          odeprecated "Language::Haskell::Cabal.install_cabal_package",
 | 
			
		||||
                      "cabal v2-update directly followed by v2-install with std_cabal_v2_args"
 | 
			
		||||
 | 
			
		||||
          cabal_sandbox do
 | 
			
		||||
            cabal_install_tools(*options[:using]) if options[:using]
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,8 @@ module Language
 | 
			
		||||
    class << self
 | 
			
		||||
      module Compat
 | 
			
		||||
        def rewrite_python_shebang(python_path)
 | 
			
		||||
          odeprecated "Language::Python.rewrite_python_shebang",
 | 
			
		||||
                      "Utils::Shebang.rewrite_shebang and Shebang.python_shebang_rewrite_info(python_path)"
 | 
			
		||||
          Pathname.pwd.find do |f|
 | 
			
		||||
            Utils::Shebang.rewrite_shebang(Shebang.python_shebang_rewrite_info(python_path), f)
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ module OS
 | 
			
		||||
    class << self
 | 
			
		||||
      module Compat
 | 
			
		||||
        def preferred_arch
 | 
			
		||||
          # odeprecated "MacOS.preferred_arch", "Hardware::CPU.arch (or ideally let the compiler handle it)"
 | 
			
		||||
          odeprecated "MacOS.preferred_arch", "Hardware::CPU.arch (or ideally let the compiler handle it)"
 | 
			
		||||
          if Hardware::CPU.is_64_bit?
 | 
			
		||||
            Hardware::CPU.arch_64_bit
 | 
			
		||||
          else
 | 
			
		||||
@ -14,12 +14,12 @@ module OS
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        def tcc_db
 | 
			
		||||
          # odeprecated "MacOS.tcc_db"
 | 
			
		||||
          odeprecated "MacOS.tcc_db"
 | 
			
		||||
          @tcc_db ||= Pathname.new("/Library/Application Support/com.apple.TCC/TCC.db")
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        def pre_mavericks_accessibility_dotfile
 | 
			
		||||
          # odeprecated "MacOS.pre_mavericks_accessibility_dotfile"
 | 
			
		||||
          odeprecated "MacOS.pre_mavericks_accessibility_dotfile"
 | 
			
		||||
          @pre_mavericks_accessibility_dotfile ||= Pathname.new("/private/var/db/.AccessibilityAPIEnabled")
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -1,35 +0,0 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class MacOSRequirement < Requirement
 | 
			
		||||
  module Compat
 | 
			
		||||
    def initialize(tags = [], comparator: ">=")
 | 
			
		||||
      if tags.first.respond_to?(:map)
 | 
			
		||||
        versions, *rest = tags
 | 
			
		||||
 | 
			
		||||
        versions = versions.map do |v|
 | 
			
		||||
          next v if v.is_a?(Symbol)
 | 
			
		||||
 | 
			
		||||
          sym = MacOS::Version.new(v).to_sym
 | 
			
		||||
 | 
			
		||||
          odisabled "depends_on macos: #{v.inspect}",
 | 
			
		||||
                    "depends_on macos: #{sym.inspect}"
 | 
			
		||||
          sym
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        tags = [versions, *rest]
 | 
			
		||||
      elsif !tags.empty? && !tags.first.is_a?(Symbol)
 | 
			
		||||
        v, *rest = tags
 | 
			
		||||
        sym = MacOS::Version.new(v).to_sym
 | 
			
		||||
 | 
			
		||||
        odisabled "depends_on macos: #{v.inspect}",
 | 
			
		||||
                  "depends_on macos: #{sym.inspect}"
 | 
			
		||||
 | 
			
		||||
        tags = [sym, *rest]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      super(tags, comparator: comparator)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  prepend Compat
 | 
			
		||||
end
 | 
			
		||||
@ -100,16 +100,11 @@ module Homebrew
 | 
			
		||||
        klass.prune if ignores.include?("recommended?") || dependent.build.without?(dep)
 | 
			
		||||
      elsif dep.optional?
 | 
			
		||||
        klass.prune if !includes.include?("optional?") && !dependent.build.with?(dep)
 | 
			
		||||
      elsif dep.test?
 | 
			
		||||
        if includes.include?("test?")
 | 
			
		||||
          Dependency.keep_but_prune_recursive_deps if type == :dependencies
 | 
			
		||||
        elsif dep.build?
 | 
			
		||||
          klass.prune unless includes.include?("build?")
 | 
			
		||||
        else
 | 
			
		||||
          klass.prune
 | 
			
		||||
        end
 | 
			
		||||
      elsif dep.build?
 | 
			
		||||
        klass.prune unless includes.include?("build?")
 | 
			
		||||
      elsif dep.build? || dep.test?
 | 
			
		||||
        keep = false
 | 
			
		||||
        keep ||= dep.test? && includes.include?("test?") && dependent == formula
 | 
			
		||||
        keep ||= dep.build? && includes.include?("build?")
 | 
			
		||||
        klass.prune unless keep
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # If a tap isn't installed, we can't find the dependencies of one of
 | 
			
		||||
 | 
			
		||||
@ -89,9 +89,6 @@ class Dependency
 | 
			
		||||
      deps.each do |dep|
 | 
			
		||||
        next if dependent.name == dep.name
 | 
			
		||||
 | 
			
		||||
        # we only care about one level of test dependencies.
 | 
			
		||||
        next if dep.test? && @expand_stack.length > 1
 | 
			
		||||
 | 
			
		||||
        case action(dependent, dep, &block)
 | 
			
		||||
        when :prune
 | 
			
		||||
          next
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
require "formula"
 | 
			
		||||
require "formula_versions"
 | 
			
		||||
require "utils/curl"
 | 
			
		||||
require "utils/notability"
 | 
			
		||||
require "extend/ENV"
 | 
			
		||||
require "formula_cellar_checks"
 | 
			
		||||
require "cmd/search"
 | 
			
		||||
@ -134,19 +135,8 @@ module Homebrew
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    created_pr_comment = false
 | 
			
		||||
    if new_formula && !new_formula_problem_lines.empty?
 | 
			
		||||
      begin
 | 
			
		||||
        created_pr_comment = true if GitHub.create_issue_comment(new_formula_problem_lines.join("\n"))
 | 
			
		||||
      rescue *GitHub.api_errors => e
 | 
			
		||||
        opoo "Unable to create issue comment: #{e.message}"
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    unless created_pr_comment
 | 
			
		||||
      new_formula_problem_count += new_formula_problem_lines.size
 | 
			
		||||
      puts new_formula_problem_lines.map { |s| "  #{s}" }
 | 
			
		||||
    end
 | 
			
		||||
    new_formula_problem_count += new_formula_problem_lines.size
 | 
			
		||||
    puts new_formula_problem_lines.map { |s| "  #{s}" }
 | 
			
		||||
 | 
			
		||||
    total_problems_count = problem_count + new_formula_problem_count
 | 
			
		||||
    problem_plural = "#{total_problems_count} #{"problem".pluralize(total_problems_count)}"
 | 
			
		||||
@ -155,10 +145,7 @@ module Homebrew
 | 
			
		||||
    errors_summary = "#{problem_plural} in #{formula_plural} detected"
 | 
			
		||||
    errors_summary += ", #{corrected_problem_plural} corrected" if corrected_problem_count.positive?
 | 
			
		||||
 | 
			
		||||
    if problem_count.positive? ||
 | 
			
		||||
       (new_formula_problem_count.positive? && !created_pr_comment)
 | 
			
		||||
      ofail errors_summary
 | 
			
		||||
    end
 | 
			
		||||
    ofail errors_summary if problem_count.positive? || new_formula_problem_count.positive?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def format_problem_lines(problems)
 | 
			
		||||
@ -458,9 +445,10 @@ module Homebrew
 | 
			
		||||
      autoconf@2.13
 | 
			
		||||
      bash-completion@2
 | 
			
		||||
      gnupg@1.4
 | 
			
		||||
      libsigc++@2
 | 
			
		||||
      lua@5.1
 | 
			
		||||
      numpy@1.16
 | 
			
		||||
      libsigc++@2
 | 
			
		||||
      python@3.8
 | 
			
		||||
    ].freeze
 | 
			
		||||
 | 
			
		||||
    def audit_versioned_keg_only
 | 
			
		||||
@ -524,79 +512,30 @@ module Homebrew
 | 
			
		||||
      user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*})
 | 
			
		||||
      return if user.nil?
 | 
			
		||||
 | 
			
		||||
      begin
 | 
			
		||||
        metadata = GitHub.repository(user, repo)
 | 
			
		||||
      rescue GitHub::HTTPNotFoundError
 | 
			
		||||
        return
 | 
			
		||||
      end
 | 
			
		||||
      warning = SharedAudits.github(user, repo)
 | 
			
		||||
      return if warning.nil?
 | 
			
		||||
 | 
			
		||||
      return if metadata.nil?
 | 
			
		||||
 | 
			
		||||
      new_formula_problem "GitHub fork (not canonical repository)" if metadata["fork"]
 | 
			
		||||
      if (metadata["forks_count"] < 30) && (metadata["subscribers_count"] < 30) &&
 | 
			
		||||
         (metadata["stargazers_count"] < 75)
 | 
			
		||||
        new_formula_problem "GitHub repository not notable enough (<30 forks, <30 watchers and <75 stars)"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      return if Date.parse(metadata["created_at"]) <= (Date.today - 30)
 | 
			
		||||
 | 
			
		||||
      new_formula_problem "GitHub repository too new (<30 days old)"
 | 
			
		||||
      new_formula_problem warning
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def audit_gitlab_repository
 | 
			
		||||
      user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*})
 | 
			
		||||
      return if user.nil?
 | 
			
		||||
 | 
			
		||||
      out, _, status= curl_output("--request", "GET", "https://gitlab.com/api/v4/projects/#{user}%2F#{repo}")
 | 
			
		||||
      return unless status.success?
 | 
			
		||||
      warning = SharedAudits.gitlab(user, repo)
 | 
			
		||||
      return if warning.nil?
 | 
			
		||||
 | 
			
		||||
      metadata = JSON.parse(out)
 | 
			
		||||
      return if metadata.nil?
 | 
			
		||||
 | 
			
		||||
      new_formula_problem "GitLab fork (not canonical repository)" if metadata["fork"]
 | 
			
		||||
      if (metadata["forks_count"] < 30) && (metadata["star_count"] < 75)
 | 
			
		||||
        new_formula_problem "GitLab repository not notable enough (<30 forks and <75 stars)"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      return if Date.parse(metadata["created_at"]) <= (Date.today - 30)
 | 
			
		||||
 | 
			
		||||
      new_formula_problem "GitLab repository too new (<30 days old)"
 | 
			
		||||
      new_formula_problem warning
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def audit_bitbucket_repository
 | 
			
		||||
      user, repo = get_repo_data(%r{https?://bitbucket\.org/([^/]+)/([^/]+)/?.*})
 | 
			
		||||
      return if user.nil?
 | 
			
		||||
 | 
			
		||||
      api_url = "https://api.bitbucket.org/2.0/repositories/#{user}/#{repo}"
 | 
			
		||||
      out, _, status= curl_output("--request", "GET", api_url)
 | 
			
		||||
      return unless status.success?
 | 
			
		||||
      warning = SharedAudits.bitbucket(user, repo)
 | 
			
		||||
      return if warning.nil?
 | 
			
		||||
 | 
			
		||||
      metadata = JSON.parse(out)
 | 
			
		||||
      return if metadata.nil?
 | 
			
		||||
 | 
			
		||||
      new_formula_problem "Uses deprecated mercurial support in Bitbucket" if metadata["scm"] == "hg"
 | 
			
		||||
 | 
			
		||||
      new_formula_problem "Bitbucket fork (not canonical repository)" unless metadata["parent"].nil?
 | 
			
		||||
 | 
			
		||||
      if Date.parse(metadata["created_on"]) >= (Date.today - 30)
 | 
			
		||||
        new_formula_problem "Bitbucket repository too new (<30 days old)"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      forks_out, _, forks_status= curl_output("--request", "GET", "#{api_url}/forks")
 | 
			
		||||
      return unless forks_status.success?
 | 
			
		||||
 | 
			
		||||
      watcher_out, _, watcher_status= curl_output("--request", "GET", "#{api_url}/watchers")
 | 
			
		||||
      return unless watcher_status.success?
 | 
			
		||||
 | 
			
		||||
      forks_metadata = JSON.parse(forks_out)
 | 
			
		||||
      return if forks_metadata.nil?
 | 
			
		||||
 | 
			
		||||
      watcher_metadata = JSON.parse(watcher_out)
 | 
			
		||||
      return if watcher_metadata.nil?
 | 
			
		||||
 | 
			
		||||
      return if (forks_metadata["size"] < 30) && (watcher_metadata["size"] < 75)
 | 
			
		||||
 | 
			
		||||
      new_formula_problem "Bitbucket repository not notable enough (<30 forks and <75 watchers)"
 | 
			
		||||
      new_formula_problem warning
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def get_repo_data(regex)
 | 
			
		||||
@ -608,7 +547,7 @@ module Homebrew
 | 
			
		||||
      _, user, repo = *regex.match(formula.homepage) unless user
 | 
			
		||||
      return if !user || !repo
 | 
			
		||||
 | 
			
		||||
      repo.gsub!(/.git$/, "")
 | 
			
		||||
      repo.delete_suffix!(".git")
 | 
			
		||||
 | 
			
		||||
      [user, repo]
 | 
			
		||||
    end
 | 
			
		||||
@ -730,7 +669,7 @@ module Homebrew
 | 
			
		||||
                                                       .map(&:to_i)
 | 
			
		||||
 | 
			
		||||
      case (url = stable.url)
 | 
			
		||||
      when /[\d\._-](alpha|beta|rc\d)/
 | 
			
		||||
      when /[\d._-](alpha|beta|rc\d)/
 | 
			
		||||
        matched = Regexp.last_match(1)
 | 
			
		||||
        version_prefix = stable_version_string.sub(/\d+$/, "")
 | 
			
		||||
        return if UNSTABLE_WHITELIST[formula.name] == version_prefix
 | 
			
		||||
@ -758,7 +697,7 @@ module Homebrew
 | 
			
		||||
                   .second
 | 
			
		||||
 | 
			
		||||
        begin
 | 
			
		||||
          if (release = GitHub.open_api("#{GitHub::API_URL}/repos/#{owner}/#{repo}/releases/tags/#{tag}"))
 | 
			
		||||
          if @online && (release = GitHub.open_api("#{GitHub::API_URL}/repos/#{owner}/#{repo}/releases/tags/#{tag}"))
 | 
			
		||||
            problem "#{tag} is a GitHub prerelease" if release["prerelease"]
 | 
			
		||||
            problem "#{tag} is a GitHub draft" if release["draft"]
 | 
			
		||||
          end
 | 
			
		||||
@ -864,7 +803,7 @@ module Homebrew
 | 
			
		||||
      end
 | 
			
		||||
      bin_names.each do |name|
 | 
			
		||||
        ["system", "shell_output", "pipe_output"].each do |cmd|
 | 
			
		||||
          if text.to_s.match?(/test do.*#{cmd}[\(\s]+['"]#{Regexp.escape(name)}[\s'"]/m)
 | 
			
		||||
          if text.to_s.match?(/test do.*#{cmd}[(\s]+['"]#{Regexp.escape(name)}[\s'"]/m)
 | 
			
		||||
            problem %Q(fully scope test #{cmd} calls, e.g. #{cmd} "\#{bin}/#{name}")
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
@ -984,7 +923,7 @@ module Homebrew
 | 
			
		||||
      except_audits = @except
 | 
			
		||||
 | 
			
		||||
      methods.map(&:to_s).grep(/^audit_/).each do |audit_method_name|
 | 
			
		||||
        name = audit_method_name.gsub(/^audit_/, "")
 | 
			
		||||
        name = audit_method_name.delete_prefix("audit_")
 | 
			
		||||
        if only_audits
 | 
			
		||||
          next unless only_audits.include?(name)
 | 
			
		||||
        elsif except_audits
 | 
			
		||||
@ -1052,15 +991,9 @@ module Homebrew
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def audit_download_strategy
 | 
			
		||||
      if url =~ %r{^(cvs|bzr|hg|fossil)://} || url =~ %r{^(svn)\+http://}
 | 
			
		||||
        # TODO: check could be in RuboCop
 | 
			
		||||
        problem "Use of the #{$&} scheme is deprecated, pass `:using => :#{Regexp.last_match(1)}` instead"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      url_strategy = DownloadStrategyDetector.detect(url)
 | 
			
		||||
 | 
			
		||||
      if using == :git || url_strategy == GitDownloadStrategy
 | 
			
		||||
        # TODO: check could be in RuboCop
 | 
			
		||||
        problem "Git should specify :revision when a :tag is specified." if specs[:tag] && !specs[:revision]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -321,7 +321,7 @@ module Homebrew
 | 
			
		||||
        if any_go_deps
 | 
			
		||||
          go_regex =
 | 
			
		||||
            Version.formula_optionally_versioned_regex(:go, full: false)
 | 
			
		||||
          ignores << %r{#{Regexp.escape(HOMEBREW_CELLAR)}/#{go_regex}/[\d\.]+/libexec}
 | 
			
		||||
          ignores << %r{#{Regexp.escape(HOMEBREW_CELLAR)}/#{go_regex}/[\d.]+/libexec}
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        relocatable = true
 | 
			
		||||
 | 
			
		||||
@ -79,7 +79,7 @@ module Homebrew
 | 
			
		||||
      origin_branch = "#{homebrew_core_remote}/#{homebrew_core_branch}"
 | 
			
		||||
      previous_branch = Utils.popen_read("git -C \"#{formula.tap.path}\" symbolic-ref -q --short HEAD").chomp
 | 
			
		||||
      previous_branch = "master" if previous_branch.empty?
 | 
			
		||||
      formula_path = formula.path.to_s[%r{(Formula\/.*)}, 1]
 | 
			
		||||
      formula_path = formula.path.to_s[%r{(Formula/.*)}, 1]
 | 
			
		||||
 | 
			
		||||
      if args.dry_run?
 | 
			
		||||
        ohai "git remote add #{homebrew_core_remote} #{homebrew_core_url}"
 | 
			
		||||
@ -89,7 +89,7 @@ module Homebrew
 | 
			
		||||
        return tap_full_name, origin_branch, previous_branch
 | 
			
		||||
      else
 | 
			
		||||
        formula.path.parent.cd do
 | 
			
		||||
          unless Utils.popen_read("git remote -v").match?(%r{^homebrew.*Homebrew\/homebrew-core.*$})
 | 
			
		||||
          unless Utils.popen_read("git remote -v").match?(%r{^homebrew.*Homebrew/homebrew-core.*$})
 | 
			
		||||
            ohai "Adding #{homebrew_core_remote} remote"
 | 
			
		||||
            safe_system "git", "remote", "add", homebrew_core_remote, homebrew_core_url
 | 
			
		||||
          end
 | 
			
		||||
@ -118,12 +118,6 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
    formula = args.formulae.first
 | 
			
		||||
 | 
			
		||||
    if formula
 | 
			
		||||
      tap_full_name, origin_branch, previous_branch = use_correct_linux_tap(formula)
 | 
			
		||||
      check_for_duplicate_pull_requests(formula, tap_full_name)
 | 
			
		||||
      checked_for_duplicates = true
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    new_url = args.url
 | 
			
		||||
    if new_url && !formula
 | 
			
		||||
      # Split the new URL on / and find any formulae that have the same URL
 | 
			
		||||
@ -152,7 +146,8 @@ module Homebrew
 | 
			
		||||
    end
 | 
			
		||||
    raise FormulaUnspecifiedError unless formula
 | 
			
		||||
 | 
			
		||||
    check_for_duplicate_pull_requests(formula, tap_full_name) unless checked_for_duplicates
 | 
			
		||||
    tap_full_name, origin_branch, previous_branch = use_correct_linux_tap(formula)
 | 
			
		||||
    check_for_duplicate_pull_requests(formula, tap_full_name)
 | 
			
		||||
 | 
			
		||||
    requested_spec, formula_spec = if args.devel?
 | 
			
		||||
      devel_message = " (devel)"
 | 
			
		||||
@ -230,7 +225,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
    replacement_pairs += formula_spec.mirrors.map do |mirror|
 | 
			
		||||
      [
 | 
			
		||||
        / +mirror \"#{Regexp.escape(mirror)}\"\n/m,
 | 
			
		||||
        / +mirror "#{Regexp.escape(mirror)}"\n/m,
 | 
			
		||||
        "",
 | 
			
		||||
      ]
 | 
			
		||||
    end
 | 
			
		||||
@ -263,7 +258,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
    if new_mirrors
 | 
			
		||||
      replacement_pairs << [
 | 
			
		||||
        /^( +)(url \"#{Regexp.escape(new_url)}\"\n)/m,
 | 
			
		||||
        /^( +)(url "#{Regexp.escape(new_url)}"\n)/m,
 | 
			
		||||
        "\\1\\2\\1mirror \"#{new_mirrors.join("\"\n\\1mirror \"")}\"\n",
 | 
			
		||||
      ]
 | 
			
		||||
    end
 | 
			
		||||
@ -288,30 +283,30 @@ module Homebrew
 | 
			
		||||
          ]
 | 
			
		||||
        elsif new_mirrors
 | 
			
		||||
          [
 | 
			
		||||
            /^( +)(mirror \"#{Regexp.escape(new_mirrors.last)}\"\n)/m,
 | 
			
		||||
            /^( +)(mirror "#{Regexp.escape(new_mirrors.last)}"\n)/m,
 | 
			
		||||
            "\\1\\2\\1version \"#{forced_version}\"\n",
 | 
			
		||||
          ]
 | 
			
		||||
        else
 | 
			
		||||
          [
 | 
			
		||||
            /^( +)(url \"#{Regexp.escape(new_url)}\"\n)/m,
 | 
			
		||||
            /^( +)(url "#{Regexp.escape(new_url)}"\n)/m,
 | 
			
		||||
            "\\1\\2\\1version \"#{forced_version}\"\n",
 | 
			
		||||
          ]
 | 
			
		||||
        end
 | 
			
		||||
      elsif requested_spec == :devel
 | 
			
		||||
        replacement_pairs << [
 | 
			
		||||
          /(  devel do.+?version \")#{old_formula_version}(\"\n.+?end\n)/m,
 | 
			
		||||
          /(  devel do.+?version ")#{old_formula_version}("\n.+?end\n)/m,
 | 
			
		||||
          "\\1#{forced_version}\\2",
 | 
			
		||||
        ]
 | 
			
		||||
      end
 | 
			
		||||
    elsif forced_version && forced_version == "0"
 | 
			
		||||
      if requested_spec == :stable
 | 
			
		||||
        replacement_pairs << [
 | 
			
		||||
          /^  version \"[\w\.\-\+]+\"\n/m,
 | 
			
		||||
          /^  version "[\w.\-+]+"\n/m,
 | 
			
		||||
          "",
 | 
			
		||||
        ]
 | 
			
		||||
      elsif requested_spec == :devel
 | 
			
		||||
        replacement_pairs << [
 | 
			
		||||
          /(  devel do.+?)^ +version \"[^\n]+\"\n(.+?end\n)/m,
 | 
			
		||||
          /(  devel do.+?)^ +version "[^\n]+"\n(.+?end\n)/m,
 | 
			
		||||
          "\\1\\2",
 | 
			
		||||
        ]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
  def irb_args
 | 
			
		||||
    # work around IRB modifying ARGV.
 | 
			
		||||
    Homebrew::CLI::Parser.new(ARGV.dup) do
 | 
			
		||||
    Homebrew::CLI::Parser.new(ARGV.dup.freeze) do
 | 
			
		||||
      usage_banner <<~EOS
 | 
			
		||||
        `irb` [<options>]
 | 
			
		||||
 | 
			
		||||
@ -38,7 +38,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
    if args.examples?
 | 
			
		||||
      puts "'v8'.f # => instance of the v8 formula"
 | 
			
		||||
      puts ":hub.f.installed?"
 | 
			
		||||
      puts ":hub.f.latest_version_installed?"
 | 
			
		||||
      puts ":lua.f.methods - 1.methods"
 | 
			
		||||
      puts ":mpd.f.recursive_dependencies.reject(&:installed?)"
 | 
			
		||||
      return
 | 
			
		||||
 | 
			
		||||
@ -60,7 +60,7 @@ module Homebrew
 | 
			
		||||
    rescue FormulaUnavailableError
 | 
			
		||||
      nil
 | 
			
		||||
    else
 | 
			
		||||
      if gnupg.installed?
 | 
			
		||||
      if gnupg.any_version_installed?
 | 
			
		||||
        path = PATH.new(ENV.fetch("PATH"))
 | 
			
		||||
        path.prepend(gnupg.installed_prefix/"bin")
 | 
			
		||||
        ENV["PATH"] = path
 | 
			
		||||
 | 
			
		||||
@ -15,6 +15,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
  def pull_args
 | 
			
		||||
    Homebrew::CLI::Parser.new do
 | 
			
		||||
      hide_from_man_page!
 | 
			
		||||
      usage_banner <<~EOS
 | 
			
		||||
        `pull` [<options>] <patch>
 | 
			
		||||
 | 
			
		||||
@ -43,6 +44,8 @@ module Homebrew
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def pull
 | 
			
		||||
    odeprecated "brew pull", "hub checkout"
 | 
			
		||||
 | 
			
		||||
    odie "You meant `git pull --rebase`." if ARGV[0] == "--rebase"
 | 
			
		||||
 | 
			
		||||
    pull_args.parse
 | 
			
		||||
@ -56,7 +59,7 @@ module Homebrew
 | 
			
		||||
        gnupg = Formula["gnupg"]
 | 
			
		||||
      rescue FormulaUnavailableError # rubocop:disable Lint/SuppressedException
 | 
			
		||||
      else
 | 
			
		||||
        if gnupg.installed?
 | 
			
		||||
        if gnupg.any_version_installed?
 | 
			
		||||
          path = PATH.new(ENV.fetch("PATH"))
 | 
			
		||||
          path.prepend(gnupg.installed_prefix/"bin")
 | 
			
		||||
          ENV["PATH"] = path
 | 
			
		||||
@ -333,7 +336,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
  def check_bintray_mirror(name, url)
 | 
			
		||||
    headers, = curl_output("--connect-timeout", "15", "--location", "--head", url)
 | 
			
		||||
    status_code = headers.scan(%r{^HTTP\/.* (\d+)}).last.first
 | 
			
		||||
    status_code = headers.scan(%r{^HTTP/.* (\d+)}).last.first
 | 
			
		||||
    return if status_code.start_with?("2")
 | 
			
		||||
 | 
			
		||||
    opoo "The Bintray mirror #{url} is not reachable (HTTP status code #{status_code})."
 | 
			
		||||
 | 
			
		||||
@ -38,12 +38,6 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      Or `brew tap #{tap}` and then `brew install <formula>`.
 | 
			
		||||
 | 
			
		||||
      Or install via URL (which will not receive updates):
 | 
			
		||||
 | 
			
		||||
      ```
 | 
			
		||||
      brew install https://raw.githubusercontent.com/#{tap.user}/homebrew-#{tap.repo}/master/Formula/<formula>.rb
 | 
			
		||||
      ```
 | 
			
		||||
 | 
			
		||||
      ## Documentation
 | 
			
		||||
      `brew help`, `man brew` or check [Homebrew's documentation](https://docs.brew.sh).
 | 
			
		||||
    MARKDOWN
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
require "keg"
 | 
			
		||||
require "language/python"
 | 
			
		||||
require "formula"
 | 
			
		||||
require "formulary"
 | 
			
		||||
require "version"
 | 
			
		||||
require "development_tools"
 | 
			
		||||
require "utils/shell"
 | 
			
		||||
@ -832,6 +833,23 @@ module Homebrew
 | 
			
		||||
        EOS
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def check_deleted_formula
 | 
			
		||||
        kegs = Keg.all
 | 
			
		||||
        deleted_formulae = []
 | 
			
		||||
        kegs.each do |keg|
 | 
			
		||||
          keg_name = keg.name
 | 
			
		||||
          deleted_formulae << keg_name if Formulary.tap_paths(keg_name).blank?
 | 
			
		||||
        end
 | 
			
		||||
        return if deleted_formulae.blank?
 | 
			
		||||
 | 
			
		||||
        message = <<~EOS
 | 
			
		||||
          Some installed formulae were deleted!
 | 
			
		||||
          You should find replacements for the following formulae:
 | 
			
		||||
            #{deleted_formulae.join("\n  ")}
 | 
			
		||||
        EOS
 | 
			
		||||
        message
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def all
 | 
			
		||||
        methods.map(&:to_s).grep(/^check_/)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -221,7 +221,7 @@ class AbstractFileDownloadStrategy < AbstractDownloadStrategy
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def basename
 | 
			
		||||
    cached_location.basename.sub(/^[\da-f]{64}\-\-/, "")
 | 
			
		||||
    cached_location.basename.sub(/^[\da-f]{64}--/, "")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
@ -390,7 +390,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
 | 
			
		||||
    filenames = lines.map(&parse_content_disposition).compact
 | 
			
		||||
 | 
			
		||||
    time =
 | 
			
		||||
      lines.map { |line| line[/^Last\-Modified:\s*(.+)/i, 1] }
 | 
			
		||||
      lines.map { |line| line[/^Last-Modified:\s*(.+)/i, 1] }
 | 
			
		||||
           .compact
 | 
			
		||||
           .map { |t| t.match?(/^\d+$/) ? Time.at(t.to_i) : Time.parse(t) }
 | 
			
		||||
           .last
 | 
			
		||||
@ -820,7 +820,7 @@ class GitHubGitDownloadStrategy < GitDownloadStrategy
 | 
			
		||||
 | 
			
		||||
    return unless status.success?
 | 
			
		||||
 | 
			
		||||
    commit = output[/^ETag: \"(\h+)\"/, 1]
 | 
			
		||||
    commit = output[/^ETag: "(\h+)"/, 1]
 | 
			
		||||
    version.update_commit(commit) if commit
 | 
			
		||||
    commit
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -1,63 +0,0 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module HomebrewArgvExtension
 | 
			
		||||
  def value(name)
 | 
			
		||||
    arg_prefix = "--#{name}="
 | 
			
		||||
    flag_with_value = find { |arg| arg.start_with?(arg_prefix) }
 | 
			
		||||
    flag_with_value&.delete_prefix(arg_prefix)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def debug?
 | 
			
		||||
    flag?("--debug") || !ENV["HOMEBREW_DEBUG"].nil?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def cc
 | 
			
		||||
    value "cc"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def env
 | 
			
		||||
    value "env"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def options_only
 | 
			
		||||
    select { |arg| arg.start_with?("-") }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def flag?(flag)
 | 
			
		||||
    options_only.include?(flag) || switch?(flag[2, 1])
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # e.g. `foo -ns -i --bar` has three switches: `n`, `s` and `i`
 | 
			
		||||
  def switch?(char)
 | 
			
		||||
    return false if char.length > 1
 | 
			
		||||
 | 
			
		||||
    options_only.any? { |arg| arg.scan("-").size == 1 && arg.include?(char) }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def spec(default = :stable)
 | 
			
		||||
    if include?("--HEAD")
 | 
			
		||||
      :head
 | 
			
		||||
    elsif include?("--devel")
 | 
			
		||||
      :devel
 | 
			
		||||
    else
 | 
			
		||||
      default
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def named
 | 
			
		||||
    self - options_only
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def downcased_unique_named
 | 
			
		||||
    # Only lowercase names, not paths, bottle filenames or URLs
 | 
			
		||||
    named.map do |arg|
 | 
			
		||||
      if arg.include?("/") || arg.end_with?(".tar.gz") || File.exist?(arg)
 | 
			
		||||
        arg
 | 
			
		||||
      else
 | 
			
		||||
        arg.downcase
 | 
			
		||||
      end
 | 
			
		||||
    end.uniq
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -6,7 +6,7 @@ require "extend/ENV/std"
 | 
			
		||||
require "extend/ENV/super"
 | 
			
		||||
 | 
			
		||||
def superenv?
 | 
			
		||||
  ARGV.env != "std" && Superenv.bin
 | 
			
		||||
  Homebrew.args.env != "std" && Superenv.bin
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
module EnvActivation
 | 
			
		||||
 | 
			
		||||
@ -162,7 +162,7 @@ module SharedEnvExtension
 | 
			
		||||
  #   ENV.append_to_cflags "-I ./missing/includes"
 | 
			
		||||
  # end</pre>
 | 
			
		||||
  def compiler
 | 
			
		||||
    @compiler ||= if (cc = ARGV.cc)
 | 
			
		||||
    @compiler ||= if (cc = Homebrew.args.cc)
 | 
			
		||||
      warn_about_non_apple_gcc($&) if cc =~ GNU_GCC_REGEXP
 | 
			
		||||
      fetch_compiler(cc, "--cc")
 | 
			
		||||
    elsif (cc = homebrew_cc)
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,8 @@ class Keg
 | 
			
		||||
    return if !file.elf? || !file.dynamic_elf?
 | 
			
		||||
 | 
			
		||||
    patchelf = DevelopmentTools.locate "patchelf"
 | 
			
		||||
    odie "Could not locate patchelf, please: brew install patchelf." if patchelf.nil?
 | 
			
		||||
 | 
			
		||||
    cmd_rpath = [patchelf, "--print-rpath", file]
 | 
			
		||||
    old_rpath = Utils.popen_read(*cmd_rpath, err: :out).strip
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -347,12 +347,13 @@ module Homebrew
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def check_deprecated_caskroom_taps
 | 
			
		||||
        tapped_caskroom_taps = Tap.select { |t| t.user == "caskroom" }.map(&:repo)
 | 
			
		||||
        tapped_caskroom_taps = Tap.select { |t| t.user == "caskroom" || t.name == "phinze/cask" }
 | 
			
		||||
                                  .map(&:name)
 | 
			
		||||
        return if tapped_caskroom_taps.empty?
 | 
			
		||||
 | 
			
		||||
        <<~EOS
 | 
			
		||||
          You have the following deprecated, cask taps tapped:
 | 
			
		||||
            Caskroom/homebrew-#{tapped_caskroom_taps.join("\n  Caskroom/homebrew-")}
 | 
			
		||||
            #{tapped_caskroom_taps.join("\n  ")}
 | 
			
		||||
          Untap them with `brew untap`.
 | 
			
		||||
        EOS
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -81,7 +81,7 @@ module Stdenv
 | 
			
		||||
    prepend "LDFLAGS", "-L#{HOMEBREW_PREFIX}/lib"
 | 
			
		||||
 | 
			
		||||
    sdk = formula ? MacOS.sdk_for_formula(formula, version) : MacOS.sdk(version)
 | 
			
		||||
    return if !MacOS.sdk_root_needed? && sdk.source != :xcode
 | 
			
		||||
    return if !MacOS.sdk_root_needed? && sdk&.source != :xcode
 | 
			
		||||
 | 
			
		||||
    sdk = sdk.path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -108,7 +108,7 @@ module Superenv
 | 
			
		||||
  # @private
 | 
			
		||||
  def setup_build_environment(formula = nil)
 | 
			
		||||
    sdk = formula ? MacOS.sdk_for_formula(formula) : MacOS.sdk
 | 
			
		||||
    if MacOS.sdk_root_needed? || sdk.source == :xcode
 | 
			
		||||
    if MacOS.sdk_root_needed? || sdk&.source == :xcode
 | 
			
		||||
      self["HOMEBREW_SDKROOT"] = sdk.path
 | 
			
		||||
      self["HOMEBREW_DEVELOPER_DIR"] = if sdk.source == :xcode
 | 
			
		||||
        MacOS::Xcode.prefix
 | 
			
		||||
 | 
			
		||||
@ -106,10 +106,12 @@ class Keg
 | 
			
		||||
      bad_name.sub(PREFIX_PLACEHOLDER, HOMEBREW_PREFIX)
 | 
			
		||||
    elsif bad_name.start_with? CELLAR_PLACEHOLDER
 | 
			
		||||
      bad_name.sub(CELLAR_PLACEHOLDER, HOMEBREW_CELLAR)
 | 
			
		||||
    elsif (file.dylib? || file.mach_o_bundle?) && (file.parent + bad_name).exist?
 | 
			
		||||
    elsif (file.dylib? || file.mach_o_bundle?) && (file.dirname/bad_name).exist?
 | 
			
		||||
      "@loader_path/#{bad_name}"
 | 
			
		||||
    elsif file.mach_o_executable? && (lib + bad_name).exist?
 | 
			
		||||
    elsif file.mach_o_executable? && (lib/bad_name).exist?
 | 
			
		||||
      "#{lib}/#{bad_name}"
 | 
			
		||||
    elsif file.mach_o_executable? && (libexec/"lib"/bad_name).exist?
 | 
			
		||||
      "#{libexec}/lib/#{bad_name}"
 | 
			
		||||
    elsif bad_name.start_with?("@rpath") && ENV["HOMEBREW_RELOCATE_METAVARS"]
 | 
			
		||||
      expand_rpath file, bad_name
 | 
			
		||||
    elsif (abs_name = find_dylib(bad_name)) && abs_name.exist?
 | 
			
		||||
 | 
			
		||||
@ -224,7 +224,7 @@ class Pathname
 | 
			
		||||
    return archive_ext if archive_ext
 | 
			
		||||
 | 
			
		||||
    # Don't treat version numbers as extname.
 | 
			
		||||
    return "" if basename.match?(/\b\d+\.\d+[^\.]*\Z/) && !basename.end_with?(".7z")
 | 
			
		||||
    return "" if basename.match?(/\b\d+\.\d+[^.]*\Z/) && !basename.end_with?(".7z")
 | 
			
		||||
 | 
			
		||||
    File.extname(basename)
 | 
			
		||||
  end
 | 
			
		||||
@ -398,15 +398,6 @@ class Pathname
 | 
			
		||||
    basename.to_s == ".DS_Store"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # https://bugs.ruby-lang.org/issues/9915
 | 
			
		||||
  if RUBY_VERSION == "2.0.0"
 | 
			
		||||
    prepend Module.new {
 | 
			
		||||
      def inspect
 | 
			
		||||
        super.force_encoding(@path.encoding)
 | 
			
		||||
      end
 | 
			
		||||
    }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def binary_executable?
 | 
			
		||||
    false
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -2,21 +2,6 @@
 | 
			
		||||
 | 
			
		||||
require "active_support/core_ext/object/blank"
 | 
			
		||||
 | 
			
		||||
class String
 | 
			
		||||
  # String.chomp, but if result is empty: returns nil instead.
 | 
			
		||||
  # Allows `chuzzle || foo` short-circuits.
 | 
			
		||||
  # TODO: Deprecate.
 | 
			
		||||
  def chuzzle
 | 
			
		||||
    s = chomp
 | 
			
		||||
    s unless s.empty?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class NilClass
 | 
			
		||||
  # TODO: Deprecate.
 | 
			
		||||
  def chuzzle; end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
# Used by the inreplace function (in `utils.rb`).
 | 
			
		||||
module StringInreplaceExtension
 | 
			
		||||
  attr_accessor :errors
 | 
			
		||||
@ -41,7 +26,7 @@ module StringInreplaceExtension
 | 
			
		||||
  # Looks for Makefile style variable definitions and replaces the
 | 
			
		||||
  # value with "new_value", or removes the definition entirely.
 | 
			
		||||
  def change_make_var!(flag, new_value)
 | 
			
		||||
    return if gsub!(/^#{Regexp.escape(flag)}[ \t]*[\\?\+\:\!]?=[ \t]*((?:.*\\\n)*.*)$/, "#{flag}=#{new_value}", false)
 | 
			
		||||
    return if gsub!(/^#{Regexp.escape(flag)}[ \t]*[\\?+:!]?=[ \t]*((?:.*\\\n)*.*)$/, "#{flag}=#{new_value}", false)
 | 
			
		||||
 | 
			
		||||
    errors << "expected to change #{flag.inspect} to #{new_value.inspect}"
 | 
			
		||||
  end
 | 
			
		||||
@ -50,7 +35,7 @@ module StringInreplaceExtension
 | 
			
		||||
  def remove_make_var!(flags)
 | 
			
		||||
    Array(flags).each do |flag|
 | 
			
		||||
      # Also remove trailing \n, if present.
 | 
			
		||||
      unless gsub!(/^#{Regexp.escape(flag)}[ \t]*[\\?\+\:\!]?=(?:.*\\\n)*.*$\n?/, "", false)
 | 
			
		||||
      unless gsub!(/^#{Regexp.escape(flag)}[ \t]*[\\?+:!]?=(?:.*\\\n)*.*$\n?/, "", false)
 | 
			
		||||
        errors << "expected to remove #{flag.inspect}"
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
@ -58,6 +43,6 @@ module StringInreplaceExtension
 | 
			
		||||
 | 
			
		||||
  # Finds the specified variable
 | 
			
		||||
  def get_make_var(flag)
 | 
			
		||||
    self[/^#{Regexp.escape(flag)}[ \t]*[\\?\+\:\!]?=[ \t]*((?:.*\\\n)*.*)$/, 1]
 | 
			
		||||
    self[/^#{Regexp.escape(flag)}[ \t]*[\\?+:!]?=[ \t]*((?:.*\\\n)*.*)$/, 1]
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -1172,7 +1172,7 @@ class Formula
 | 
			
		||||
      begin
 | 
			
		||||
        yield self, staging
 | 
			
		||||
      rescue
 | 
			
		||||
        staging.retain! if Homebrew.args.interactive? || ARGV.debug?
 | 
			
		||||
        staging.retain! if Homebrew.args.interactive? || Homebrew.args.debug?
 | 
			
		||||
        raise
 | 
			
		||||
      ensure
 | 
			
		||||
        cp Dir["config.log", "CMakeCache.txt"], logs
 | 
			
		||||
@ -1822,7 +1822,7 @@ class Formula
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      rescue Exception # rubocop:disable Lint/RescueException
 | 
			
		||||
        staging.retain! if ARGV.debug?
 | 
			
		||||
        staging.retain! if Homebrew.args.debug?
 | 
			
		||||
        raise
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
@ -2090,7 +2090,6 @@ class Formula
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def prepare_patches
 | 
			
		||||
    active_spec.add_legacy_patches(patches) if respond_to?(:patches)
 | 
			
		||||
    patchlist.grep(DATAPatch) { |p| p.path = path }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -2171,7 +2170,10 @@ class Formula
 | 
			
		||||
        raise "You cannot override Formula#brew in class #{name}"
 | 
			
		||||
      when :test
 | 
			
		||||
        define_method(:test_defined?) { true }
 | 
			
		||||
      when :patches
 | 
			
		||||
        odeprecated "a Formula#patches definition", "'patch do' block calls"
 | 
			
		||||
      when :options
 | 
			
		||||
        odeprecated "a Formula#options definition", "'option do' block calls"
 | 
			
		||||
        instance = allocate
 | 
			
		||||
 | 
			
		||||
        specs.each do |spec|
 | 
			
		||||
@ -2385,6 +2387,7 @@ class Formula
 | 
			
		||||
      @devel ||= SoftwareSpec.new
 | 
			
		||||
      return @devel unless block_given?
 | 
			
		||||
 | 
			
		||||
      odeprecated "'devel' blocks in formulae", "'head' blocks or @-versioned formulae"
 | 
			
		||||
      @devel.instance_eval(&block)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -2668,7 +2671,7 @@ class Formula
 | 
			
		||||
    #   regex /foo-(\d+(?:\.\d+)+)\.tar/
 | 
			
		||||
    # end</pre>
 | 
			
		||||
    def livecheck(&block)
 | 
			
		||||
      @livecheck ||= Livecheck.new
 | 
			
		||||
      @livecheck ||= Livecheck.new(self)
 | 
			
		||||
      return @livecheck unless block_given?
 | 
			
		||||
 | 
			
		||||
      @livecheckable = true
 | 
			
		||||
 | 
			
		||||
@ -59,7 +59,7 @@ class FormulaInstaller
 | 
			
		||||
    @git = false
 | 
			
		||||
    @verbose = Homebrew.args.verbose?
 | 
			
		||||
    @quiet = Homebrew.args.quiet?
 | 
			
		||||
    @debug = ARGV.debug?
 | 
			
		||||
    @debug = Homebrew.args.debug?
 | 
			
		||||
    @installed_as_dependency = false
 | 
			
		||||
    @installed_on_request = true
 | 
			
		||||
    @options = Options.new
 | 
			
		||||
@ -100,7 +100,7 @@ class FormulaInstaller
 | 
			
		||||
    return false if !formula.bottled? && !formula.local_bottle_path
 | 
			
		||||
    return true  if force_bottle?
 | 
			
		||||
    return false if build_from_source? || build_bottle? || interactive?
 | 
			
		||||
    return false if ARGV.cc
 | 
			
		||||
    return false if Homebrew.args.cc
 | 
			
		||||
    return false unless options.empty?
 | 
			
		||||
    return false if formula.bottle_disabled?
 | 
			
		||||
 | 
			
		||||
@ -141,7 +141,6 @@ class FormulaInstaller
 | 
			
		||||
  def prelude
 | 
			
		||||
    Tab.clear_cache
 | 
			
		||||
    verify_deps_exist unless ignore_deps?
 | 
			
		||||
    lock
 | 
			
		||||
    check_install_sanity
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -221,6 +220,8 @@ class FormulaInstaller
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def install
 | 
			
		||||
    lock
 | 
			
		||||
 | 
			
		||||
    start_time = Time.now
 | 
			
		||||
    if !formula.bottle_unneeded? && !pour_bottle? && DevelopmentTools.installed?
 | 
			
		||||
      Homebrew::Install.perform_build_from_source_checks
 | 
			
		||||
@ -417,7 +418,7 @@ class FormulaInstaller
 | 
			
		||||
 | 
			
		||||
    req_map.each_pair do |dependent, reqs|
 | 
			
		||||
      reqs.each do |req|
 | 
			
		||||
        next if dependent.installed? && req.name == "maximummacos"
 | 
			
		||||
        next if dependent.latest_version_installed? && req.name == "maximummacos"
 | 
			
		||||
 | 
			
		||||
        @requirement_messages << "#{dependent}: #{req.message}"
 | 
			
		||||
        fatals << req if req.fatal?
 | 
			
		||||
@ -453,13 +454,16 @@ class FormulaInstaller
 | 
			
		||||
        build = effective_build_options_for(dependent)
 | 
			
		||||
        install_bottle_for_dependent = install_bottle_for?(dependent, build)
 | 
			
		||||
 | 
			
		||||
        keep_build_test = false
 | 
			
		||||
        keep_build_test ||= runtime_requirements.include?(req)
 | 
			
		||||
        keep_build_test ||= req.test? && include_test? && dependent == f
 | 
			
		||||
        keep_build_test ||= req.build? && !install_bottle_for_dependent && !dependent.latest_version_installed?
 | 
			
		||||
 | 
			
		||||
        if req.prune_from_option?(build)
 | 
			
		||||
          Requirement.prune
 | 
			
		||||
        elsif req.satisfied?
 | 
			
		||||
          Requirement.prune
 | 
			
		||||
        elsif include_test? && req.test?
 | 
			
		||||
          next
 | 
			
		||||
        elsif !runtime_requirements.include?(req) && install_bottle_for_dependent
 | 
			
		||||
        elsif (req.build? || req.test?) && !keep_build_test
 | 
			
		||||
          Requirement.prune
 | 
			
		||||
        elsif (dep = formula_deps_map[dependent.name]) && dep.build?
 | 
			
		||||
          Requirement.prune
 | 
			
		||||
@ -486,13 +490,13 @@ class FormulaInstaller
 | 
			
		||||
        inherited_options.fetch(dependent.name, []),
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      keep_build_test = false
 | 
			
		||||
      keep_build_test ||= dep.test? && include_test? && Homebrew.args.include_formula_test_deps?(dependent)
 | 
			
		||||
      keep_build_test ||= dep.build? && !install_bottle_for?(dependent, build) && !dependent.latest_version_installed?
 | 
			
		||||
 | 
			
		||||
      if dep.prune_from_option?(build)
 | 
			
		||||
        Dependency.prune
 | 
			
		||||
      elsif dep.test? && !dep.build? && !include_test?
 | 
			
		||||
        Dependency.prune
 | 
			
		||||
      elsif dep.build? && !dep.test? && install_bottle_for?(dependent, build)
 | 
			
		||||
        Dependency.prune
 | 
			
		||||
      elsif dep.prune_if_build_and_not_dependent?(dependent)
 | 
			
		||||
      elsif (dep.build? || dep.test?) && !keep_build_test
 | 
			
		||||
        Dependency.prune
 | 
			
		||||
      elsif dep.satisfied?(inherited_options[dep.name])
 | 
			
		||||
        Dependency.skip
 | 
			
		||||
@ -568,6 +572,7 @@ class FormulaInstaller
 | 
			
		||||
 | 
			
		||||
    fi.build_from_source       = Homebrew.args.build_formula_from_source?(df)
 | 
			
		||||
    fi.force_bottle            = false
 | 
			
		||||
    fi.include_test            = Homebrew.args.include_formula_test_deps?(df)
 | 
			
		||||
    fi.verbose                 = verbose?
 | 
			
		||||
    fi.quiet                   = quiet?
 | 
			
		||||
    fi.debug                   = debug?
 | 
			
		||||
@ -589,7 +594,7 @@ class FormulaInstaller
 | 
			
		||||
      linked_keg.unlink
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if df.installed?
 | 
			
		||||
    if df.latest_version_installed?
 | 
			
		||||
      installed_keg = Keg.new(df.prefix)
 | 
			
		||||
      tmp_keg = Pathname.new("#{installed_keg}.tmp")
 | 
			
		||||
      installed_keg.rename(tmp_keg)
 | 
			
		||||
@ -610,6 +615,7 @@ class FormulaInstaller
 | 
			
		||||
    fi.options                &= df.options
 | 
			
		||||
    fi.build_from_source       = Homebrew.args.build_formula_from_source?(df)
 | 
			
		||||
    fi.force_bottle            = false
 | 
			
		||||
    fi.include_test            = Homebrew.args.include_formula_test_deps?(df)
 | 
			
		||||
    fi.verbose                 = verbose?
 | 
			
		||||
    fi.quiet                   = quiet?
 | 
			
		||||
    fi.debug                   = debug?
 | 
			
		||||
@ -723,11 +729,11 @@ class FormulaInstaller
 | 
			
		||||
    args << "--interactive" if interactive?
 | 
			
		||||
    args << "--verbose" if verbose?
 | 
			
		||||
    args << "--debug" if debug?
 | 
			
		||||
    args << "--cc=#{ARGV.cc}" if ARGV.cc
 | 
			
		||||
    args << "--cc=#{Homebrew.args.cc}" if Homebrew.args.cc
 | 
			
		||||
    args << "--keep-tmp" if Homebrew.args.keep_tmp?
 | 
			
		||||
 | 
			
		||||
    if ARGV.env
 | 
			
		||||
      args << "--env=#{ARGV.env}"
 | 
			
		||||
    if Homebrew.args.env.present?
 | 
			
		||||
      args << "--env=#{Homebrew.args.env}"
 | 
			
		||||
    elsif formula.env.std? || formula.deps.select(&:build?).any? { |d| d.name == "scons" }
 | 
			
		||||
      args << "--env=std"
 | 
			
		||||
    end
 | 
			
		||||
@ -740,7 +746,7 @@ class FormulaInstaller
 | 
			
		||||
 | 
			
		||||
    formula.options.each do |opt|
 | 
			
		||||
      name = opt.name[/^([^=]+)=$/, 1]
 | 
			
		||||
      value = ARGV.value(name) if name
 | 
			
		||||
      value = Homebrew.args.value(name) if name
 | 
			
		||||
      args << "--#{name}=#{value}" if value
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -964,9 +970,10 @@ class FormulaInstaller
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def fetch_dependencies
 | 
			
		||||
    deps = compute_dependencies
 | 
			
		||||
    return if ignore_deps?
 | 
			
		||||
 | 
			
		||||
    return if deps.empty? || ignore_deps?
 | 
			
		||||
    deps = compute_dependencies
 | 
			
		||||
    return if deps.empty?
 | 
			
		||||
 | 
			
		||||
    deps.each { |dep, _options| fetch_dependency(dep) }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -44,7 +44,7 @@ class FormulaVersions
 | 
			
		||||
  rescue *IGNORED_EXCEPTIONS => e
 | 
			
		||||
    # We rescue these so that we can skip bad versions and
 | 
			
		||||
    # continue walking the history
 | 
			
		||||
    odebug "#{e} in #{name} at revision #{rev}", e.backtrace if ARGV.debug?
 | 
			
		||||
    odebug "#{e} in #{name} at revision #{rev}", e.backtrace if Homebrew.args.debug?
 | 
			
		||||
  rescue FormulaUnavailableError
 | 
			
		||||
    nil
 | 
			
		||||
  ensure
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,8 @@ require "extend/cachable"
 | 
			
		||||
module Formulary
 | 
			
		||||
  extend Cachable
 | 
			
		||||
 | 
			
		||||
  URL_START_REGEX = %r{(https?|ftp|file)://}.freeze
 | 
			
		||||
 | 
			
		||||
  def self.enable_factory_cache!
 | 
			
		||||
    @factory_cache = true
 | 
			
		||||
  end
 | 
			
		||||
@ -130,7 +132,7 @@ module Formulary
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    def load_file
 | 
			
		||||
      $stderr.puts "#{$PROGRAM_NAME} (#{self.class.name}): loading #{path}" if ARGV.debug?
 | 
			
		||||
      $stderr.puts "#{$PROGRAM_NAME} (#{self.class.name}): loading #{path}" if Homebrew.args.debug?
 | 
			
		||||
      raise FormulaUnavailableError, name unless path.file?
 | 
			
		||||
 | 
			
		||||
      Formulary.load_formula_from_path(name, path)
 | 
			
		||||
@ -141,7 +143,7 @@ module Formulary
 | 
			
		||||
  class BottleLoader < FormulaLoader
 | 
			
		||||
    def initialize(bottle_name)
 | 
			
		||||
      case bottle_name
 | 
			
		||||
      when %r{(https?|ftp|file)://}
 | 
			
		||||
      when URL_START_REGEX
 | 
			
		||||
        # The name of the formula is found between the last slash and the last hyphen.
 | 
			
		||||
        formula_name = File.basename(bottle_name)[/(.+)-/, 1]
 | 
			
		||||
        resource = Resource.new(formula_name) { url bottle_name }
 | 
			
		||||
@ -205,21 +207,20 @@ module Formulary
 | 
			
		||||
    def load_file
 | 
			
		||||
      if url =~ %r{githubusercontent.com/[\w-]+/[\w-]+/[a-f0-9]{40}(/Formula)?/([\w+-.@]+).rb}
 | 
			
		||||
        formula_name = Regexp.last_match(2)
 | 
			
		||||
        opoo <<~EOS
 | 
			
		||||
          Unsupported installation from a commit URL!
 | 
			
		||||
          Consider using `brew extract #{formula_name} ...` instead!"
 | 
			
		||||
          This will extract your desired #{formula_name} version to a stable tap instead of
 | 
			
		||||
          installing from a commit URL that cannnot receive updates or fixes!
 | 
			
		||||
 | 
			
		||||
        EOS
 | 
			
		||||
        odeprecated "Installation of #{formula_name} from a GitHub commit URL",
 | 
			
		||||
                    "'brew extract #{formula_name}' to stable tap on GitHub"
 | 
			
		||||
      elsif url.match?(%r{^(https?|ftp)://})
 | 
			
		||||
        odeprecated "Non-checksummed download of #{name} formula file from an arbitrary URL",
 | 
			
		||||
                    "'brew extract' or 'brew create' and 'brew tap-new' to create a "\
 | 
			
		||||
                    "formula file in a tap on GitHub"
 | 
			
		||||
      end
 | 
			
		||||
      HOMEBREW_CACHE_FORMULA.mkpath
 | 
			
		||||
      FileUtils.rm_f(path)
 | 
			
		||||
      curl_download url, to: path
 | 
			
		||||
      super
 | 
			
		||||
    rescue MethodDeprecatedError => e
 | 
			
		||||
      if url =~ %r{github.com/([\w-]+)/homebrew-([\w-]+)/}
 | 
			
		||||
        e.issues_url = "https://github.com/#{Regexp.last_match(1)}/homebrew-#{Regexp.last_match(2)}/issues/new"
 | 
			
		||||
      if url =~ %r{github.com/([\w-]+)/([\w-]+)/}
 | 
			
		||||
        e.issues_url = "https://github.com/#{Regexp.last_match(1)}/#{Regexp.last_match(2)}/issues/new"
 | 
			
		||||
      end
 | 
			
		||||
      raise
 | 
			
		||||
    end
 | 
			
		||||
@ -307,7 +308,7 @@ module Formulary
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def klass
 | 
			
		||||
      $stderr.puts "#{$PROGRAM_NAME} (#{self.class.name}): loading #{path}" if ARGV.debug?
 | 
			
		||||
      $stderr.puts "#{$PROGRAM_NAME} (#{self.class.name}): loading #{path}" if Homebrew.args.debug?
 | 
			
		||||
      namespace = "FormulaNamespace#{Digest::MD5.hexdigest(contents)}"
 | 
			
		||||
      Formulary.load_formula(name, path, contents, namespace)
 | 
			
		||||
    end
 | 
			
		||||
@ -418,7 +419,7 @@ module Formulary
 | 
			
		||||
    case ref
 | 
			
		||||
    when Pathname::BOTTLE_EXTNAME_RX
 | 
			
		||||
      return BottleLoader.new(ref)
 | 
			
		||||
    when %r{(https?|ftp|file)://}
 | 
			
		||||
    when URL_START_REGEX
 | 
			
		||||
      return FromUrlLoader.new(ref)
 | 
			
		||||
    when HOMEBREW_TAP_FORMULA_REGEX
 | 
			
		||||
      return TapLoader.new(ref, from: from)
 | 
			
		||||
@ -483,20 +484,4 @@ module Formulary
 | 
			
		||||
                    ]).find(&:file?)
 | 
			
		||||
    end.compact
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def self.find_with_priority(ref, spec = :stable)
 | 
			
		||||
    possible_pinned_tap_formulae = tap_paths(ref, Dir["#{HOMEBREW_LIBRARY}/PinnedTaps/*/*/"]).map(&:realpath)
 | 
			
		||||
    raise TapFormulaAmbiguityError.new(ref, possible_pinned_tap_formulae) if possible_pinned_tap_formulae.size > 1
 | 
			
		||||
 | 
			
		||||
    if possible_pinned_tap_formulae.size == 1
 | 
			
		||||
      selected_formula = factory(possible_pinned_tap_formulae.first, spec)
 | 
			
		||||
      if core_path(ref).file?
 | 
			
		||||
        odisabled "the brew tap-pin command",
 | 
			
		||||
                  "fully-scoped user/tap/formula naming when installing and in dependency references"
 | 
			
		||||
      end
 | 
			
		||||
      selected_formula
 | 
			
		||||
    else
 | 
			
		||||
      factory(ref, spec)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -35,13 +35,10 @@ require "env_config"
 | 
			
		||||
 | 
			
		||||
require "config"
 | 
			
		||||
require "os"
 | 
			
		||||
require "extend/ARGV"
 | 
			
		||||
require "cli/args"
 | 
			
		||||
require "messages"
 | 
			
		||||
require "system_command"
 | 
			
		||||
 | 
			
		||||
ARGV.extend(HomebrewArgvExtension)
 | 
			
		||||
 | 
			
		||||
HOMEBREW_PRODUCT = ENV["HOMEBREW_PRODUCT"]
 | 
			
		||||
HOMEBREW_VERSION = ENV["HOMEBREW_VERSION"]
 | 
			
		||||
HOMEBREW_WWW = "https://brew.sh"
 | 
			
		||||
 | 
			
		||||
@ -103,7 +103,7 @@ module Homebrew
 | 
			
		||||
      help_lines = command_help_lines(path)
 | 
			
		||||
      return if help_lines.blank?
 | 
			
		||||
 | 
			
		||||
      Formatter.wrap(help_lines.join.gsub(/^  /, ""), COMMAND_DESC_WIDTH)
 | 
			
		||||
      Formatter.wrap(help_lines.join.delete_prefix("  "), COMMAND_DESC_WIDTH)
 | 
			
		||||
               .sub("@hide_from_man_page ", "")
 | 
			
		||||
               .sub(/^\* /, "#{Tty.bold}Usage: brew#{Tty.reset} ")
 | 
			
		||||
               .gsub(/`(.*?)`/m, "#{Tty.bold}\\1#{Tty.reset}")
 | 
			
		||||
 | 
			
		||||
@ -37,11 +37,11 @@ module Homebrew
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def check_cc_argv
 | 
			
		||||
      return unless ARGV.cc
 | 
			
		||||
      return unless Homebrew.args.cc
 | 
			
		||||
 | 
			
		||||
      @checks ||= Diagnostic::Checks.new
 | 
			
		||||
      opoo <<~EOS
 | 
			
		||||
        You passed `--cc=#{ARGV.cc}`.
 | 
			
		||||
        You passed `--cc=#{Homebrew.args.cc}`.
 | 
			
		||||
        #{@checks.please_create_pull_requests}
 | 
			
		||||
      EOS
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -117,6 +117,10 @@ class Keg
 | 
			
		||||
    path/"lib"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def libexec
 | 
			
		||||
    path/"libexec"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def text_files
 | 
			
		||||
    text_files = []
 | 
			
		||||
    return text_files unless which("file") && which("xargs")
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ module Language
 | 
			
		||||
        next if build.without? python_formula.to_s
 | 
			
		||||
 | 
			
		||||
        version = major_minor_version python
 | 
			
		||||
        ENV["PYTHONPATH"] = if python_formula.installed?
 | 
			
		||||
        ENV["PYTHONPATH"] = if python_formula.latest_version_installed?
 | 
			
		||||
          nil
 | 
			
		||||
        else
 | 
			
		||||
          homebrew_site_packages(python)
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,8 @@ class Livecheck
 | 
			
		||||
  # e.g. `Not maintained`
 | 
			
		||||
  attr_reader :skip_msg
 | 
			
		||||
 | 
			
		||||
  def initialize
 | 
			
		||||
  def initialize(formula)
 | 
			
		||||
    @formula = formula
 | 
			
		||||
    @regex = nil
 | 
			
		||||
    @skip = false
 | 
			
		||||
    @skip_msg = nil
 | 
			
		||||
@ -44,7 +45,14 @@ class Livecheck
 | 
			
		||||
  def url(val = nil)
 | 
			
		||||
    return @url if val.nil?
 | 
			
		||||
 | 
			
		||||
    @url = val
 | 
			
		||||
    @url = case val
 | 
			
		||||
    when :head, :stable, :devel
 | 
			
		||||
      @formula.send(val).url
 | 
			
		||||
    when :homepage
 | 
			
		||||
      @formula.homepage
 | 
			
		||||
    else
 | 
			
		||||
      val
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns a Hash of all instance variable values.
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@ class Locale
 | 
			
		||||
  REGION_REGEX   = /(?:[A-Z]{2}|\d{3})/.freeze # ISO 3166-1 or UN M.49
 | 
			
		||||
  SCRIPT_REGEX   = /(?:[A-Z][a-z]{3})/.freeze  # ISO 15924
 | 
			
		||||
 | 
			
		||||
  LOCALE_REGEX = /\A((?:#{LANGUAGE_REGEX}|#{REGION_REGEX}|#{SCRIPT_REGEX})(?:\-|$)){1,3}\Z/.freeze
 | 
			
		||||
  LOCALE_REGEX = /\A((?:#{LANGUAGE_REGEX}|#{REGION_REGEX}|#{SCRIPT_REGEX})(?:-|$)){1,3}\Z/.freeze
 | 
			
		||||
 | 
			
		||||
  def self.parse(string)
 | 
			
		||||
    string = string.to_s
 | 
			
		||||
@ -16,7 +16,7 @@ class Locale
 | 
			
		||||
    raise ParserError, "'#{string}' cannot be parsed to a #{self}" unless string.match?(LOCALE_REGEX)
 | 
			
		||||
 | 
			
		||||
    scan = proc do |regex|
 | 
			
		||||
      string.scan(/(?:\-|^)(#{regex})(?:\-|$)/).flatten.first
 | 
			
		||||
      string.scan(/(?:-|^)(#{regex})(?:-|$)/).flatten.first
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    language = scan.call(LANGUAGE_REGEX)
 | 
			
		||||
 | 
			
		||||
@ -97,11 +97,9 @@ can take several different forms:
 | 
			
		||||
    You can still access these formulae by using a special syntax, e.g.
 | 
			
		||||
    `homebrew/dupes/vim` or `homebrew/versions/node4`.
 | 
			
		||||
 | 
			
		||||
  * An arbitrary file or URL:
 | 
			
		||||
    Homebrew can install formulae via URL, e.g.
 | 
			
		||||
    `https://raw.githubusercontent.com/Homebrew/homebrew-core/master/Formula/git.rb`,
 | 
			
		||||
    or from a local path. It can point to either a formula file or a bottle.
 | 
			
		||||
    In the case of a URL, the downloaded file will be cached for later use.
 | 
			
		||||
  * An arbitrary file:
 | 
			
		||||
    Homebrew can install formulae from a local path. It can point to either a
 | 
			
		||||
    formula file or a bottle.
 | 
			
		||||
 | 
			
		||||
## ENVIRONMENT
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -209,7 +209,7 @@ class Migrator
 | 
			
		||||
  rescue Exception => e # rubocop:disable Lint/RescueException
 | 
			
		||||
    onoe "Error occurred while migrating."
 | 
			
		||||
    puts e
 | 
			
		||||
    puts e.backtrace if ARGV.debug?
 | 
			
		||||
    puts e.backtrace if Homebrew.args.debug?
 | 
			
		||||
    puts "Backing up..."
 | 
			
		||||
    ignore_interrupts { backup_oldname }
 | 
			
		||||
  ensure
 | 
			
		||||
@ -318,7 +318,7 @@ class Migrator
 | 
			
		||||
    rescue Exception => e # rubocop:disable Lint/RescueException
 | 
			
		||||
      onoe "An unexpected error occurred during linking"
 | 
			
		||||
      puts e
 | 
			
		||||
      puts e.backtrace if ARGV.debug?
 | 
			
		||||
      puts e.backtrace if Homebrew.args.debug?
 | 
			
		||||
      ignore_interrupts { new_keg.unlink }
 | 
			
		||||
      raise
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -42,11 +42,7 @@ module OS
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def languages
 | 
			
		||||
      @languages ||= [
 | 
			
		||||
        *ARGV.value("language")&.split(","),
 | 
			
		||||
        *ENV["HOMEBREW_LANGUAGES"]&.split(","),
 | 
			
		||||
        *ENV["LANG"]&.slice(/[a-z]+/),
 | 
			
		||||
      ].uniq
 | 
			
		||||
      @languages ||= [*ENV["LANG"]&.slice(/[a-z]+/)].uniq
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def language
 | 
			
		||||
 | 
			
		||||
@ -60,9 +60,11 @@ module OS
 | 
			
		||||
 | 
			
		||||
    def languages
 | 
			
		||||
      @languages ||= [
 | 
			
		||||
        *ARGV.value("language")&.split(","),
 | 
			
		||||
        *Homebrew.args.value("language")&.split(","),
 | 
			
		||||
        *ENV["HOMEBREW_LANGUAGES"]&.split(","),
 | 
			
		||||
        *Open3.capture2("defaults", "read", "-g", "AppleLanguages")[0].scan(/[^ \n"(),]+/),
 | 
			
		||||
        *Open3.capture2("defaults", "read", "-g", "AppleLanguages")
 | 
			
		||||
              .first
 | 
			
		||||
              .scan(/[^ \n"(),]+/),
 | 
			
		||||
      ].uniq
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ class Keg
 | 
			
		||||
    return if file.dylib_id == id
 | 
			
		||||
 | 
			
		||||
    @require_relocation = true
 | 
			
		||||
    odebug "Changing dylib ID of #{file}\n  from #{file.dylib_id}\n    to #{id}" if ARGV.debug?
 | 
			
		||||
    odebug "Changing dylib ID of #{file}\n  from #{file.dylib_id}\n    to #{id}" if Homebrew.args.debug?
 | 
			
		||||
    MachO::Tools.change_dylib_id(file, id, strict: false)
 | 
			
		||||
  rescue MachO::MachOError
 | 
			
		||||
    onoe <<~EOS
 | 
			
		||||
@ -20,7 +20,7 @@ class Keg
 | 
			
		||||
    return if old == new
 | 
			
		||||
 | 
			
		||||
    @require_relocation = true
 | 
			
		||||
    odebug "Changing install name in #{file}\n  from #{old}\n    to #{new}" if ARGV.debug?
 | 
			
		||||
    odebug "Changing install name in #{file}\n  from #{old}\n    to #{new}" if Homebrew.args.debug?
 | 
			
		||||
    MachO::Tools.change_install_name(file, old, new, strict: false)
 | 
			
		||||
  rescue MachO::MachOError
 | 
			
		||||
    onoe <<~EOS
 | 
			
		||||
 | 
			
		||||
@ -169,6 +169,7 @@ end
 | 
			
		||||
# Legacy patches have no checksum and are not cached.
 | 
			
		||||
class LegacyPatch < ExternalPatch
 | 
			
		||||
  def initialize(strip, url)
 | 
			
		||||
    odeprecated "legacy patches", "'patch do' blocks"
 | 
			
		||||
    super(strip)
 | 
			
		||||
    resource.url(url)
 | 
			
		||||
    resource.download_strategy = CurlDownloadStrategy
 | 
			
		||||
 | 
			
		||||
@ -35,8 +35,8 @@ module Homebrew
 | 
			
		||||
      fi.installed_as_dependency = tab.installed_as_dependency
 | 
			
		||||
      fi.installed_on_request    = tab.installed_on_request
 | 
			
		||||
    end
 | 
			
		||||
    fi.fetch
 | 
			
		||||
    fi.prelude
 | 
			
		||||
    fi.fetch
 | 
			
		||||
 | 
			
		||||
    oh1 "Reinstalling #{Formatter.identifier(f.full_name)} #{options.to_a.join " "}"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -111,7 +111,7 @@ class JavaRequirement < Requirement
 | 
			
		||||
    rescue FormulaUnavailableError
 | 
			
		||||
      nil
 | 
			
		||||
    end
 | 
			
		||||
    javas << jdk.bin/"java" if jdk&.installed?
 | 
			
		||||
    javas << jdk.bin/"java" if jdk&.latest_version_installed?
 | 
			
		||||
    javas << which("java")
 | 
			
		||||
    javas
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -72,7 +72,7 @@ class Resource
 | 
			
		||||
  # directory. Subclasses that override stage should implement the tmp
 | 
			
		||||
  # dir using {Mktemp} so that works with all subtypes.
 | 
			
		||||
  def stage(target = nil, &block)
 | 
			
		||||
    raise ArgumentError, "target directory or block is required" if target.blank? && block.blank?
 | 
			
		||||
    raise ArgumentError, "target directory or block is required" if !target && block.blank?
 | 
			
		||||
 | 
			
		||||
    prepare_patches
 | 
			
		||||
    fetch_patches(skip_downloaded: true)
 | 
			
		||||
 | 
			
		||||
@ -129,7 +129,7 @@ module RuboCop
 | 
			
		||||
          string = stanza.stanza_node.children[2]
 | 
			
		||||
          return string.str_content if string.str_type?
 | 
			
		||||
 | 
			
		||||
          string.to_s.gsub(%r{.*"([a-z0-9]+\:\/\/[^"]+)".*}m, '\1')
 | 
			
		||||
          string.to_s.gsub(%r{.*"([a-z0-9]+://[^"]+)".*}m, '\1')
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        def url_match_homepage?(stanza)
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,11 @@ module RuboCop
 | 
			
		||||
      # - `component_precedence_list` has component hierarchy in a nested list
 | 
			
		||||
      #   where each sub array contains components' details which are at same precedence level
 | 
			
		||||
      class ComponentsOrder < FormulaCop
 | 
			
		||||
        # `aspell`: options and resources should be grouped by language
 | 
			
		||||
        COMPONENT_WHITELIST = %w[
 | 
			
		||||
          aspell
 | 
			
		||||
        ].freeze
 | 
			
		||||
 | 
			
		||||
        def audit_formula(_node, _class_node, _parent_class_node, body_node)
 | 
			
		||||
          component_precedence_list = [
 | 
			
		||||
            [{ name: :include,   type: :method_call }],
 | 
			
		||||
@ -34,6 +39,8 @@ module RuboCop
 | 
			
		||||
            [{ name: :deprecated_option, type: :method_call }],
 | 
			
		||||
            [{ name: :depends_on, type: :method_call }],
 | 
			
		||||
            [{ name: :uses_from_macos, type: :method_call }],
 | 
			
		||||
            [{ name: :on_macos, type: :block_call }],
 | 
			
		||||
            [{ name: :on_linux, type: :block_call }],
 | 
			
		||||
            [{ name: :conflicts_with, type: :method_call }],
 | 
			
		||||
            [{ name: :skip_clean, type: :method_call }],
 | 
			
		||||
            [{ name: :cxxstdlib_check, type: :method_call }],
 | 
			
		||||
@ -49,50 +56,115 @@ module RuboCop
 | 
			
		||||
            [{ name: :test, type: :block_call }],
 | 
			
		||||
          ]
 | 
			
		||||
 | 
			
		||||
          @present_components = component_precedence_list.map do |components|
 | 
			
		||||
            relevant_components = []
 | 
			
		||||
            components.each do |component|
 | 
			
		||||
              case component[:type]
 | 
			
		||||
              when :method_call
 | 
			
		||||
                relevant_components += find_method_calls_by_name(body_node, component[:name]).to_a
 | 
			
		||||
              when :block_call
 | 
			
		||||
                relevant_components += find_blocks(body_node, component[:name]).to_a
 | 
			
		||||
              when :method_definition
 | 
			
		||||
                relevant_components << find_method_def(body_node, component[:name])
 | 
			
		||||
              end
 | 
			
		||||
            end
 | 
			
		||||
            relevant_components.delete_if(&:nil?)
 | 
			
		||||
          @present_components, @offensive_nodes = check_order(component_precedence_list, body_node)
 | 
			
		||||
 | 
			
		||||
          component_problem @offensive_nodes[0], @offensive_nodes[1] if @offensive_nodes
 | 
			
		||||
 | 
			
		||||
          component_precedence_list = [
 | 
			
		||||
            [{ name: :depends_on, type: :method_call }],
 | 
			
		||||
            [{ name: :resource, type: :block_call }],
 | 
			
		||||
            [{ name: :patch, type: :method_call }, { name: :patch, type: :block_call }],
 | 
			
		||||
          ]
 | 
			
		||||
 | 
			
		||||
          on_macos_blocks = find_blocks(body_node, :on_macos)
 | 
			
		||||
 | 
			
		||||
          if on_macos_blocks.length > 1
 | 
			
		||||
            @offensive_node = on_macos_blocks.second
 | 
			
		||||
            @offense_source_range = on_macos_blocks.second.source_range
 | 
			
		||||
            problem "there can only be one `on_macos` block in a formula."
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          # Check if each present_components is above rest of the present_components
 | 
			
		||||
          @present_components.take(@present_components.size - 1).each_with_index do |preceding_component, p_idx|
 | 
			
		||||
            next if preceding_component.empty?
 | 
			
		||||
          check_on_os_block_content(component_precedence_list, on_macos_blocks.first) if on_macos_blocks.any?
 | 
			
		||||
 | 
			
		||||
            @present_components.drop(p_idx + 1).each do |succeeding_component|
 | 
			
		||||
              next if succeeding_component.empty?
 | 
			
		||||
          on_linux_blocks = find_blocks(body_node, :on_linux)
 | 
			
		||||
 | 
			
		||||
              @offensive_nodes = check_precedence(preceding_component, succeeding_component)
 | 
			
		||||
              component_problem @offensive_nodes[0], @offensive_nodes[1] if @offensive_nodes
 | 
			
		||||
          if on_linux_blocks.length > 1
 | 
			
		||||
            @offensive_node = on_linux_blocks.second
 | 
			
		||||
            @offense_source_range = on_linux_blocks.second.source_range
 | 
			
		||||
            problem "there can only be one `on_linux` block in a formula."
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          check_on_os_block_content(component_precedence_list, on_linux_blocks.first) if on_linux_blocks.any?
 | 
			
		||||
 | 
			
		||||
          resource_blocks = find_blocks(body_node, :resource)
 | 
			
		||||
          resource_blocks.each do |resource_block|
 | 
			
		||||
            on_macos_blocks = find_blocks(resource_block.body, :on_macos)
 | 
			
		||||
            on_linux_blocks = find_blocks(resource_block.body, :on_linux)
 | 
			
		||||
 | 
			
		||||
            if on_macos_blocks.length.zero? && on_linux_blocks.length.zero?
 | 
			
		||||
              # Found nothing. Try without .body as depending on the code,
 | 
			
		||||
              # on_macos or on_linux might be in .body or not ...
 | 
			
		||||
              on_macos_blocks = find_blocks(resource_block, :on_macos)
 | 
			
		||||
              on_linux_blocks = find_blocks(resource_block, :on_linux)
 | 
			
		||||
 | 
			
		||||
              next if on_macos_blocks.length.zero? && on_linux_blocks.length.zero?
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            @offensive_node = resource_block
 | 
			
		||||
            @offense_source_range = resource_block.source_range
 | 
			
		||||
 | 
			
		||||
            if on_macos_blocks.length > 1
 | 
			
		||||
              problem "there can only be one `on_macos` block in a resource block."
 | 
			
		||||
              next
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            if on_linux_blocks.length > 1
 | 
			
		||||
              problem "there can only be one `on_linux` block in a resource block."
 | 
			
		||||
              next
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            if on_macos_blocks.length == 1 && on_linux_blocks.length.zero?
 | 
			
		||||
              problem "you need to define an `on_linux` block within your resource block."
 | 
			
		||||
              next
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            if on_macos_blocks.length.zero? && on_linux_blocks.length == 1
 | 
			
		||||
              problem "you need to define an `on_macos` block within your resource block."
 | 
			
		||||
              next
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            on_macos_block = on_macos_blocks.first
 | 
			
		||||
            on_linux_block = on_linux_blocks.first
 | 
			
		||||
 | 
			
		||||
            child_nodes = on_macos_block.body.child_nodes
 | 
			
		||||
            if child_nodes[0].method_name.to_s != "url" && child_nodes[1].method_name.to_s != "sha256"
 | 
			
		||||
              problem "only an url and a sha256 (in the right order) are allowed in a `on_macos` " \
 | 
			
		||||
                      "block within a resource block."
 | 
			
		||||
              next
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            child_nodes = on_linux_block.body.child_nodes
 | 
			
		||||
            if child_nodes[0].method_name.to_s != "url" && child_nodes[1].method_name.to_s != "sha256"
 | 
			
		||||
              problem "only an url and a sha256 (in the right order) are allowed in a `on_linux` " \
 | 
			
		||||
                      "block within a resource block."
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        # `aspell`: options and resources should be grouped by language
 | 
			
		||||
        WHITELIST = %w[
 | 
			
		||||
          aspell
 | 
			
		||||
        ].freeze
 | 
			
		||||
        def check_on_os_block_content(component_precedence_list, on_os_block)
 | 
			
		||||
          _, offensive_node = check_order(component_precedence_list, on_os_block.body)
 | 
			
		||||
          component_problem(*offensive_node) if offensive_node
 | 
			
		||||
          on_os_block.body.child_nodes.each do |child|
 | 
			
		||||
            valid_node = depends_on_node?(child)
 | 
			
		||||
            # Check for RuboCop::AST::SendNode instances only, as we are checking the
 | 
			
		||||
            # method_name for patches and resources.
 | 
			
		||||
            next unless child.instance_of? RuboCop::AST::SendNode
 | 
			
		||||
 | 
			
		||||
        # Method to format message for reporting component precedence violations
 | 
			
		||||
        def component_problem(c1, c2)
 | 
			
		||||
          return if WHITELIST.include?(@formula_name)
 | 
			
		||||
            valid_node ||= child.method_name.to_s == "patch"
 | 
			
		||||
            valid_node ||= child.method_name.to_s == "resource"
 | 
			
		||||
 | 
			
		||||
          problem "`#{format_component(c1)}` (line #{line_number(c1)}) " \
 | 
			
		||||
                  "should be put before `#{format_component(c2)}` " \
 | 
			
		||||
                  "(line #{line_number(c2)})"
 | 
			
		||||
            @offensive_node = on_os_block
 | 
			
		||||
            @offense_source_range = on_os_block.source_range
 | 
			
		||||
            unless valid_node
 | 
			
		||||
              problem "`#{on_os_block.method_name}` can only include `depends_on`, `patch` and `resource` nodes."
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        # autocorrect method gets called just after component_problem method call
 | 
			
		||||
        def autocorrect(_node)
 | 
			
		||||
          return if @offensive_nodes.nil?
 | 
			
		||||
 | 
			
		||||
          succeeding_node = @offensive_nodes[0]
 | 
			
		||||
          preceding_node = @offensive_nodes[1]
 | 
			
		||||
          lambda do |corrector|
 | 
			
		||||
@ -130,6 +202,52 @@ module RuboCop
 | 
			
		||||
            return [idx, comp.index(node1), comp] if comp.member?(node1)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        def check_order(component_precedence_list, body_node)
 | 
			
		||||
          present_components = component_precedence_list.map do |components|
 | 
			
		||||
            components.flat_map do |component|
 | 
			
		||||
              case component[:type]
 | 
			
		||||
              when :method_call
 | 
			
		||||
                find_method_calls_by_name(body_node, component[:name]).to_a
 | 
			
		||||
              when :block_call
 | 
			
		||||
                find_blocks(body_node, component[:name]).to_a
 | 
			
		||||
              when :method_definition
 | 
			
		||||
                find_method_def(body_node, component[:name])
 | 
			
		||||
              end
 | 
			
		||||
            end.compact
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          # Check if each present_components is above rest of the present_components
 | 
			
		||||
          offensive_nodes = nil
 | 
			
		||||
          present_components.take(present_components.size - 1).each_with_index do |preceding_component, p_idx|
 | 
			
		||||
            next if preceding_component.empty?
 | 
			
		||||
 | 
			
		||||
            present_components.drop(p_idx + 1).each do |succeeding_component|
 | 
			
		||||
              next if succeeding_component.empty?
 | 
			
		||||
 | 
			
		||||
              offensive_nodes = check_precedence(preceding_component, succeeding_component)
 | 
			
		||||
              break if offensive_nodes
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          [present_components, offensive_nodes]
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        # Method to format message for reporting component precedence violations
 | 
			
		||||
        def component_problem(c1, c2)
 | 
			
		||||
          return if COMPONENT_WHITELIST.include?(@formula_name)
 | 
			
		||||
 | 
			
		||||
          problem "`#{format_component(c1)}` (line #{line_number(c1)}) " \
 | 
			
		||||
                  "should be put before `#{format_component(c2)}` " \
 | 
			
		||||
                  "(line #{line_number(c2)})"
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        # Node pattern method to match
 | 
			
		||||
        # `depends_on` variants
 | 
			
		||||
        def_node_matcher :depends_on_node?, <<~EOS
 | 
			
		||||
          {(if _ (send nil? :depends_on ...) nil?)
 | 
			
		||||
           (send nil? :depends_on ...)}
 | 
			
		||||
        EOS
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -153,7 +153,7 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
          find_instance_method_call(body_node, :build, :include?) do |method|
 | 
			
		||||
            arg = parameters(method).first
 | 
			
		||||
            next unless match = regex_match_group(arg, /^\-\-(.*)$/)
 | 
			
		||||
            next unless match = regex_match_group(arg, /^--(.*)$/)
 | 
			
		||||
 | 
			
		||||
            problem "Reference '#{match[1]}' without dashes"
 | 
			
		||||
          end
 | 
			
		||||
@ -403,7 +403,7 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
            path = parameters(method).first
 | 
			
		||||
            next unless path.str_type?
 | 
			
		||||
            next unless match = regex_match_group(path, /^[^\*{},]+$/)
 | 
			
		||||
            next unless match = regex_match_group(path, /^[^*{},]+$/)
 | 
			
		||||
 | 
			
		||||
            problem "Dir([\"#{string_content(path)}\"]) is unnecessary; just use \"#{match[0]}\""
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
@ -13,11 +13,12 @@ module RuboCop
 | 
			
		||||
          https://downloads.sourceforge.net/project/bittwist/
 | 
			
		||||
          https://downloads.sourceforge.net/project/launch4j/
 | 
			
		||||
          https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard/archive/
 | 
			
		||||
          https://github.com/obihann/archey-osx/archive/
 | 
			
		||||
          https://github.com/obihann/archey-osx
 | 
			
		||||
          https://github.com/sindresorhus/macos-wallpaper/archive/
 | 
			
		||||
          https://raw.githubusercontent.com/liyanage/macosx-shell-scripts/
 | 
			
		||||
          https://osxbook.com/book/bonus/chapter8/core/download/gcore
 | 
			
		||||
          https://naif.jpl.nasa.gov/pub/naif/toolkit/C/MacIntel_OSX_AppleC_64bit/packages/
 | 
			
		||||
          https://artifacts.videolan.org/x264/release-macos/
 | 
			
		||||
        ].freeze
 | 
			
		||||
 | 
			
		||||
        # These are formulae that, sadly, require an upstream binary to bootstrap.
 | 
			
		||||
@ -48,6 +49,12 @@ module RuboCop
 | 
			
		||||
          urls = find_every_func_call_by_name(body_node, :url)
 | 
			
		||||
          mirrors = find_every_func_call_by_name(body_node, :mirror)
 | 
			
		||||
 | 
			
		||||
          # Identify livecheck urls, to skip some checks for them
 | 
			
		||||
          livecheck_url = if (livecheck = find_every_func_call_by_name(body_node, :livecheck).first) &&
 | 
			
		||||
                             (livecheck_url = find_every_func_call_by_name(livecheck.parent, :url).first)
 | 
			
		||||
            string_content(parameters(livecheck_url).first)
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          # GNU urls; doesn't apply to mirrors
 | 
			
		||||
          gnu_pattern = %r{^(?:https?|ftp)://ftpmirror.gnu.org/(.*)}
 | 
			
		||||
          audit_urls(urls, gnu_pattern) do |match, url|
 | 
			
		||||
@ -63,9 +70,21 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
          apache_pattern = %r{^https?://(?:[^/]*\.)?apache\.org/(?:dyn/closer\.cgi\?path=/?|dist/)(.*)}i
 | 
			
		||||
          audit_urls(urls, apache_pattern) do |match, url|
 | 
			
		||||
            next if url == livecheck_url
 | 
			
		||||
 | 
			
		||||
            problem "#{url} should be `https://www.apache.org/dyn/closer.lua?path=#{match[1]}`"
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          version_control_pattern = %r{^(cvs|bzr|hg|fossil)://}
 | 
			
		||||
          audit_urls(urls, version_control_pattern) do |match, _|
 | 
			
		||||
            problem "Use of the #{match[1]}:// scheme is deprecated, pass `:using => :#{match[1]}` instead"
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          svn_pattern = %r{^svn\+http://}
 | 
			
		||||
          audit_urls(urls, svn_pattern) do |_, _|
 | 
			
		||||
            problem "Use of the svn+http:// scheme is deprecated, pass `:using => :svn` instead"
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          audit_urls(mirrors, /.*/) do |_, mirror|
 | 
			
		||||
            urls.each do |url|
 | 
			
		||||
              url_string = string_content(parameters(url).first)
 | 
			
		||||
@ -148,7 +167,7 @@ module RuboCop
 | 
			
		||||
 | 
			
		||||
            problem "Don't use /download in SourceForge urls (url is #{url})." if url.end_with?("/download")
 | 
			
		||||
 | 
			
		||||
            if url.match?(%r{^https?://sourceforge\.})
 | 
			
		||||
            if url.match?(%r{^https?://sourceforge\.}) && url != livecheck_url
 | 
			
		||||
              problem "Use https://downloads.sourceforge.net to get geolocation (url is #{url})."
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
@ -220,7 +239,7 @@ module RuboCop
 | 
			
		||||
          # Use new-style archive downloads
 | 
			
		||||
          archive_gh_pattern = %r{https://.*github.*/(?:tar|zip)ball/}
 | 
			
		||||
          audit_urls(urls, archive_gh_pattern) do |_, url|
 | 
			
		||||
            next if url.match?(/\.git$/)
 | 
			
		||||
            next if url.end_with?(".git")
 | 
			
		||||
 | 
			
		||||
            problem "Use /archive/ URLs for GitHub tarballs (url is #{url})."
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
@ -221,6 +221,7 @@ class SoftwareSpec
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # TODO
 | 
			
		||||
  def add_legacy_patches(list)
 | 
			
		||||
    list = Patch.normalize_legacy_patches(list)
 | 
			
		||||
    list.each { |p| p.owner = self }
 | 
			
		||||
 | 
			
		||||
@ -77,7 +77,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      case output_type
 | 
			
		||||
      when :print
 | 
			
		||||
        args << "--debug" if ARGV.debug?
 | 
			
		||||
        args << "--debug" if Homebrew.args.debug?
 | 
			
		||||
        args << "--display-cop-names" if Homebrew.args.display_cop_names?
 | 
			
		||||
        args << "--format" << "simple" if files
 | 
			
		||||
        system(cache_env, "rubocop", *args)
 | 
			
		||||
 | 
			
		||||
@ -34,7 +34,7 @@ class SystemCommand
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def run!
 | 
			
		||||
    puts redact_secrets(command.shelljoin.gsub('\=', "="), @secrets) if verbose? || ARGV.debug?
 | 
			
		||||
    puts redact_secrets(command.shelljoin.gsub('\=', "="), @secrets) if verbose? || Homebrew.args.debug?
 | 
			
		||||
 | 
			
		||||
    @output = []
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -88,7 +88,7 @@ class SystemConfig
 | 
			
		||||
      _, err, status = system_command("java", args: ["-version"], print_stderr: false)
 | 
			
		||||
      return "N/A" unless status.success?
 | 
			
		||||
 | 
			
		||||
      err[/java version "([\d\._]+)"/, 1] || "N/A"
 | 
			
		||||
      err[/java version "([\d._]+)"/, 1] || "N/A"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def describe_git
 | 
			
		||||
@ -100,7 +100,7 @@ class SystemConfig
 | 
			
		||||
    def describe_curl
 | 
			
		||||
      out, = system_command(curl_executable, args: ["--version"])
 | 
			
		||||
 | 
			
		||||
      if /^curl (?<curl_version>[\d\.]+)/ =~ out
 | 
			
		||||
      if /^curl (?<curl_version>[\d.]+)/ =~ out
 | 
			
		||||
        "#{curl_version} => #{curl_executable}"
 | 
			
		||||
      else
 | 
			
		||||
        "N/A"
 | 
			
		||||
 | 
			
		||||
@ -1,89 +0,0 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "extend/ARGV"
 | 
			
		||||
 | 
			
		||||
describe HomebrewArgvExtension do
 | 
			
		||||
  subject { argv.extend(described_class) }
 | 
			
		||||
 | 
			
		||||
  let(:argv) { ["mxcl"] }
 | 
			
		||||
 | 
			
		||||
  describe "#named" do
 | 
			
		||||
    let(:argv) { ["foo", "--debug", "-v"] }
 | 
			
		||||
 | 
			
		||||
    it "returns an array of non-option arguments" do
 | 
			
		||||
      expect(subject.send(:named)).to eq ["foo"]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context "when there are no named arguments" do
 | 
			
		||||
      let(:argv) { [] }
 | 
			
		||||
 | 
			
		||||
      it "returns an empty array" do
 | 
			
		||||
        expect(subject.send(:named)).to be_empty
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "#options_only" do
 | 
			
		||||
    let(:argv) { ["--foo", "-vds", "a", "b", "cdefg"] }
 | 
			
		||||
 | 
			
		||||
    it "returns an array of option arguments" do
 | 
			
		||||
      expect(subject.send("options_only")).to eq ["--foo", "-vds"]
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "#empty?" do
 | 
			
		||||
    let(:argv) { [] }
 | 
			
		||||
 | 
			
		||||
    it "returns true if it is empty" do
 | 
			
		||||
      expect(subject).to be_empty
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "#switch?" do
 | 
			
		||||
    let(:argv) { ["-ns", "-i", "--bar", "-a-bad-arg"] }
 | 
			
		||||
 | 
			
		||||
    it "returns true if the given string is a switch" do
 | 
			
		||||
      %w[n s i].each do |s|
 | 
			
		||||
        expect(subject.send("switch?", s)).to be true
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "returns false if the given string is not a switch" do
 | 
			
		||||
      %w[b ns bar --bar -n a bad arg].each do |s|
 | 
			
		||||
        expect(subject.send("switch?", s)).to be false
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "#flag?" do
 | 
			
		||||
    let(:argv) { ["--foo", "-bq", "--bar"] }
 | 
			
		||||
 | 
			
		||||
    it "returns true if the given string is a flag" do
 | 
			
		||||
      expect(subject.send("flag?", "--foo")).to eq true
 | 
			
		||||
      expect(subject.send("flag?", "--bar")).to eq true
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "returns true if there is a switch with the same initial character" do
 | 
			
		||||
      expect(subject.send("flag?", "--baz")).to eq true
 | 
			
		||||
      expect(subject.send("flag?", "--qux")).to eq true
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "returns false if there is no matching flag" do
 | 
			
		||||
      expect(subject.send("flag?", "--frotz")).to eq false
 | 
			
		||||
      expect(subject.send("flag?", "--debug")).to eq false
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "#value" do
 | 
			
		||||
    let(:argv) { ["--foo=", "--bar=ab"] }
 | 
			
		||||
 | 
			
		||||
    it "returns the value for a given string" do
 | 
			
		||||
      expect(subject.value("foo")).to eq ""
 | 
			
		||||
      expect(subject.value("bar")).to eq "ab"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "returns nil if there is no matching argument" do
 | 
			
		||||
      expect(subject.value("baz")).to be nil
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -39,12 +39,12 @@ describe Cask::Audit, :cask do
 | 
			
		||||
 | 
			
		||||
  let(:cask) { instance_double(Cask::Cask) }
 | 
			
		||||
  let(:download) { false }
 | 
			
		||||
  let(:check_token_conflicts) { false }
 | 
			
		||||
  let(:token_conflicts) { false }
 | 
			
		||||
  let(:fake_system_command) { class_double(SystemCommand) }
 | 
			
		||||
  let(:audit) {
 | 
			
		||||
    described_class.new(cask, download:              download,
 | 
			
		||||
                              check_token_conflicts: check_token_conflicts,
 | 
			
		||||
                              command:               fake_system_command)
 | 
			
		||||
    described_class.new(cask, download:        download,
 | 
			
		||||
                              token_conflicts: token_conflicts,
 | 
			
		||||
                              command:         fake_system_command)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  describe "#result" do
 | 
			
		||||
@ -517,7 +517,7 @@ describe Cask::Audit, :cask do
 | 
			
		||||
 | 
			
		||||
    describe "token conflicts" do
 | 
			
		||||
      let(:cask_token) { "with-binary" }
 | 
			
		||||
      let(:check_token_conflicts) { true }
 | 
			
		||||
      let(:token_conflicts) { true }
 | 
			
		||||
 | 
			
		||||
      context "when cask token conflicts with a core formula" do
 | 
			
		||||
        let(:formula_names) { %w[with-binary other-formula] }
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,13 @@ describe Cask::Cmd::Audit, :cask do
 | 
			
		||||
      expect(Cask::CaskLoader).to receive(:load).with(cask_token).and_return(cask)
 | 
			
		||||
 | 
			
		||||
      expect(Cask::Auditor).to receive(:audit)
 | 
			
		||||
        .with(cask, audit_download: false, audit_appcast: false, check_token_conflicts: false, quarantine: true)
 | 
			
		||||
        .with(cask, audit_download:        false,
 | 
			
		||||
                    audit_appcast:         false,
 | 
			
		||||
                    audit_token_conflicts: false,
 | 
			
		||||
                    audit_new_cask:        false,
 | 
			
		||||
                    audit_online:          false,
 | 
			
		||||
                    audit_strict:          false,
 | 
			
		||||
                    quarantine:            true)
 | 
			
		||||
        .and_return(true)
 | 
			
		||||
 | 
			
		||||
      described_class.run(cask_token)
 | 
			
		||||
@ -32,7 +38,13 @@ describe Cask::Cmd::Audit, :cask do
 | 
			
		||||
    it "does not download the Cask per default" do
 | 
			
		||||
      allow(Cask::CaskLoader).to receive(:load).and_return(cask)
 | 
			
		||||
      expect(Cask::Auditor).to receive(:audit)
 | 
			
		||||
        .with(cask, audit_download: false, audit_appcast: false, check_token_conflicts: false, quarantine: true)
 | 
			
		||||
        .with(cask, audit_download:        false,
 | 
			
		||||
                    audit_appcast:         false,
 | 
			
		||||
                    audit_token_conflicts: false,
 | 
			
		||||
                    audit_new_cask:        false,
 | 
			
		||||
                    audit_online:          false,
 | 
			
		||||
                    audit_strict:          false,
 | 
			
		||||
                    quarantine:            true)
 | 
			
		||||
        .and_return(true)
 | 
			
		||||
 | 
			
		||||
      described_class.run("casktoken")
 | 
			
		||||
@ -41,7 +53,13 @@ describe Cask::Cmd::Audit, :cask do
 | 
			
		||||
    it "download a Cask if --download flag is set" do
 | 
			
		||||
      allow(Cask::CaskLoader).to receive(:load).and_return(cask)
 | 
			
		||||
      expect(Cask::Auditor).to receive(:audit)
 | 
			
		||||
        .with(cask, audit_download: true, audit_appcast: false, check_token_conflicts: false, quarantine: true)
 | 
			
		||||
        .with(cask, audit_download:        true,
 | 
			
		||||
                    audit_appcast:         false,
 | 
			
		||||
                    audit_token_conflicts: false,
 | 
			
		||||
                    audit_new_cask:        false,
 | 
			
		||||
                    audit_online:          false,
 | 
			
		||||
                    audit_strict:          false,
 | 
			
		||||
                    quarantine:            true)
 | 
			
		||||
        .and_return(true)
 | 
			
		||||
 | 
			
		||||
      described_class.run("casktoken", "--download")
 | 
			
		||||
@ -52,7 +70,13 @@ describe Cask::Cmd::Audit, :cask do
 | 
			
		||||
    it "does not check for token conflicts per default" do
 | 
			
		||||
      allow(Cask::CaskLoader).to receive(:load).and_return(cask)
 | 
			
		||||
      expect(Cask::Auditor).to receive(:audit)
 | 
			
		||||
        .with(cask, audit_download: false, audit_appcast: false, check_token_conflicts: false, quarantine: true)
 | 
			
		||||
        .with(cask, audit_download:        false,
 | 
			
		||||
                    audit_appcast:         false,
 | 
			
		||||
                    audit_token_conflicts: false,
 | 
			
		||||
                    audit_new_cask:        false,
 | 
			
		||||
                    audit_online:          false,
 | 
			
		||||
                    audit_strict:          false,
 | 
			
		||||
                    quarantine:            true)
 | 
			
		||||
        .and_return(true)
 | 
			
		||||
 | 
			
		||||
      described_class.run("casktoken")
 | 
			
		||||
@ -61,10 +85,112 @@ describe Cask::Cmd::Audit, :cask do
 | 
			
		||||
    it "checks for token conflicts if --token-conflicts flag is set" do
 | 
			
		||||
      allow(Cask::CaskLoader).to receive(:load).and_return(cask)
 | 
			
		||||
      expect(Cask::Auditor).to receive(:audit)
 | 
			
		||||
        .with(cask, audit_download: false, audit_appcast: false, check_token_conflicts: true, quarantine: true)
 | 
			
		||||
        .with(cask, audit_download:        false,
 | 
			
		||||
                    audit_appcast:         false,
 | 
			
		||||
                    audit_token_conflicts: true,
 | 
			
		||||
                    audit_new_cask:        false,
 | 
			
		||||
                    audit_online:          false,
 | 
			
		||||
                    audit_strict:          false,
 | 
			
		||||
                    quarantine:            true)
 | 
			
		||||
        .and_return(true)
 | 
			
		||||
 | 
			
		||||
      described_class.run("casktoken", "--token-conflicts")
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "rules for checking strictly" do
 | 
			
		||||
    it "does not check strictly per default" do
 | 
			
		||||
      allow(Cask::CaskLoader).to receive(:load).and_return(cask)
 | 
			
		||||
      expect(Cask::Auditor).to receive(:audit)
 | 
			
		||||
        .with(cask, audit_download:        false,
 | 
			
		||||
                    audit_appcast:         false,
 | 
			
		||||
                    audit_token_conflicts: false,
 | 
			
		||||
                    audit_new_cask:        false,
 | 
			
		||||
                    audit_online:          false,
 | 
			
		||||
                    audit_strict:          false,
 | 
			
		||||
                    quarantine:            true)
 | 
			
		||||
        .and_return(true)
 | 
			
		||||
 | 
			
		||||
      described_class.run("casktoken")
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "checks strictly if --strict flag is set" do
 | 
			
		||||
      allow(Cask::CaskLoader).to receive(:load).and_return(cask)
 | 
			
		||||
      expect(Cask::Auditor).to receive(:audit)
 | 
			
		||||
        .with(cask, audit_download:        false,
 | 
			
		||||
                    audit_appcast:         false,
 | 
			
		||||
                    audit_token_conflicts: true,
 | 
			
		||||
                    audit_new_cask:        false,
 | 
			
		||||
                    audit_online:          false,
 | 
			
		||||
                    audit_strict:          true,
 | 
			
		||||
                    quarantine:            true)
 | 
			
		||||
        .and_return(true)
 | 
			
		||||
 | 
			
		||||
      described_class.run("casktoken", "--strict")
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "rules for checking online" do
 | 
			
		||||
    it "does not check online per default" do
 | 
			
		||||
      allow(Cask::CaskLoader).to receive(:load).and_return(cask)
 | 
			
		||||
      expect(Cask::Auditor).to receive(:audit)
 | 
			
		||||
        .with(cask, audit_download:        false,
 | 
			
		||||
                    audit_appcast:         false,
 | 
			
		||||
                    audit_token_conflicts: false,
 | 
			
		||||
                    audit_new_cask:        false,
 | 
			
		||||
                    audit_online:          false,
 | 
			
		||||
                    audit_strict:          false,
 | 
			
		||||
                    quarantine:            true)
 | 
			
		||||
        .and_return(true)
 | 
			
		||||
 | 
			
		||||
      described_class.run("casktoken")
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "checks online if --online flag is set" do
 | 
			
		||||
      allow(Cask::CaskLoader).to receive(:load).and_return(cask)
 | 
			
		||||
      expect(Cask::Auditor).to receive(:audit)
 | 
			
		||||
        .with(cask, audit_download:        true,
 | 
			
		||||
                    audit_appcast:         true,
 | 
			
		||||
                    audit_token_conflicts: false,
 | 
			
		||||
                    audit_new_cask:        false,
 | 
			
		||||
                    audit_online:          true,
 | 
			
		||||
                    audit_strict:          false,
 | 
			
		||||
                    quarantine:            true)
 | 
			
		||||
        .and_return(true)
 | 
			
		||||
 | 
			
		||||
      described_class.run("casktoken", "--online")
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "rules for checking new casks" do
 | 
			
		||||
    it "does not check new casks per default" do
 | 
			
		||||
      allow(Cask::CaskLoader).to receive(:load).and_return(cask)
 | 
			
		||||
      expect(Cask::Auditor).to receive(:audit)
 | 
			
		||||
        .with(cask, audit_download:        false,
 | 
			
		||||
                    audit_appcast:         false,
 | 
			
		||||
                    audit_token_conflicts: false,
 | 
			
		||||
                    audit_new_cask:        false,
 | 
			
		||||
                    audit_online:          false,
 | 
			
		||||
                    audit_strict:          false,
 | 
			
		||||
                    quarantine:            true)
 | 
			
		||||
        .and_return(true)
 | 
			
		||||
 | 
			
		||||
      described_class.run("casktoken")
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "checks new casks if --new-cask flag is set" do
 | 
			
		||||
      allow(Cask::CaskLoader).to receive(:load).and_return(cask)
 | 
			
		||||
      expect(Cask::Auditor).to receive(:audit)
 | 
			
		||||
        .with(cask, audit_download:        true,
 | 
			
		||||
                    audit_appcast:         true,
 | 
			
		||||
                    audit_token_conflicts: true,
 | 
			
		||||
                    audit_new_cask:        true,
 | 
			
		||||
                    audit_online:          true,
 | 
			
		||||
                    audit_strict:          true,
 | 
			
		||||
                    quarantine:            true)
 | 
			
		||||
        .and_return(true)
 | 
			
		||||
 | 
			
		||||
      described_class.run("casktoken", "--new-cask")
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@
 | 
			
		||||
 | 
			
		||||
require_relative "shared_examples/requires_cask_token"
 | 
			
		||||
require_relative "shared_examples/invalid_option"
 | 
			
		||||
require "utils"
 | 
			
		||||
 | 
			
		||||
describe Cask::Cmd::Info, :cask do
 | 
			
		||||
  it_behaves_like "a command that requires a Cask token"
 | 
			
		||||
@ -139,7 +140,16 @@ describe Cask::Cmd::Info, :cask do
 | 
			
		||||
    EOS
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "can run be run with a url twice", :needs_network do
 | 
			
		||||
  it "can run be run with a url twice and returns analytics", :needs_network do
 | 
			
		||||
    analytics = {
 | 
			
		||||
      "analytics" => {
 | 
			
		||||
        "install" => {
 | 
			
		||||
          "30d" => { "docker" => 1000 }, "90d" => { "docker" => 2000 }, "365d" => { "docker" => 3000 }
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    }
 | 
			
		||||
    expect(Utils::Analytics).to receive(:formulae_brew_sh_json).twice.with("cask/docker.json")
 | 
			
		||||
    .and_return(analytics)
 | 
			
		||||
    expect {
 | 
			
		||||
      described_class.run("https://raw.githubusercontent.com/Homebrew/homebrew-cask" \
 | 
			
		||||
                          "/d0b2c58652ae5eff20a7a4ac93292a08b250912b/Casks/docker.rb")
 | 
			
		||||
@ -155,6 +165,8 @@ describe Cask::Cmd::Info, :cask do
 | 
			
		||||
      Docker CE
 | 
			
		||||
      ==> Artifacts
 | 
			
		||||
      Docker.app (App)
 | 
			
		||||
      ==> Analytics
 | 
			
		||||
      install: 1,000 (30 days), 2,000 (90 days), 3,000 (365 days)
 | 
			
		||||
      ==> Downloading https://raw.githubusercontent.com/Homebrew/homebrew-cask/d0b2c58652ae5eff20a7a4ac93292a08b250912b/Casks/docker.rb.
 | 
			
		||||
      docker: 2.0.0.2-ce-mac81,30215 (auto_updates)
 | 
			
		||||
      https://www.docker.com/community-edition
 | 
			
		||||
@ -164,6 +176,8 @@ describe Cask::Cmd::Info, :cask do
 | 
			
		||||
      Docker CE
 | 
			
		||||
      ==> Artifacts
 | 
			
		||||
      Docker.app (App)
 | 
			
		||||
      ==> Analytics
 | 
			
		||||
      install: 1,000 (30 days), 2,000 (90 days), 3,000 (365 days)
 | 
			
		||||
    EOS
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@ end
 | 
			
		||||
describe "brew --cache", :integration_test do
 | 
			
		||||
  it "prints all cache files for a given Formula" do
 | 
			
		||||
    expect { brew "--cache", testball }
 | 
			
		||||
      .to output(%r{#{HOMEBREW_CACHE}/downloads/[\da-f]{64}\-\-testball\-}).to_stdout
 | 
			
		||||
      .to output(%r{#{HOMEBREW_CACHE}/downloads/[\da-f]{64}--testball-}).to_stdout
 | 
			
		||||
      .and not_to_output.to_stderr
 | 
			
		||||
      .and be_a_success
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -68,7 +68,7 @@ describe "brew install", :integration_test do
 | 
			
		||||
    # and there will be the git requirement, but we cannot instantiate git
 | 
			
		||||
    # formula since we only have testball1 formula.
 | 
			
		||||
    expect { brew "install", "testball1", "--HEAD", "--ignore-dependencies" }
 | 
			
		||||
      .to output(%r{#{HOMEBREW_CELLAR}/testball1/HEAD\-d5eb689}).to_stdout
 | 
			
		||||
      .to output(%r{#{HOMEBREW_CELLAR}/testball1/HEAD-d5eb689}).to_stdout
 | 
			
		||||
      .and output(/Cloning into/).to_stderr
 | 
			
		||||
      .and be_a_success
 | 
			
		||||
    expect(HOMEBREW_CELLAR/"testball1/HEAD-d5eb689/foo/test").not_to be_a_file
 | 
			
		||||
 | 
			
		||||
@ -3,11 +3,12 @@
 | 
			
		||||
shared_examples "parseable arguments" do
 | 
			
		||||
  subject(:method_name) do |example|
 | 
			
		||||
    example.metadata[:example_group][:parent_example_group][:description]
 | 
			
		||||
           .gsub(/^Homebrew\./, "")
 | 
			
		||||
           .delete_prefix("Homebrew.")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  let(:command_name) do
 | 
			
		||||
    method_name.gsub(/_args$/, "").tr("_", "-")
 | 
			
		||||
    method_name.delete_suffix("_args")
 | 
			
		||||
               .tr("_", "-")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it "can parse arguments" do
 | 
			
		||||
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user