Merge branch 'master' into appcast-configuration-match

This commit is contained in:
Vítor Galvão 2020-06-06 03:04:57 +01:00 committed by GitHub
commit 446ef2c85f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
204 changed files with 2282 additions and 1386 deletions

View File

@ -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: --> <!-- Please fill these sections with the relevant information: -->
# A detailed description of the proposed feature # A detailed description of the proposed feature

View File

@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
version: ["18.04", "20.04"] version: ["16.04", "18.04", "20.04"]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@master uses: actions/checkout@master
@ -33,9 +33,24 @@ jobs:
docker login docker.pkg.github.com -u BrewTestBot -p ${{secrets.GITHUB_TOKEN}} 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 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 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 - name: Deploy the tagged Docker image to Docker Hub
if: startsWith(github.ref, 'refs/tags/') if: startsWith(github.ref, 'refs/tags/')
run: | run: |
docker login -u brewtestbot -p ${{secrets.DOCKER_TOKEN}} docker login -u brewtestbot -p ${{secrets.DOCKER_TOKEN}}
docker tag brew "homebrew/ubuntu${{matrix.version}}:$brew_version" docker tag brew "homebrew/ubuntu${{matrix.version}}:$brew_version"
docker push "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"

View File

@ -3,9 +3,6 @@ on:
push: push:
branches: master branches: master
pull_request: [] pull_request: []
release:
types:
- published
env: env:
HOMEBREW_GITHUB_ACTIONS: 1 HOMEBREW_GITHUB_ACTIONS: 1
HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_AUTO_UPDATE: 1
@ -71,6 +68,9 @@ jobs:
else else
# Link old gettext (otherwise `brew doctor` is sad) # Link old gettext (otherwise `brew doctor` is sad)
brew link gettext brew link gettext
# remove deleted formula
brew uninstall --force python@2
fi fi
brew doctor brew doctor
@ -173,7 +173,7 @@ jobs:
- name: Build Docker image - name: Build Docker image
if: matrix.os == 'ubuntu-latest' 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 - name: Run brew test-bot
run: | run: |
@ -184,16 +184,11 @@ jobs:
fi fi
- name: Deploy the Docker image to GitHub and Docker Hub - 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: | 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 login docker.pkg.github.com -u BrewTestBot -p ${{secrets.GITHUB_TOKEN}}
docker tag brew "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/brew:$v" docker push "docker.pkg.github.com/homebrew/brew/ubuntu16.04:master"
docker login -u brewtestbot -p ${{secrets.DOCKER_TOKEN}} docker login -u brewtestbot -p ${{secrets.DOCKER_TOKEN}}
docker tag brew "homebrew/brew:$v" docker tag brew "homebrew/ubuntu16.04:master"
docker push "homebrew/brew:$v" docker push "homebrew/ubuntu16.04:master"

2
.gitignore vendored
View File

@ -110,6 +110,7 @@
**/vendor/bundle/ruby/*/gems/pry-*/ **/vendor/bundle/ruby/*/gems/pry-*/
**/vendor/bundle/ruby/*/gems/rainbow-*/ **/vendor/bundle/ruby/*/gems/rainbow-*/
**/vendor/bundle/ruby/*/gems/rdiscount-*/ **/vendor/bundle/ruby/*/gems/rdiscount-*/
**/vendor/bundle/ruby/*/gems/regexp_parser-*/
**/vendor/bundle/ruby/*/gems/ronn-*/ **/vendor/bundle/ruby/*/gems/ronn-*/
**/vendor/bundle/ruby/*/gems/rspec-*/ **/vendor/bundle/ruby/*/gems/rspec-*/
**/vendor/bundle/ruby/*/gems/rspec-core-*/ **/vendor/bundle/ruby/*/gems/rspec-core-*/
@ -120,6 +121,7 @@
**/vendor/bundle/ruby/*/gems/rspec-support-*/ **/vendor/bundle/ruby/*/gems/rspec-support-*/
**/vendor/bundle/ruby/*/gems/rspec-wait-*/ **/vendor/bundle/ruby/*/gems/rspec-wait-*/
**/vendor/bundle/ruby/*/gems/rubocop-0*/ **/vendor/bundle/ruby/*/gems/rubocop-0*/
**/vendor/bundle/ruby/*/gems/rubocop-ast-*/
**/vendor/bundle/ruby/*/gems/ruby-prof-*/ **/vendor/bundle/ruby/*/gems/ruby-prof-*/
**/vendor/bundle/ruby/*/gems/ruby-progressbar-*/ **/vendor/bundle/ruby/*/gems/ruby-progressbar-*/
**/vendor/bundle/ruby/*/gems/simplecov-*/ **/vendor/bundle/ruby/*/gems/simplecov-*/

View File

@ -1,4 +1,4 @@
ARG version=16.04 ARG version=20.04
FROM ubuntu:$version FROM ubuntu:$version
ARG DEBIAN_FRONTEND=noninteractive 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 \ && HOMEBREW_NO_ANALYTICS=1 HOMEBREW_NO_AUTO_UPDATE=1 brew tap homebrew/core \
&& brew install-bundler-gems \ && brew install-bundler-gems \
&& brew cleanup \ && 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 \ && rm -rf ~/.cache \
&& chown -R linuxbrew: /home/linuxbrew/.linuxbrew \ && chown -R linuxbrew: /home/linuxbrew/.linuxbrew \
&& chmod -R g+w,o-w /home/linuxbrew/.linuxbrew && chmod -R g+w,o-w /home/linuxbrew/.linuxbrew

View File

@ -8,7 +8,7 @@ AllCops:
# Use `<<~` for heredocs. # Use `<<~` for heredocs.
Layout/HeredocIndentation: Layout/HeredocIndentation:
EnforcedStyle: squiggly Enabled: true
# Not useful in casks and formulae. # Not useful in casks and formulae.
Metrics/BlockLength: Metrics/BlockLength:

View File

@ -10,7 +10,7 @@ GEM
ast (2.4.0) ast (2.4.0)
byebug (11.1.3) byebug (11.1.3)
concurrent-ruby (1.1.6) concurrent-ruby (1.1.6)
connection_pool (2.2.2) connection_pool (2.2.3)
coveralls (0.8.23) coveralls (0.8.23)
json (>= 1.8, < 3) json (>= 1.8, < 3)
simplecov (~> 0.16.1) simplecov (~> 0.16.1)
@ -24,7 +24,7 @@ GEM
hpricot (0.8.6) hpricot (0.8.6)
http-cookie (1.0.3) http-cookie (1.0.3)
domain_name (~> 0.5) domain_name (~> 0.5)
i18n (1.8.2) i18n (1.8.3)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
json (2.3.0) json (2.3.0)
mechanize (2.7.6) mechanize (2.7.6)
@ -51,11 +51,12 @@ GEM
parallel (1.19.1) parallel (1.19.1)
parallel_tests (2.32.0) parallel_tests (2.32.0)
parallel parallel
parser (2.7.1.2) parser (2.7.1.3)
ast (~> 2.4.0) ast (~> 2.4.0)
plist (3.5.0) plist (3.5.0)
rainbow (3.0.0) rainbow (3.0.0)
rdiscount (2.2.0.1) rdiscount (2.2.0.1)
regexp_parser (1.7.0)
rexml (3.2.4) rexml (3.2.4)
ronn (0.7.3) ronn (0.7.3)
hpricot (>= 0.8.2) hpricot (>= 0.8.2)
@ -81,14 +82,18 @@ GEM
rspec-support (3.9.3) rspec-support (3.9.3)
rspec-wait (0.0.9) rspec-wait (0.0.9)
rspec (>= 3, < 4) rspec (>= 3, < 4)
rubocop (0.83.0) rubocop (0.85.0)
parallel (~> 1.10) parallel (~> 1.10)
parser (>= 2.7.0.1) parser (>= 2.7.0.1)
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.7)
rexml rexml
rubocop-ast (>= 0.0.3)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 2.0) 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 (>= 0.71.0)
rubocop-rspec (1.39.0) rubocop-rspec (1.39.0)
rubocop (>= 0.68.1) rubocop (>= 0.68.1)

View File

@ -50,7 +50,7 @@ begin
help_flag = !ENV["HOMEBREW_HELP"].nil? help_flag = !ENV["HOMEBREW_HELP"].nil?
cmd = nil cmd = nil
ARGV.dup.each_with_index do |arg, i| ARGV.each_with_index do |arg, i|
break if help_flag && cmd break if help_flag && cmd
if arg == "help" && !cmd if arg == "help" && !cmd
@ -139,8 +139,8 @@ rescue UsageError => e
require "help" require "help"
Homebrew::Help.help cmd, usage_error: e.message Homebrew::Help.help cmd, usage_error: e.message
rescue SystemExit => e rescue SystemExit => e
onoe "Kernel.exit" if ARGV.debug? && !e.success? onoe "Kernel.exit" if Homebrew.args.debug? && !e.success?
$stderr.puts e.backtrace if ARGV.debug? $stderr.puts e.backtrace if Homebrew.args.debug?
raise raise
rescue Interrupt rescue Interrupt
$stderr.puts # seemingly a newline is typical $stderr.puts # seemingly a newline is typical
@ -156,7 +156,7 @@ rescue RuntimeError, SystemCallError => e
raise if e.message.empty? raise if e.message.empty?
onoe e onoe e
$stderr.puts e.backtrace if ARGV.debug? $stderr.puts e.backtrace if Homebrew.args.debug?
output_unsupported_error if Homebrew.args.HEAD? 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 "If reporting this issue please do so at (not Homebrew/brew or Homebrew/core):"
$stderr.puts " #{Formatter.url(e.issues_url)}" $stderr.puts " #{Formatter.url(e.issues_url)}"
end end
$stderr.puts e.backtrace if ARGV.debug? $stderr.puts e.backtrace if Homebrew.args.debug?
exit 1 exit 1
rescue Exception => e # rubocop:disable Lint/RescueException rescue Exception => e # rubocop:disable Lint/RescueException
onoe e onoe e

View File

@ -52,6 +52,8 @@ class Build
Requirement.prune Requirement.prune
elsif req.prune_if_build_and_not_dependent?(dependent, formula) elsif req.prune_if_build_and_not_dependent?(dependent, formula)
Requirement.prune Requirement.prune
elsif req.test?
Requirement.prune
end end
end end
end end
@ -65,6 +67,8 @@ class Build
Dependency.prune Dependency.prune
elsif dep.build? elsif dep.build?
Dependency.keep_but_prune_recursive_deps Dependency.keep_but_prune_recursive_deps
elsif dep.test?
Dependency.prune
end end
end end
end end
@ -112,7 +116,7 @@ class Build
} }
with_env(new_env) do with_env(new_env) do
formula.extend(Debrew::Formula) if ARGV.debug? formula.extend(Debrew::Formula) if Homebrew.args.debug?
formula.update_head_version formula.update_head_version

View File

@ -89,7 +89,7 @@ module Cask
args: ["list", service], args: ["list", service],
sudo: with_sudo, print_stderr: false sudo: with_sudo, print_stderr: false
).stdout ).stdout
if plist_status.match?(/^\{/) if plist_status.start_with?("{")
command.run!("/bin/launchctl", args: ["remove", service], sudo: with_sudo) command.run!("/bin/launchctl", args: ["remove", service], sudo: with_sudo)
sleep 1 sleep 1
end end
@ -326,7 +326,14 @@ module Cask
next next
end end
begin
yield path, Pathname.glob(resolved_path) 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
end end

View File

@ -6,6 +6,7 @@ require "cask/download"
require "digest" require "digest"
require "utils/curl" require "utils/curl"
require "utils/git" require "utils/git"
require "utils/notability"
module Cask module Cask
class Audit class Audit
@ -14,22 +15,22 @@ module Cask
attr_reader :cask, :commit_range, :download 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, def initialize(cask, appcast: false, download: false,
commit_range: nil, command: SystemCommand) token_conflicts: false, online: false, strict: false,
new_cask: false, commit_range: nil, command: SystemCommand)
@cask = cask @cask = cask
@check_appcast = check_appcast @appcast = appcast
@download = download @download = download
@online = online
@strict = strict
@new_cask = new_cask
@commit_range = commit_range @commit_range = commit_range
@check_token_conflicts = check_token_conflicts @token_conflicts = token_conflicts
@command = command @command = command
end end
def check_token_conflicts?
@check_token_conflicts
end
def run! def run!
check_blacklist check_blacklist
check_required_stanzas check_required_stanzas
@ -48,6 +49,9 @@ module Cask
check_latest_with_auto_updates check_latest_with_auto_updates
check_stanza_requires_uninstall check_stanza_requires_uninstall
check_appcast_contains_version check_appcast_contains_version
check_github_repository
check_gitlab_repository
check_bitbucket_repository
self self
rescue => e rescue => e
odebug "#{e.message}\n#{e.backtrace.join("\n")}" odebug "#{e.message}\n#{e.backtrace.join("\n")}"
@ -255,7 +259,7 @@ module Cask
bad_url_format?(/sourceforge/, bad_url_format?(/sourceforge/,
[ [
%r{\Ahttps://sourceforge\.net/projects/[^/]+/files/latest/download\Z}, %r{\Ahttps://sourceforge\.net/projects/[^/]+/files/latest/download\Z},
%r{\Ahttps://downloads\.sourceforge\.net/(?!(project|sourceforge)\/)}, %r{\Ahttps://downloads\.sourceforge\.net/(?!(project|sourceforge)/)},
]) ])
end end
@ -272,7 +276,7 @@ module Cask
end end
def check_token_conflicts def check_token_conflicts
return unless check_token_conflicts? return unless @token_conflicts
return unless core_formula_names.include?(cask.token) return unless core_formula_names.include?(cask.token)
add_warning "possible duplicate, cask token conflicts with Homebrew core formula: #{core_formula_url}" add_warning "possible duplicate, cask token conflicts with Homebrew core formula: #{core_formula_url}"
@ -301,7 +305,7 @@ module Cask
end end
def check_appcast_contains_version def check_appcast_contains_version
return unless check_appcast? return unless appcast?
return if cask.appcast.to_s.empty? return if cask.appcast.to_s.empty?
return if cask.appcast.must_contain == :no_check 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", appcast_contents, = curl_output("--compressed", "--user-agent", HOMEBREW_USER_AGENT_FAKE_SAFARI, "--location",
"--globoff", "--max-time", "5", appcast_stanza) "--globoff", "--max-time", "5", appcast_stanza)
version_stanza = cask.version.to_s version_stanza = cask.version.to_s
adjusted_version_stanza = if cask.appcast.must_contain.blank? adjusted_version_stanza = if cask.appcast.configuration.blank?
version_stanza.split(",")[0].split("-")[0].split("_")[0] version_stanza.match(/^[[:alnum:].]+/)[0]
else else
cask.appcast.must_contain cask.appcast.must_contain
end end
@ -322,6 +326,50 @@ module Cask
add_error "appcast at URL '#{appcast_stanza}' offline or looping" add_error "appcast at URL '#{appcast_stanza}' offline or looping"
end 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 def check_blacklist
return if cask.tap&.user != "Homebrew" return if cask.tap&.user != "Homebrew"
return unless reason = Blacklist.blacklisted_reason(cask.token) return unless reason = Blacklist.blacklisted_reason(cask.token)

View File

@ -8,37 +8,40 @@ module Cask
extend Predicable extend Predicable
def self.audit(cask, audit_download: false, audit_appcast: false, 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, new(cask, audit_download: audit_download,
audit_appcast: audit_appcast, 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 quarantine: quarantine, commit_range: commit_range).audit
end end
attr_reader :cask, :commit_range attr_reader :cask, :commit_range
def initialize(cask, audit_download: false, audit_appcast: false, 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 @cask = cask
@audit_download = audit_download @audit_download = audit_download
@audit_appcast = audit_appcast @audit_appcast = audit_appcast
@audit_online = audit_online
@audit_strict = audit_strict
@audit_new_cask = audit_new_cask
@quarantine = quarantine @quarantine = quarantine
@commit_range = commit_range @commit_range = commit_range
@check_token_conflicts = check_token_conflicts @audit_token_conflicts = audit_token_conflicts
end end
def audit_download? attr_predicate :audit_appcast?, :audit_download?, :audit_online?,
@audit_download :audit_strict?, :audit_new_cask?, :audit_token_conflicts?, :quarantine?
end
attr_predicate :audit_appcast?, :quarantine?
def check_token_conflicts?
@check_token_conflicts
end
def audit def audit
if !ARGV.value("language") && language_blocks if !Homebrew.args.value("language") && language_blocks
audit_all_languages audit_all_languages
else else
audit_cask_instance(cask) audit_cask_instance(cask)
@ -64,9 +67,12 @@ module Cask
def audit_cask_instance(cask) def audit_cask_instance(cask)
download = audit_download? && Download.new(cask, quarantine: quarantine?) download = audit_download? && Download.new(cask, quarantine: quarantine?)
audit = Audit.new(cask, check_appcast: audit_appcast?, 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, download: download,
check_token_conflicts: check_token_conflicts?,
commit_range: commit_range) commit_range: commit_range)
audit.run! audit.run!
puts audit.summary puts audit.summary

View File

@ -4,7 +4,7 @@ module Cask
module Blacklist module Blacklist
def self.blacklisted_reason(name) def self.blacklisted_reason(name)
case 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." "Adobe casks were removed because they are too difficult to maintain."
when /^audacity$/ when /^audacity$/
"Audacity was removed because it is too difficult to download programmatically." "Audacity was removed because it is too difficult to download programmatically."

View File

@ -145,13 +145,13 @@ module Cask
command, args = detect_internal_command(*args) || detect_external_command(*args) || [NullCommand.new, args] command, args = detect_internal_command(*args) || detect_external_command(*args) || [NullCommand.new, args]
if help? if help?
puts command.help Help.new(command.command_name).run
else else
command.run(*args) command.run(*args)
end end
rescue CaskError, MethodDeprecatedError, ArgumentError, OptionParser::InvalidOption => e rescue CaskError, MethodDeprecatedError, ArgumentError, OptionParser::InvalidOption => e
onoe e.message onoe e.message
$stderr.puts e.backtrace if ARGV.debug? $stderr.puts e.backtrace if Homebrew.args.debug?
exit 1 exit 1
rescue StandardError, ScriptError, NoMemoryError => e rescue StandardError, ScriptError, NoMemoryError => e
onoe e.message onoe e.message
@ -180,7 +180,7 @@ module Cask
end end
def process_options(*args) 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 = [] non_options = []

View File

@ -1,32 +1,66 @@
# frozen_string_literal: true # frozen_string_literal: true
require "cli/parser"
module Cask module Cask
class Cmd class Cmd
class Audit < AbstractCommand class Audit < AbstractCommand
option "--download", :download, false option "--download", :download_arg, false
option "--appcast", :appcast, false option "--appcast", :appcast_arg, false
option "--token-conflicts", :token_conflicts, 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 def self.help
"verifies installability of Casks" "verifies installability of Casks"
end end
def run 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 }) 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? return if failed_casks.empty?
raise CaskError, "audit failed for casks: #{failed_casks.join(" ")}" raise CaskError, "audit failed for casks: #{failed_casks.join(" ")}"
end 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 end
end end

View File

@ -3,17 +3,26 @@
module Cask module Cask
class Cmd class Cmd
class Help < AbstractCommand class Help < AbstractCommand
def initialize(*)
super
return if args.empty?
raise ArgumentError, "#{self.class.command_name} does not take arguments."
end
def run def run
if args.empty?
puts self.class.purpose puts self.class.purpose
puts puts
puts self.class.usage 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 end
def self.purpose def self.purpose
@ -23,6 +32,10 @@ module Cask
EOS EOS
end end
def self.commands
Cmd.command_classes.select(&:visible?).map { |klass| [klass.command_name, klass] }.to_h
end
def self.usage def self.usage
max_command_len = Cmd.commands.map(&:length).max max_command_len = Cmd.commands.map(&:length).max

View File

@ -46,6 +46,7 @@ module Cask
def self.info(cask) def self.info(cask)
puts get_info(cask) puts get_info(cask)
::Utils::Analytics.cask_output(cask)
end end
def self.title_info(cask) def self.title_info(cask)

View File

@ -46,7 +46,7 @@ module Cask
next if self.class.options.nil? next if self.class.options.nil?
self.class.options.each do |option_name, option_method| 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" when "PATH"
Pathname Pathname
when /\w+(,\w+)+/ when /\w+(,\w+)+/

View File

@ -86,7 +86,7 @@ module Cask
Shellwords.shellsplit(ENV.fetch("HOMEBREW_CASK_OPTS", "")) Shellwords.shellsplit(ENV.fetch("HOMEBREW_CASK_OPTS", ""))
.select { |arg| arg.include?("=") } .select { |arg| arg.include?("=") }
.map { |arg| arg.split("=", 2) } .map { |arg| arg.split("=", 2) }
.map { |(flag, value)| [flag.sub(/^\-\-/, ""), value] }, .map { |(flag, value)| [flag.sub(/^--/, ""), value] },
) )
end end

View File

@ -58,6 +58,19 @@ module Cask
EOS EOS
end 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| caveat :path_environment_variable do |path|
<<~EOS <<~EOS
To use #{@cask}, you may need to add the #{path} directory To use #{@cask}, you may need to add the #{path} directory

View File

@ -11,9 +11,9 @@ module Cask
DIVIDER_REGEX = /(#{DIVIDERS.keys.map { |v| Regexp.quote(v) }.join('|')})/.freeze 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 class << self
private private
@ -75,7 +75,7 @@ module Cask
s = downcase.delete(".").gsub(/[^a-z\d]+/, "-") 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?(/(\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 false
end end

View File

@ -368,8 +368,8 @@ module Cask
fi.installed_on_request = false fi.installed_on_request = false
fi.show_header = true fi.show_header = true
fi.verbose = verbose? fi.verbose = verbose?
fi.fetch
fi.prelude fi.prelude
fi.fetch
fi.install fi.install
fi.finish fi.finish
end end

View File

@ -109,7 +109,7 @@ class Cleaner
else else
0444 0444
end end
if ARGV.debug? if Homebrew.args.debug?
old_perms = path.stat.mode & 0777 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 odebug "Fixing #{path} permissions from #{old_perms.to_s(8)} to #{perms.to_s(8)}" if perms != old_perms
end end

View File

@ -56,14 +56,14 @@ module CleanupRefinement
end end
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 return false unless version
version = Version.new(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 formula = begin
Formulary.from_rack(HOMEBREW_CELLAR/formula_name) Formulary.from_rack(HOMEBREW_CELLAR/formula_name)
@ -71,7 +71,7 @@ module CleanupRefinement
return false return false
end 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" if resource_name == "patch"
patch_hashes = formula.stable&.patches&.select(&:external?)&.map(&:resource)&.map(&:version) patch_hashes = formula.stable&.patches&.select(&:external?)&.map(&:resource)&.map(&:version)
@ -84,7 +84,7 @@ module CleanupRefinement
return true return true
end end
return true if scrub && !formula.installed? return true if scrub && !formula.latest_version_installed?
return true if Utils::Bottles.file_outdated?(formula, self) return true if Utils::Bottles.file_outdated?(formula, self)
@ -92,7 +92,7 @@ module CleanupRefinement
end end
def stale_cask?(scrub) 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 = begin
Cask::CaskLoader.load(name) Cask::CaskLoader.load(name)
@ -100,7 +100,7 @@ module CleanupRefinement
return false return false
end 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) return true if scrub && !cask.versions.include?(cask.version)

View File

@ -10,7 +10,7 @@ module Homebrew
# undefine tap to allow --tap argument # undefine tap to allow --tap argument
undef tap undef tap
def initialize(argv = ARGV.dup.freeze, set_default_args: false) def initialize(argv = ARGV.freeze, set_default_args: false)
super() super()
@processed_options = [] @processed_options = []
@ -84,11 +84,7 @@ module Homebrew
require "formula" require "formula"
@formulae ||= (downcased_unique_named - casks).map do |name| @formulae ||= (downcased_unique_named - casks).map do |name|
if name.include?("/") || File.exist?(name)
Formulary.factory(name, spec) Formulary.factory(name, spec)
else
Formulary.find_with_priority(name, spec)
end
end.uniq(&:name).freeze end.uniq(&:name).freeze
end end
@ -175,6 +171,20 @@ module Homebrew
formulae.any? { |args_f| args_f.full_name == f.full_name } formulae.any? { |args_f| args_f.full_name == f.full_name }
end 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 private
def option_to_name(option) def option_to_name(option)

View File

@ -13,7 +13,7 @@ module Homebrew
class Parser class Parser
attr_reader :processed_options, :hide_from_man_page 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) new(argv, &block).parse(allow_no_named_args: allow_no_named_args)
end end
@ -38,7 +38,7 @@ module Homebrew
} }
end end
def initialize(argv = ARGV.dup.freeze, &block) def initialize(argv = ARGV.freeze, &block)
@parser = OptionParser.new @parser = OptionParser.new
@argv = argv @argv = argv
@args = Homebrew::CLI::Args.new(@argv) @args = Homebrew::CLI::Args.new(@argv)
@ -359,11 +359,7 @@ module Homebrew
named_args.map do |arg| named_args.map do |arg|
next if arg.match?(HOMEBREW_CASK_TAP_CASK_REGEX) next if arg.match?(HOMEBREW_CASK_TAP_CASK_REGEX)
if arg.include?("/") || arg.end_with?(".tar.gz") || File.exist?(arg)
Formulary.factory(arg, spec) Formulary.factory(arg, spec)
else
Formulary.find_with_priority(arg.downcase, spec)
end
end.compact.uniq(&:name) end.compact.uniq(&:name)
end end
end end

View File

@ -36,7 +36,6 @@ module Homebrew
shell = if args.plain? shell = if args.plain?
nil nil
elsif args.shell.nil? elsif args.shell.nil?
# legacy behavior
:bash unless $stdout.tty? :bash unless $stdout.tty?
elsif args.shell == "auto" elsif args.shell == "auto"
Utils::Shell.parent || Utils::Shell.preferred Utils::Shell.parent || Utils::Shell.preferred

View File

@ -105,11 +105,7 @@ module Homebrew
args.named.each_with_index do |f, i| args.named.each_with_index do |f, i|
puts unless i.zero? puts unless i.zero?
begin begin
formula = if f.include?("/") || File.exist?(f) formula = Formulary.factory(f)
Formulary.factory(f)
else
Formulary.find_with_priority(f)
end
if args.analytics? if args.analytics?
Utils::Analytics.formula_output(formula) Utils::Analytics.formula_output(formula)
else else

View File

@ -325,8 +325,8 @@ module Homebrew
fi.build_bottle = args.build_bottle? fi.build_bottle = args.build_bottle?
fi.interactive = args.interactive? fi.interactive = args.interactive?
fi.git = args.git? fi.git = args.git?
fi.fetch
fi.prelude fi.prelude
fi.fetch
fi.install fi.install
fi.finish fi.finish
rescue FormulaInstallationAlreadyAttemptedError rescue FormulaInstallationAlreadyAttemptedError

View File

@ -20,8 +20,8 @@ homebrew-shellenv() {
echo "setenv HOMEBREW_CELLAR $HOMEBREW_CELLAR;" echo "setenv HOMEBREW_CELLAR $HOMEBREW_CELLAR;"
echo "setenv HOMEBREW_REPOSITORY $HOMEBREW_REPOSITORY;" echo "setenv HOMEBREW_REPOSITORY $HOMEBREW_REPOSITORY;"
echo "setenv PATH $HOMEBREW_PREFIX/bin:$HOMEBREW_PREFIX/sbin:\$PATH;" echo "setenv PATH $HOMEBREW_PREFIX/bin:$HOMEBREW_PREFIX/sbin:\$PATH;"
echo "setenv MANPATH $HOMEBREW_PREFIX/share/man:\$MANPATH;" echo "setenv MANPATH $HOMEBREW_PREFIX/share/man\`[ \${?MANPATH} == 1 ] && echo \":\${MANPATH}\"\`:;"
echo "setenv INFOPATH $HOMEBREW_PREFIX/share/info:\$INFOPATH;" echo "setenv INFOPATH $HOMEBREW_PREFIX/share/info\`[ \${?INFOPATH} == 1 ] && echo \":\${INFOPATH}\"\`;"
;; ;;
*) *)
echo "export HOMEBREW_PREFIX=\"$HOMEBREW_PREFIX\";" echo "export HOMEBREW_PREFIX=\"$HOMEBREW_PREFIX\";"

View File

@ -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

View File

@ -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

View File

@ -599,7 +599,6 @@ EOS
-d "$HOMEBREW_LIBRARY/LinkedKegs" || -d "$HOMEBREW_LIBRARY/LinkedKegs" ||
(-n "$HOMEBREW_DEVELOPER" && -z "$HOMEBREW_UPDATE_PREINSTALL") ]] (-n "$HOMEBREW_DEVELOPER" && -z "$HOMEBREW_UPDATE_PREINSTALL") ]]
then then
unset HOMEBREW_RUBY_PATH
brew update-report "$@" brew update-report "$@"
return $? return $?
elif [[ -z "$HOMEBREW_UPDATE_PREINSTALL" ]] elif [[ -z "$HOMEBREW_UPDATE_PREINSTALL" ]]

View File

@ -191,8 +191,8 @@ module Homebrew
end end
oh1 "Upgrading #{Formatter.identifier(f.full_specified_name)} #{upgrade_version} #{fi.options.to_a.join(" ")}" oh1 "Upgrading #{Formatter.identifier(f.full_specified_name)} #{upgrade_version} #{fi.options.to_a.join(" ")}"
fi.fetch
fi.prelude fi.prelude
fi.fetch
# first we unlink the currently active keg for this formula otherwise it is # first we unlink the currently active keg for this formula otherwise it is
# possible for the existing build to interfere with the build we are about to # possible for the existing build to interfere with the build we are about to
@ -216,7 +216,7 @@ module Homebrew
ensure ensure
# restore previous installation state if build failed # restore previous installation state if build failed
begin begin
linked_kegs.each(&:link) unless f.installed? linked_kegs.each(&:link) unless f.latest_version_installed?
rescue rescue
nil nil
end end

View File

@ -101,7 +101,7 @@ module Commands
end end
def official_external_commands_paths 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 = Tap.fetch("Homebrew/#{cmd}")
tap.install unless tap.installed? tap.install unless tap.installed?
external_ruby_v2_cmd_path(cmd) external_ruby_v2_cmd_path(cmd)

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require "compat/cask/dsl/version" require "compat/extend/nil"
require "compat/language/python" require "compat/extend/string"
require "compat/requirements/macos_requirement"
require "compat/formula" require "compat/formula"
require "compat/language/python"
require "compat/os/mac" if OS.mac? require "compat/os/mac" if OS.mac?

View File

@ -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

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
class NilClass
module Compat
def chuzzle
odeprecated "chuzzle", "chomp.presence"
end
end
prepend Compat
end

View 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

View File

@ -3,10 +3,19 @@
class Formula class Formula
module Compat module Compat
def installed? def installed?
# odeprecated "Formula#installed?", odeprecated "Formula#installed?",
# "Formula#latest_version_installed? (or Formula#any_version_installed? )" "Formula#latest_version_installed? (or Formula#any_version_installed? )"
latest_version_installed? latest_version_installed?
end end
def prepare_patches
if respond_to?(:patches)
active_spec.add_legacy_patches(patches)
odeprecated "patches", "patch do"
end
super
end
end end
prepend Compat prepend Compat

View File

@ -5,7 +5,7 @@ module Language
module Cabal module Cabal
module Compat module Compat
def cabal_sandbox(options = {}) def cabal_sandbox(options = {})
# odeprecated "Language::Haskell::Cabal.cabal_sandbox" odeprecated "Language::Haskell::Cabal.cabal_sandbox"
pwd = Pathname.pwd pwd = Pathname.pwd
home = options[:home] || pwd home = options[:home] || pwd
@ -41,14 +41,14 @@ module Language
end end
def cabal_sandbox_add_source(*args) 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 system "cabal", "v1-sandbox", "add-source", *args
end end
def cabal_install(*args) def cabal_install(*args)
# odeprecated "Language::Haskell::Cabal.cabal_install", odeprecated "Language::Haskell::Cabal.cabal_install",
# "cabal v2-install directly with std_cabal_v2_args" "cabal v2-install directly with std_cabal_v2_args"
# cabal hardcodes 64 as the maximum number of parallel jobs # cabal hardcodes 64 as the maximum number of parallel jobs
# https://github.com/Homebrew/legacy-homebrew/issues/49509 # https://github.com/Homebrew/legacy-homebrew/issues/49509
@ -64,13 +64,13 @@ module Language
end end
def cabal_configure(flags) def cabal_configure(flags)
# odeprecated "Language::Haskell::Cabal.cabal_configure" odeprecated "Language::Haskell::Cabal.cabal_configure"
system "cabal", "v1-configure", flags system "cabal", "v1-configure", flags
end end
def cabal_install_tools(*tools) 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 # install tools sequentially, as some tools can depend on other tools
tools.each { |tool| cabal_install tool } tools.each { |tool| cabal_install tool }
@ -81,8 +81,8 @@ module Language
end end
def install_cabal_package(*args, **options) def install_cabal_package(*args, **options)
# odeprecated "Language::Haskell::Cabal.install_cabal_package", odeprecated "Language::Haskell::Cabal.install_cabal_package",
# "cabal v2-update directly followed by v2-install with std_cabal_v2_args" "cabal v2-update directly followed by v2-install with std_cabal_v2_args"
cabal_sandbox do cabal_sandbox do
cabal_install_tools(*options[:using]) if options[:using] cabal_install_tools(*options[:using]) if options[:using]

View File

@ -5,6 +5,8 @@ module Language
class << self class << self
module Compat module Compat
def rewrite_python_shebang(python_path) 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| Pathname.pwd.find do |f|
Utils::Shebang.rewrite_shebang(Shebang.python_shebang_rewrite_info(python_path), f) Utils::Shebang.rewrite_shebang(Shebang.python_shebang_rewrite_info(python_path), f)
end end

View File

@ -5,7 +5,7 @@ module OS
class << self class << self
module Compat module Compat
def preferred_arch 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? if Hardware::CPU.is_64_bit?
Hardware::CPU.arch_64_bit Hardware::CPU.arch_64_bit
else else
@ -14,12 +14,12 @@ module OS
end end
def tcc_db def tcc_db
# odeprecated "MacOS.tcc_db" odeprecated "MacOS.tcc_db"
@tcc_db ||= Pathname.new("/Library/Application Support/com.apple.TCC/TCC.db") @tcc_db ||= Pathname.new("/Library/Application Support/com.apple.TCC/TCC.db")
end end
def pre_mavericks_accessibility_dotfile 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") @pre_mavericks_accessibility_dotfile ||= Pathname.new("/private/var/db/.AccessibilityAPIEnabled")
end end
end end

View File

@ -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

View File

@ -100,16 +100,11 @@ module Homebrew
klass.prune if ignores.include?("recommended?") || dependent.build.without?(dep) klass.prune if ignores.include?("recommended?") || dependent.build.without?(dep)
elsif dep.optional? elsif dep.optional?
klass.prune if !includes.include?("optional?") && !dependent.build.with?(dep) klass.prune if !includes.include?("optional?") && !dependent.build.with?(dep)
elsif dep.test? elsif dep.build? || dep.test?
if includes.include?("test?") keep = false
Dependency.keep_but_prune_recursive_deps if type == :dependencies keep ||= dep.test? && includes.include?("test?") && dependent == formula
elsif dep.build? keep ||= dep.build? && includes.include?("build?")
klass.prune unless includes.include?("build?") klass.prune unless keep
else
klass.prune
end
elsif dep.build?
klass.prune unless includes.include?("build?")
end end
# If a tap isn't installed, we can't find the dependencies of one of # If a tap isn't installed, we can't find the dependencies of one of

View File

@ -89,9 +89,6 @@ class Dependency
deps.each do |dep| deps.each do |dep|
next if dependent.name == dep.name 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) case action(dependent, dep, &block)
when :prune when :prune
next next

View File

@ -3,6 +3,7 @@
require "formula" require "formula"
require "formula_versions" require "formula_versions"
require "utils/curl" require "utils/curl"
require "utils/notability"
require "extend/ENV" require "extend/ENV"
require "formula_cellar_checks" require "formula_cellar_checks"
require "cmd/search" require "cmd/search"
@ -134,19 +135,8 @@ module Homebrew
end end
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 new_formula_problem_count += new_formula_problem_lines.size
puts new_formula_problem_lines.map { |s| " #{s}" } puts new_formula_problem_lines.map { |s| " #{s}" }
end
total_problems_count = problem_count + new_formula_problem_count total_problems_count = problem_count + new_formula_problem_count
problem_plural = "#{total_problems_count} #{"problem".pluralize(total_problems_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 = "#{problem_plural} in #{formula_plural} detected"
errors_summary += ", #{corrected_problem_plural} corrected" if corrected_problem_count.positive? errors_summary += ", #{corrected_problem_plural} corrected" if corrected_problem_count.positive?
if problem_count.positive? || ofail errors_summary if problem_count.positive? || new_formula_problem_count.positive?
(new_formula_problem_count.positive? && !created_pr_comment)
ofail errors_summary
end
end end
def format_problem_lines(problems) def format_problem_lines(problems)
@ -458,9 +445,10 @@ module Homebrew
autoconf@2.13 autoconf@2.13
bash-completion@2 bash-completion@2
gnupg@1.4 gnupg@1.4
libsigc++@2
lua@5.1 lua@5.1
numpy@1.16 numpy@1.16
libsigc++@2 python@3.8
].freeze ].freeze
def audit_versioned_keg_only def audit_versioned_keg_only
@ -524,79 +512,30 @@ module Homebrew
user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*})
return if user.nil? return if user.nil?
begin warning = SharedAudits.github(user, repo)
metadata = GitHub.repository(user, repo) return if warning.nil?
rescue GitHub::HTTPNotFoundError
return
end
return if metadata.nil? new_formula_problem warning
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)"
end end
def audit_gitlab_repository def audit_gitlab_repository
user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*}) user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*})
return if user.nil? return if user.nil?
out, _, status= curl_output("--request", "GET", "https://gitlab.com/api/v4/projects/#{user}%2F#{repo}") warning = SharedAudits.gitlab(user, repo)
return unless status.success? return if warning.nil?
metadata = JSON.parse(out) new_formula_problem warning
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)"
end end
def audit_bitbucket_repository def audit_bitbucket_repository
user, repo = get_repo_data(%r{https?://bitbucket\.org/([^/]+)/([^/]+)/?.*}) user, repo = get_repo_data(%r{https?://bitbucket\.org/([^/]+)/([^/]+)/?.*})
return if user.nil? return if user.nil?
api_url = "https://api.bitbucket.org/2.0/repositories/#{user}/#{repo}" warning = SharedAudits.bitbucket(user, repo)
out, _, status= curl_output("--request", "GET", api_url) return if warning.nil?
return unless status.success?
metadata = JSON.parse(out) new_formula_problem warning
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)"
end end
def get_repo_data(regex) def get_repo_data(regex)
@ -608,7 +547,7 @@ module Homebrew
_, user, repo = *regex.match(formula.homepage) unless user _, user, repo = *regex.match(formula.homepage) unless user
return if !user || !repo return if !user || !repo
repo.gsub!(/.git$/, "") repo.delete_suffix!(".git")
[user, repo] [user, repo]
end end
@ -730,7 +669,7 @@ module Homebrew
.map(&:to_i) .map(&:to_i)
case (url = stable.url) case (url = stable.url)
when /[\d\._-](alpha|beta|rc\d)/ when /[\d._-](alpha|beta|rc\d)/
matched = Regexp.last_match(1) matched = Regexp.last_match(1)
version_prefix = stable_version_string.sub(/\d+$/, "") version_prefix = stable_version_string.sub(/\d+$/, "")
return if UNSTABLE_WHITELIST[formula.name] == version_prefix return if UNSTABLE_WHITELIST[formula.name] == version_prefix
@ -758,7 +697,7 @@ module Homebrew
.second .second
begin 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 prerelease" if release["prerelease"]
problem "#{tag} is a GitHub draft" if release["draft"] problem "#{tag} is a GitHub draft" if release["draft"]
end end
@ -864,7 +803,7 @@ module Homebrew
end end
bin_names.each do |name| bin_names.each do |name|
["system", "shell_output", "pipe_output"].each do |cmd| ["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}") problem %Q(fully scope test #{cmd} calls, e.g. #{cmd} "\#{bin}/#{name}")
end end
end end
@ -984,7 +923,7 @@ module Homebrew
except_audits = @except except_audits = @except
methods.map(&:to_s).grep(/^audit_/).each do |audit_method_name| 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 if only_audits
next unless only_audits.include?(name) next unless only_audits.include?(name)
elsif except_audits elsif except_audits
@ -1052,15 +991,9 @@ module Homebrew
end end
def audit_download_strategy 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) url_strategy = DownloadStrategyDetector.detect(url)
if using == :git || url_strategy == GitDownloadStrategy 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] problem "Git should specify :revision when a :tag is specified." if specs[:tag] && !specs[:revision]
end end

View File

@ -321,7 +321,7 @@ module Homebrew
if any_go_deps if any_go_deps
go_regex = go_regex =
Version.formula_optionally_versioned_regex(:go, full: false) 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 end
relocatable = true relocatable = true

View File

@ -79,7 +79,7 @@ module Homebrew
origin_branch = "#{homebrew_core_remote}/#{homebrew_core_branch}" 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 = Utils.popen_read("git -C \"#{formula.tap.path}\" symbolic-ref -q --short HEAD").chomp
previous_branch = "master" if previous_branch.empty? 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? if args.dry_run?
ohai "git remote add #{homebrew_core_remote} #{homebrew_core_url}" ohai "git remote add #{homebrew_core_remote} #{homebrew_core_url}"
@ -89,7 +89,7 @@ module Homebrew
return tap_full_name, origin_branch, previous_branch return tap_full_name, origin_branch, previous_branch
else else
formula.path.parent.cd do 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" ohai "Adding #{homebrew_core_remote} remote"
safe_system "git", "remote", "add", homebrew_core_remote, homebrew_core_url safe_system "git", "remote", "add", homebrew_core_remote, homebrew_core_url
end end
@ -118,12 +118,6 @@ module Homebrew
formula = args.formulae.first 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 new_url = args.url
if new_url && !formula if new_url && !formula
# Split the new URL on / and find any formulae that have the same URL # Split the new URL on / and find any formulae that have the same URL
@ -152,7 +146,8 @@ module Homebrew
end end
raise FormulaUnspecifiedError unless formula 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? requested_spec, formula_spec = if args.devel?
devel_message = " (devel)" devel_message = " (devel)"
@ -230,7 +225,7 @@ module Homebrew
replacement_pairs += formula_spec.mirrors.map do |mirror| replacement_pairs += formula_spec.mirrors.map do |mirror|
[ [
/ +mirror \"#{Regexp.escape(mirror)}\"\n/m, / +mirror "#{Regexp.escape(mirror)}"\n/m,
"", "",
] ]
end end
@ -263,7 +258,7 @@ module Homebrew
if new_mirrors if new_mirrors
replacement_pairs << [ 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", "\\1\\2\\1mirror \"#{new_mirrors.join("\"\n\\1mirror \"")}\"\n",
] ]
end end
@ -288,30 +283,30 @@ module Homebrew
] ]
elsif new_mirrors 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", "\\1\\2\\1version \"#{forced_version}\"\n",
] ]
else else
[ [
/^( +)(url \"#{Regexp.escape(new_url)}\"\n)/m, /^( +)(url "#{Regexp.escape(new_url)}"\n)/m,
"\\1\\2\\1version \"#{forced_version}\"\n", "\\1\\2\\1version \"#{forced_version}\"\n",
] ]
end end
elsif requested_spec == :devel elsif requested_spec == :devel
replacement_pairs << [ 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", "\\1#{forced_version}\\2",
] ]
end end
elsif forced_version && forced_version == "0" elsif forced_version && forced_version == "0"
if requested_spec == :stable if requested_spec == :stable
replacement_pairs << [ replacement_pairs << [
/^ version \"[\w\.\-\+]+\"\n/m, /^ version "[\w.\-+]+"\n/m,
"", "",
] ]
elsif requested_spec == :devel elsif requested_spec == :devel
replacement_pairs << [ replacement_pairs << [
/( devel do.+?)^ +version \"[^\n]+\"\n(.+?end\n)/m, /( devel do.+?)^ +version "[^\n]+"\n(.+?end\n)/m,
"\\1\\2", "\\1\\2",
] ]
end end

View File

@ -19,7 +19,7 @@ module Homebrew
def irb_args def irb_args
# work around IRB modifying ARGV. # work around IRB modifying ARGV.
Homebrew::CLI::Parser.new(ARGV.dup) do Homebrew::CLI::Parser.new(ARGV.dup.freeze) do
usage_banner <<~EOS usage_banner <<~EOS
`irb` [<options>] `irb` [<options>]
@ -38,7 +38,7 @@ module Homebrew
if args.examples? if args.examples?
puts "'v8'.f # => instance of the v8 formula" 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 ":lua.f.methods - 1.methods"
puts ":mpd.f.recursive_dependencies.reject(&:installed?)" puts ":mpd.f.recursive_dependencies.reject(&:installed?)"
return return

View File

@ -60,7 +60,7 @@ module Homebrew
rescue FormulaUnavailableError rescue FormulaUnavailableError
nil nil
else else
if gnupg.installed? if gnupg.any_version_installed?
path = PATH.new(ENV.fetch("PATH")) path = PATH.new(ENV.fetch("PATH"))
path.prepend(gnupg.installed_prefix/"bin") path.prepend(gnupg.installed_prefix/"bin")
ENV["PATH"] = path ENV["PATH"] = path

View File

@ -15,6 +15,7 @@ module Homebrew
def pull_args def pull_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
hide_from_man_page!
usage_banner <<~EOS usage_banner <<~EOS
`pull` [<options>] <patch> `pull` [<options>] <patch>
@ -43,6 +44,8 @@ module Homebrew
end end
def pull def pull
odeprecated "brew pull", "hub checkout"
odie "You meant `git pull --rebase`." if ARGV[0] == "--rebase" odie "You meant `git pull --rebase`." if ARGV[0] == "--rebase"
pull_args.parse pull_args.parse
@ -56,7 +59,7 @@ module Homebrew
gnupg = Formula["gnupg"] gnupg = Formula["gnupg"]
rescue FormulaUnavailableError # rubocop:disable Lint/SuppressedException rescue FormulaUnavailableError # rubocop:disable Lint/SuppressedException
else else
if gnupg.installed? if gnupg.any_version_installed?
path = PATH.new(ENV.fetch("PATH")) path = PATH.new(ENV.fetch("PATH"))
path.prepend(gnupg.installed_prefix/"bin") path.prepend(gnupg.installed_prefix/"bin")
ENV["PATH"] = path ENV["PATH"] = path
@ -333,7 +336,7 @@ module Homebrew
def check_bintray_mirror(name, url) def check_bintray_mirror(name, url)
headers, = curl_output("--connect-timeout", "15", "--location", "--head", 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") return if status_code.start_with?("2")
opoo "The Bintray mirror #{url} is not reachable (HTTP status code #{status_code})." opoo "The Bintray mirror #{url} is not reachable (HTTP status code #{status_code})."

View File

@ -38,12 +38,6 @@ module Homebrew
Or `brew tap #{tap}` and then `brew install <formula>`. 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 ## Documentation
`brew help`, `man brew` or check [Homebrew's documentation](https://docs.brew.sh). `brew help`, `man brew` or check [Homebrew's documentation](https://docs.brew.sh).
MARKDOWN MARKDOWN

View File

@ -3,6 +3,7 @@
require "keg" require "keg"
require "language/python" require "language/python"
require "formula" require "formula"
require "formulary"
require "version" require "version"
require "development_tools" require "development_tools"
require "utils/shell" require "utils/shell"
@ -832,6 +833,23 @@ module Homebrew
EOS EOS
end 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 def all
methods.map(&:to_s).grep(/^check_/) methods.map(&:to_s).grep(/^check_/)
end end

View File

@ -221,7 +221,7 @@ class AbstractFileDownloadStrategy < AbstractDownloadStrategy
end end
def basename def basename
cached_location.basename.sub(/^[\da-f]{64}\-\-/, "") cached_location.basename.sub(/^[\da-f]{64}--/, "")
end end
private private
@ -390,7 +390,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
filenames = lines.map(&parse_content_disposition).compact filenames = lines.map(&parse_content_disposition).compact
time = time =
lines.map { |line| line[/^Last\-Modified:\s*(.+)/i, 1] } lines.map { |line| line[/^Last-Modified:\s*(.+)/i, 1] }
.compact .compact
.map { |t| t.match?(/^\d+$/) ? Time.at(t.to_i) : Time.parse(t) } .map { |t| t.match?(/^\d+$/) ? Time.at(t.to_i) : Time.parse(t) }
.last .last
@ -820,7 +820,7 @@ class GitHubGitDownloadStrategy < GitDownloadStrategy
return unless status.success? return unless status.success?
commit = output[/^ETag: \"(\h+)\"/, 1] commit = output[/^ETag: "(\h+)"/, 1]
version.update_commit(commit) if commit version.update_commit(commit) if commit
commit commit
end end

View File

@ -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

View File

@ -6,7 +6,7 @@ require "extend/ENV/std"
require "extend/ENV/super" require "extend/ENV/super"
def superenv? def superenv?
ARGV.env != "std" && Superenv.bin Homebrew.args.env != "std" && Superenv.bin
end end
module EnvActivation module EnvActivation

View File

@ -162,7 +162,7 @@ module SharedEnvExtension
# ENV.append_to_cflags "-I ./missing/includes" # ENV.append_to_cflags "-I ./missing/includes"
# end</pre> # end</pre>
def compiler def compiler
@compiler ||= if (cc = ARGV.cc) @compiler ||= if (cc = Homebrew.args.cc)
warn_about_non_apple_gcc($&) if cc =~ GNU_GCC_REGEXP warn_about_non_apple_gcc($&) if cc =~ GNU_GCC_REGEXP
fetch_compiler(cc, "--cc") fetch_compiler(cc, "--cc")
elsif (cc = homebrew_cc) elsif (cc = homebrew_cc)

View File

@ -19,6 +19,8 @@ class Keg
return if !file.elf? || !file.dynamic_elf? return if !file.elf? || !file.dynamic_elf?
patchelf = DevelopmentTools.locate "patchelf" patchelf = DevelopmentTools.locate "patchelf"
odie "Could not locate patchelf, please: brew install patchelf." if patchelf.nil?
cmd_rpath = [patchelf, "--print-rpath", file] cmd_rpath = [patchelf, "--print-rpath", file]
old_rpath = Utils.popen_read(*cmd_rpath, err: :out).strip old_rpath = Utils.popen_read(*cmd_rpath, err: :out).strip

View File

@ -347,12 +347,13 @@ module Homebrew
end end
def check_deprecated_caskroom_taps 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? return if tapped_caskroom_taps.empty?
<<~EOS <<~EOS
You have the following deprecated, cask taps tapped: 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`. Untap them with `brew untap`.
EOS EOS
end end

View File

@ -81,7 +81,7 @@ module Stdenv
prepend "LDFLAGS", "-L#{HOMEBREW_PREFIX}/lib" prepend "LDFLAGS", "-L#{HOMEBREW_PREFIX}/lib"
sdk = formula ? MacOS.sdk_for_formula(formula, version) : MacOS.sdk(version) 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 sdk = sdk.path

View File

@ -108,7 +108,7 @@ module Superenv
# @private # @private
def setup_build_environment(formula = nil) def setup_build_environment(formula = nil)
sdk = formula ? MacOS.sdk_for_formula(formula) : MacOS.sdk 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_SDKROOT"] = sdk.path
self["HOMEBREW_DEVELOPER_DIR"] = if sdk.source == :xcode self["HOMEBREW_DEVELOPER_DIR"] = if sdk.source == :xcode
MacOS::Xcode.prefix MacOS::Xcode.prefix

View File

@ -106,10 +106,12 @@ class Keg
bad_name.sub(PREFIX_PLACEHOLDER, HOMEBREW_PREFIX) bad_name.sub(PREFIX_PLACEHOLDER, HOMEBREW_PREFIX)
elsif bad_name.start_with? CELLAR_PLACEHOLDER elsif bad_name.start_with? CELLAR_PLACEHOLDER
bad_name.sub(CELLAR_PLACEHOLDER, HOMEBREW_CELLAR) 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}" "@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}" "#{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"] elsif bad_name.start_with?("@rpath") && ENV["HOMEBREW_RELOCATE_METAVARS"]
expand_rpath file, bad_name expand_rpath file, bad_name
elsif (abs_name = find_dylib(bad_name)) && abs_name.exist? elsif (abs_name = find_dylib(bad_name)) && abs_name.exist?

View File

@ -224,7 +224,7 @@ class Pathname
return archive_ext if archive_ext return archive_ext if archive_ext
# Don't treat version numbers as extname. # 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) File.extname(basename)
end end
@ -398,15 +398,6 @@ class Pathname
basename.to_s == ".DS_Store" basename.to_s == ".DS_Store"
end 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? def binary_executable?
false false
end end

View File

@ -2,21 +2,6 @@
require "active_support/core_ext/object/blank" 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`). # Used by the inreplace function (in `utils.rb`).
module StringInreplaceExtension module StringInreplaceExtension
attr_accessor :errors attr_accessor :errors
@ -41,7 +26,7 @@ module StringInreplaceExtension
# Looks for Makefile style variable definitions and replaces the # Looks for Makefile style variable definitions and replaces the
# value with "new_value", or removes the definition entirely. # value with "new_value", or removes the definition entirely.
def change_make_var!(flag, new_value) 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}" errors << "expected to change #{flag.inspect} to #{new_value.inspect}"
end end
@ -50,7 +35,7 @@ module StringInreplaceExtension
def remove_make_var!(flags) def remove_make_var!(flags)
Array(flags).each do |flag| Array(flags).each do |flag|
# Also remove trailing \n, if present. # 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}" errors << "expected to remove #{flag.inspect}"
end end
end end
@ -58,6 +43,6 @@ module StringInreplaceExtension
# Finds the specified variable # Finds the specified variable
def get_make_var(flag) def get_make_var(flag)
self[/^#{Regexp.escape(flag)}[ \t]*[\\?\+\:\!]?=[ \t]*((?:.*\\\n)*.*)$/, 1] self[/^#{Regexp.escape(flag)}[ \t]*[\\?+:!]?=[ \t]*((?:.*\\\n)*.*)$/, 1]
end end
end end

View File

@ -1172,7 +1172,7 @@ class Formula
begin begin
yield self, staging yield self, staging
rescue rescue
staging.retain! if Homebrew.args.interactive? || ARGV.debug? staging.retain! if Homebrew.args.interactive? || Homebrew.args.debug?
raise raise
ensure ensure
cp Dir["config.log", "CMakeCache.txt"], logs cp Dir["config.log", "CMakeCache.txt"], logs
@ -1822,7 +1822,7 @@ class Formula
end end
end end
rescue Exception # rubocop:disable Lint/RescueException rescue Exception # rubocop:disable Lint/RescueException
staging.retain! if ARGV.debug? staging.retain! if Homebrew.args.debug?
raise raise
end end
end end
@ -2090,7 +2090,6 @@ class Formula
private private
def prepare_patches def prepare_patches
active_spec.add_legacy_patches(patches) if respond_to?(:patches)
patchlist.grep(DATAPatch) { |p| p.path = path } patchlist.grep(DATAPatch) { |p| p.path = path }
end end
@ -2171,7 +2170,10 @@ class Formula
raise "You cannot override Formula#brew in class #{name}" raise "You cannot override Formula#brew in class #{name}"
when :test when :test
define_method(:test_defined?) { true } define_method(:test_defined?) { true }
when :patches
odeprecated "a Formula#patches definition", "'patch do' block calls"
when :options when :options
odeprecated "a Formula#options definition", "'option do' block calls"
instance = allocate instance = allocate
specs.each do |spec| specs.each do |spec|
@ -2385,6 +2387,7 @@ class Formula
@devel ||= SoftwareSpec.new @devel ||= SoftwareSpec.new
return @devel unless block_given? return @devel unless block_given?
odeprecated "'devel' blocks in formulae", "'head' blocks or @-versioned formulae"
@devel.instance_eval(&block) @devel.instance_eval(&block)
end end
@ -2668,7 +2671,7 @@ class Formula
# regex /foo-(\d+(?:\.\d+)+)\.tar/ # regex /foo-(\d+(?:\.\d+)+)\.tar/
# end</pre> # end</pre>
def livecheck(&block) def livecheck(&block)
@livecheck ||= Livecheck.new @livecheck ||= Livecheck.new(self)
return @livecheck unless block_given? return @livecheck unless block_given?
@livecheckable = true @livecheckable = true

View File

@ -59,7 +59,7 @@ class FormulaInstaller
@git = false @git = false
@verbose = Homebrew.args.verbose? @verbose = Homebrew.args.verbose?
@quiet = Homebrew.args.quiet? @quiet = Homebrew.args.quiet?
@debug = ARGV.debug? @debug = Homebrew.args.debug?
@installed_as_dependency = false @installed_as_dependency = false
@installed_on_request = true @installed_on_request = true
@options = Options.new @options = Options.new
@ -100,7 +100,7 @@ class FormulaInstaller
return false if !formula.bottled? && !formula.local_bottle_path return false if !formula.bottled? && !formula.local_bottle_path
return true if force_bottle? return true if force_bottle?
return false if build_from_source? || build_bottle? || interactive? 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 unless options.empty?
return false if formula.bottle_disabled? return false if formula.bottle_disabled?
@ -141,7 +141,6 @@ class FormulaInstaller
def prelude def prelude
Tab.clear_cache Tab.clear_cache
verify_deps_exist unless ignore_deps? verify_deps_exist unless ignore_deps?
lock
check_install_sanity check_install_sanity
end end
@ -221,6 +220,8 @@ class FormulaInstaller
end end
def install def install
lock
start_time = Time.now start_time = Time.now
if !formula.bottle_unneeded? && !pour_bottle? && DevelopmentTools.installed? if !formula.bottle_unneeded? && !pour_bottle? && DevelopmentTools.installed?
Homebrew::Install.perform_build_from_source_checks Homebrew::Install.perform_build_from_source_checks
@ -417,7 +418,7 @@ class FormulaInstaller
req_map.each_pair do |dependent, reqs| req_map.each_pair do |dependent, reqs|
reqs.each do |req| 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}" @requirement_messages << "#{dependent}: #{req.message}"
fatals << req if req.fatal? fatals << req if req.fatal?
@ -453,13 +454,16 @@ class FormulaInstaller
build = effective_build_options_for(dependent) build = effective_build_options_for(dependent)
install_bottle_for_dependent = install_bottle_for?(dependent, build) 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) if req.prune_from_option?(build)
Requirement.prune Requirement.prune
elsif req.satisfied? elsif req.satisfied?
Requirement.prune Requirement.prune
elsif include_test? && req.test? elsif (req.build? || req.test?) && !keep_build_test
next
elsif !runtime_requirements.include?(req) && install_bottle_for_dependent
Requirement.prune Requirement.prune
elsif (dep = formula_deps_map[dependent.name]) && dep.build? elsif (dep = formula_deps_map[dependent.name]) && dep.build?
Requirement.prune Requirement.prune
@ -486,13 +490,13 @@ class FormulaInstaller
inherited_options.fetch(dependent.name, []), 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) if dep.prune_from_option?(build)
Dependency.prune Dependency.prune
elsif dep.test? && !dep.build? && !include_test? elsif (dep.build? || dep.test?) && !keep_build_test
Dependency.prune
elsif dep.build? && !dep.test? && install_bottle_for?(dependent, build)
Dependency.prune
elsif dep.prune_if_build_and_not_dependent?(dependent)
Dependency.prune Dependency.prune
elsif dep.satisfied?(inherited_options[dep.name]) elsif dep.satisfied?(inherited_options[dep.name])
Dependency.skip Dependency.skip
@ -568,6 +572,7 @@ class FormulaInstaller
fi.build_from_source = Homebrew.args.build_formula_from_source?(df) fi.build_from_source = Homebrew.args.build_formula_from_source?(df)
fi.force_bottle = false fi.force_bottle = false
fi.include_test = Homebrew.args.include_formula_test_deps?(df)
fi.verbose = verbose? fi.verbose = verbose?
fi.quiet = quiet? fi.quiet = quiet?
fi.debug = debug? fi.debug = debug?
@ -589,7 +594,7 @@ class FormulaInstaller
linked_keg.unlink linked_keg.unlink
end end
if df.installed? if df.latest_version_installed?
installed_keg = Keg.new(df.prefix) installed_keg = Keg.new(df.prefix)
tmp_keg = Pathname.new("#{installed_keg}.tmp") tmp_keg = Pathname.new("#{installed_keg}.tmp")
installed_keg.rename(tmp_keg) installed_keg.rename(tmp_keg)
@ -610,6 +615,7 @@ class FormulaInstaller
fi.options &= df.options fi.options &= df.options
fi.build_from_source = Homebrew.args.build_formula_from_source?(df) fi.build_from_source = Homebrew.args.build_formula_from_source?(df)
fi.force_bottle = false fi.force_bottle = false
fi.include_test = Homebrew.args.include_formula_test_deps?(df)
fi.verbose = verbose? fi.verbose = verbose?
fi.quiet = quiet? fi.quiet = quiet?
fi.debug = debug? fi.debug = debug?
@ -723,11 +729,11 @@ class FormulaInstaller
args << "--interactive" if interactive? args << "--interactive" if interactive?
args << "--verbose" if verbose? args << "--verbose" if verbose?
args << "--debug" if debug? 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? args << "--keep-tmp" if Homebrew.args.keep_tmp?
if ARGV.env if Homebrew.args.env.present?
args << "--env=#{ARGV.env}" args << "--env=#{Homebrew.args.env}"
elsif formula.env.std? || formula.deps.select(&:build?).any? { |d| d.name == "scons" } elsif formula.env.std? || formula.deps.select(&:build?).any? { |d| d.name == "scons" }
args << "--env=std" args << "--env=std"
end end
@ -740,7 +746,7 @@ class FormulaInstaller
formula.options.each do |opt| formula.options.each do |opt|
name = opt.name[/^([^=]+)=$/, 1] name = opt.name[/^([^=]+)=$/, 1]
value = ARGV.value(name) if name value = Homebrew.args.value(name) if name
args << "--#{name}=#{value}" if value args << "--#{name}=#{value}" if value
end end
@ -964,9 +970,10 @@ class FormulaInstaller
end end
def fetch_dependencies 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) } deps.each { |dep, _options| fetch_dependency(dep) }
end end

View File

@ -44,7 +44,7 @@ class FormulaVersions
rescue *IGNORED_EXCEPTIONS => e rescue *IGNORED_EXCEPTIONS => e
# We rescue these so that we can skip bad versions and # We rescue these so that we can skip bad versions and
# continue walking the history # 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 rescue FormulaUnavailableError
nil nil
ensure ensure

View File

@ -9,6 +9,8 @@ require "extend/cachable"
module Formulary module Formulary
extend Cachable extend Cachable
URL_START_REGEX = %r{(https?|ftp|file)://}.freeze
def self.enable_factory_cache! def self.enable_factory_cache!
@factory_cache = true @factory_cache = true
end end
@ -130,7 +132,7 @@ module Formulary
private private
def load_file 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? raise FormulaUnavailableError, name unless path.file?
Formulary.load_formula_from_path(name, path) Formulary.load_formula_from_path(name, path)
@ -141,7 +143,7 @@ module Formulary
class BottleLoader < FormulaLoader class BottleLoader < FormulaLoader
def initialize(bottle_name) def initialize(bottle_name)
case 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. # The name of the formula is found between the last slash and the last hyphen.
formula_name = File.basename(bottle_name)[/(.+)-/, 1] formula_name = File.basename(bottle_name)[/(.+)-/, 1]
resource = Resource.new(formula_name) { url bottle_name } resource = Resource.new(formula_name) { url bottle_name }
@ -205,21 +207,20 @@ module Formulary
def load_file def load_file
if url =~ %r{githubusercontent.com/[\w-]+/[\w-]+/[a-f0-9]{40}(/Formula)?/([\w+-.@]+).rb} if url =~ %r{githubusercontent.com/[\w-]+/[\w-]+/[a-f0-9]{40}(/Formula)?/([\w+-.@]+).rb}
formula_name = Regexp.last_match(2) formula_name = Regexp.last_match(2)
opoo <<~EOS odeprecated "Installation of #{formula_name} from a GitHub commit URL",
Unsupported installation from a commit URL! "'brew extract #{formula_name}' to stable tap on GitHub"
Consider using `brew extract #{formula_name} ...` instead!" elsif url.match?(%r{^(https?|ftp)://})
This will extract your desired #{formula_name} version to a stable tap instead of odeprecated "Non-checksummed download of #{name} formula file from an arbitrary URL",
installing from a commit URL that cannnot receive updates or fixes! "'brew extract' or 'brew create' and 'brew tap-new' to create a "\
"formula file in a tap on GitHub"
EOS
end end
HOMEBREW_CACHE_FORMULA.mkpath HOMEBREW_CACHE_FORMULA.mkpath
FileUtils.rm_f(path) FileUtils.rm_f(path)
curl_download url, to: path curl_download url, to: path
super super
rescue MethodDeprecatedError => e rescue MethodDeprecatedError => e
if url =~ %r{github.com/([\w-]+)/homebrew-([\w-]+)/} if url =~ %r{github.com/([\w-]+)/([\w-]+)/}
e.issues_url = "https://github.com/#{Regexp.last_match(1)}/homebrew-#{Regexp.last_match(2)}/issues/new" e.issues_url = "https://github.com/#{Regexp.last_match(1)}/#{Regexp.last_match(2)}/issues/new"
end end
raise raise
end end
@ -307,7 +308,7 @@ module Formulary
end end
def klass 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)}" namespace = "FormulaNamespace#{Digest::MD5.hexdigest(contents)}"
Formulary.load_formula(name, path, contents, namespace) Formulary.load_formula(name, path, contents, namespace)
end end
@ -418,7 +419,7 @@ module Formulary
case ref case ref
when Pathname::BOTTLE_EXTNAME_RX when Pathname::BOTTLE_EXTNAME_RX
return BottleLoader.new(ref) return BottleLoader.new(ref)
when %r{(https?|ftp|file)://} when URL_START_REGEX
return FromUrlLoader.new(ref) return FromUrlLoader.new(ref)
when HOMEBREW_TAP_FORMULA_REGEX when HOMEBREW_TAP_FORMULA_REGEX
return TapLoader.new(ref, from: from) return TapLoader.new(ref, from: from)
@ -483,20 +484,4 @@ module Formulary
]).find(&:file?) ]).find(&:file?)
end.compact end.compact
end 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 end

View File

@ -35,13 +35,10 @@ require "env_config"
require "config" require "config"
require "os" require "os"
require "extend/ARGV"
require "cli/args" require "cli/args"
require "messages" require "messages"
require "system_command" require "system_command"
ARGV.extend(HomebrewArgvExtension)
HOMEBREW_PRODUCT = ENV["HOMEBREW_PRODUCT"] HOMEBREW_PRODUCT = ENV["HOMEBREW_PRODUCT"]
HOMEBREW_VERSION = ENV["HOMEBREW_VERSION"] HOMEBREW_VERSION = ENV["HOMEBREW_VERSION"]
HOMEBREW_WWW = "https://brew.sh" HOMEBREW_WWW = "https://brew.sh"

View File

@ -103,7 +103,7 @@ module Homebrew
help_lines = command_help_lines(path) help_lines = command_help_lines(path)
return if help_lines.blank? 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("@hide_from_man_page ", "")
.sub(/^\* /, "#{Tty.bold}Usage: brew#{Tty.reset} ") .sub(/^\* /, "#{Tty.bold}Usage: brew#{Tty.reset} ")
.gsub(/`(.*?)`/m, "#{Tty.bold}\\1#{Tty.reset}") .gsub(/`(.*?)`/m, "#{Tty.bold}\\1#{Tty.reset}")

View File

@ -37,11 +37,11 @@ module Homebrew
end end
def check_cc_argv def check_cc_argv
return unless ARGV.cc return unless Homebrew.args.cc
@checks ||= Diagnostic::Checks.new @checks ||= Diagnostic::Checks.new
opoo <<~EOS opoo <<~EOS
You passed `--cc=#{ARGV.cc}`. You passed `--cc=#{Homebrew.args.cc}`.
#{@checks.please_create_pull_requests} #{@checks.please_create_pull_requests}
EOS EOS
end end

View File

@ -117,6 +117,10 @@ class Keg
path/"lib" path/"lib"
end end
def libexec
path/"libexec"
end
def text_files def text_files
text_files = [] text_files = []
return text_files unless which("file") && which("xargs") return text_files unless which("file") && which("xargs")

View File

@ -33,7 +33,7 @@ module Language
next if build.without? python_formula.to_s next if build.without? python_formula.to_s
version = major_minor_version python version = major_minor_version python
ENV["PYTHONPATH"] = if python_formula.installed? ENV["PYTHONPATH"] = if python_formula.latest_version_installed?
nil nil
else else
homebrew_site_packages(python) homebrew_site_packages(python)

View File

@ -10,7 +10,8 @@ class Livecheck
# e.g. `Not maintained` # e.g. `Not maintained`
attr_reader :skip_msg attr_reader :skip_msg
def initialize def initialize(formula)
@formula = formula
@regex = nil @regex = nil
@skip = false @skip = false
@skip_msg = nil @skip_msg = nil
@ -44,7 +45,14 @@ class Livecheck
def url(val = nil) def url(val = nil)
return @url if 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 end
# Returns a Hash of all instance variable values. # Returns a Hash of all instance variable values.

View File

@ -8,7 +8,7 @@ class Locale
REGION_REGEX = /(?:[A-Z]{2}|\d{3})/.freeze # ISO 3166-1 or UN M.49 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 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) def self.parse(string)
string = string.to_s string = string.to_s
@ -16,7 +16,7 @@ class Locale
raise ParserError, "'#{string}' cannot be parsed to a #{self}" unless string.match?(LOCALE_REGEX) raise ParserError, "'#{string}' cannot be parsed to a #{self}" unless string.match?(LOCALE_REGEX)
scan = proc do |regex| scan = proc do |regex|
string.scan(/(?:\-|^)(#{regex})(?:\-|$)/).flatten.first string.scan(/(?:-|^)(#{regex})(?:-|$)/).flatten.first
end end
language = scan.call(LANGUAGE_REGEX) language = scan.call(LANGUAGE_REGEX)

View File

@ -97,11 +97,9 @@ can take several different forms:
You can still access these formulae by using a special syntax, e.g. You can still access these formulae by using a special syntax, e.g.
`homebrew/dupes/vim` or `homebrew/versions/node4`. `homebrew/dupes/vim` or `homebrew/versions/node4`.
* An arbitrary file or URL: * An arbitrary file:
Homebrew can install formulae via URL, e.g. Homebrew can install formulae from a local path. It can point to either a
`https://raw.githubusercontent.com/Homebrew/homebrew-core/master/Formula/git.rb`, formula file or a bottle.
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.
## ENVIRONMENT ## ENVIRONMENT

View File

@ -209,7 +209,7 @@ class Migrator
rescue Exception => e # rubocop:disable Lint/RescueException rescue Exception => e # rubocop:disable Lint/RescueException
onoe "Error occurred while migrating." onoe "Error occurred while migrating."
puts e puts e
puts e.backtrace if ARGV.debug? puts e.backtrace if Homebrew.args.debug?
puts "Backing up..." puts "Backing up..."
ignore_interrupts { backup_oldname } ignore_interrupts { backup_oldname }
ensure ensure
@ -318,7 +318,7 @@ class Migrator
rescue Exception => e # rubocop:disable Lint/RescueException rescue Exception => e # rubocop:disable Lint/RescueException
onoe "An unexpected error occurred during linking" onoe "An unexpected error occurred during linking"
puts e puts e
puts e.backtrace if ARGV.debug? puts e.backtrace if Homebrew.args.debug?
ignore_interrupts { new_keg.unlink } ignore_interrupts { new_keg.unlink }
raise raise
end end

View File

@ -42,11 +42,7 @@ module OS
end end
def languages def languages
@languages ||= [ @languages ||= [*ENV["LANG"]&.slice(/[a-z]+/)].uniq
*ARGV.value("language")&.split(","),
*ENV["HOMEBREW_LANGUAGES"]&.split(","),
*ENV["LANG"]&.slice(/[a-z]+/),
].uniq
end end
def language def language

View File

@ -60,9 +60,11 @@ module OS
def languages def languages
@languages ||= [ @languages ||= [
*ARGV.value("language")&.split(","), *Homebrew.args.value("language")&.split(","),
*ENV["HOMEBREW_LANGUAGES"]&.split(","), *ENV["HOMEBREW_LANGUAGES"]&.split(","),
*Open3.capture2("defaults", "read", "-g", "AppleLanguages")[0].scan(/[^ \n"(),]+/), *Open3.capture2("defaults", "read", "-g", "AppleLanguages")
.first
.scan(/[^ \n"(),]+/),
].uniq ].uniq
end end

View File

@ -5,7 +5,7 @@ class Keg
return if file.dylib_id == id return if file.dylib_id == id
@require_relocation = true @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) MachO::Tools.change_dylib_id(file, id, strict: false)
rescue MachO::MachOError rescue MachO::MachOError
onoe <<~EOS onoe <<~EOS
@ -20,7 +20,7 @@ class Keg
return if old == new return if old == new
@require_relocation = true @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) MachO::Tools.change_install_name(file, old, new, strict: false)
rescue MachO::MachOError rescue MachO::MachOError
onoe <<~EOS onoe <<~EOS

View File

@ -169,6 +169,7 @@ end
# Legacy patches have no checksum and are not cached. # Legacy patches have no checksum and are not cached.
class LegacyPatch < ExternalPatch class LegacyPatch < ExternalPatch
def initialize(strip, url) def initialize(strip, url)
odeprecated "legacy patches", "'patch do' blocks"
super(strip) super(strip)
resource.url(url) resource.url(url)
resource.download_strategy = CurlDownloadStrategy resource.download_strategy = CurlDownloadStrategy

View File

@ -35,8 +35,8 @@ module Homebrew
fi.installed_as_dependency = tab.installed_as_dependency fi.installed_as_dependency = tab.installed_as_dependency
fi.installed_on_request = tab.installed_on_request fi.installed_on_request = tab.installed_on_request
end end
fi.fetch
fi.prelude fi.prelude
fi.fetch
oh1 "Reinstalling #{Formatter.identifier(f.full_name)} #{options.to_a.join " "}" oh1 "Reinstalling #{Formatter.identifier(f.full_name)} #{options.to_a.join " "}"

View File

@ -111,7 +111,7 @@ class JavaRequirement < Requirement
rescue FormulaUnavailableError rescue FormulaUnavailableError
nil nil
end end
javas << jdk.bin/"java" if jdk&.installed? javas << jdk.bin/"java" if jdk&.latest_version_installed?
javas << which("java") javas << which("java")
javas javas
end end

View File

@ -72,7 +72,7 @@ class Resource
# directory. Subclasses that override stage should implement the tmp # directory. Subclasses that override stage should implement the tmp
# dir using {Mktemp} so that works with all subtypes. # dir using {Mktemp} so that works with all subtypes.
def stage(target = nil, &block) 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 prepare_patches
fetch_patches(skip_downloaded: true) fetch_patches(skip_downloaded: true)

View File

@ -129,7 +129,7 @@ module RuboCop
string = stanza.stanza_node.children[2] string = stanza.stanza_node.children[2]
return string.str_content if string.str_type? 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 end
def url_match_homepage?(stanza) def url_match_homepage?(stanza)

View File

@ -10,6 +10,11 @@ module RuboCop
# - `component_precedence_list` has component hierarchy in a nested list # - `component_precedence_list` has component hierarchy in a nested list
# where each sub array contains components' details which are at same precedence level # where each sub array contains components' details which are at same precedence level
class ComponentsOrder < FormulaCop 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) def audit_formula(_node, _class_node, _parent_class_node, body_node)
component_precedence_list = [ component_precedence_list = [
[{ name: :include, type: :method_call }], [{ name: :include, type: :method_call }],
@ -34,6 +39,8 @@ module RuboCop
[{ name: :deprecated_option, type: :method_call }], [{ name: :deprecated_option, type: :method_call }],
[{ name: :depends_on, type: :method_call }], [{ name: :depends_on, type: :method_call }],
[{ name: :uses_from_macos, 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: :conflicts_with, type: :method_call }],
[{ name: :skip_clean, type: :method_call }], [{ name: :skip_clean, type: :method_call }],
[{ name: :cxxstdlib_check, type: :method_call }], [{ name: :cxxstdlib_check, type: :method_call }],
@ -49,50 +56,115 @@ module RuboCop
[{ name: :test, type: :block_call }], [{ name: :test, type: :block_call }],
] ]
@present_components = component_precedence_list.map do |components| @present_components, @offensive_nodes = check_order(component_precedence_list, body_node)
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?)
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?
@present_components.drop(p_idx + 1).each do |succeeding_component|
next if succeeding_component.empty?
@offensive_nodes = check_precedence(preceding_component, succeeding_component)
component_problem @offensive_nodes[0], @offensive_nodes[1] if @offensive_nodes 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_on_os_block_content(component_precedence_list, on_macos_blocks.first) if on_macos_blocks.any?
on_linux_blocks = find_blocks(body_node, :on_linux)
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 end
end end
# `aspell`: options and resources should be grouped by language def check_on_os_block_content(component_precedence_list, on_os_block)
WHITELIST = %w[ _, offensive_node = check_order(component_precedence_list, on_os_block.body)
aspell component_problem(*offensive_node) if offensive_node
].freeze 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 valid_node ||= child.method_name.to_s == "patch"
def component_problem(c1, c2) valid_node ||= child.method_name.to_s == "resource"
return if WHITELIST.include?(@formula_name)
problem "`#{format_component(c1)}` (line #{line_number(c1)}) " \ @offensive_node = on_os_block
"should be put before `#{format_component(c2)}` " \ @offense_source_range = on_os_block.source_range
"(line #{line_number(c2)})" unless valid_node
problem "`#{on_os_block.method_name}` can only include `depends_on`, `patch` and `resource` nodes."
end
end
end end
# autocorrect method gets called just after component_problem method call # autocorrect method gets called just after component_problem method call
def autocorrect(_node) def autocorrect(_node)
return if @offensive_nodes.nil?
succeeding_node = @offensive_nodes[0] succeeding_node = @offensive_nodes[0]
preceding_node = @offensive_nodes[1] preceding_node = @offensive_nodes[1]
lambda do |corrector| lambda do |corrector|
@ -130,6 +202,52 @@ module RuboCop
return [idx, comp.index(node1), comp] if comp.member?(node1) return [idx, comp.index(node1), comp] if comp.member?(node1)
end end
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 end
end end

View File

@ -153,7 +153,7 @@ module RuboCop
find_instance_method_call(body_node, :build, :include?) do |method| find_instance_method_call(body_node, :build, :include?) do |method|
arg = parameters(method).first arg = parameters(method).first
next unless match = regex_match_group(arg, /^\-\-(.*)$/) next unless match = regex_match_group(arg, /^--(.*)$/)
problem "Reference '#{match[1]}' without dashes" problem "Reference '#{match[1]}' without dashes"
end end
@ -403,7 +403,7 @@ module RuboCop
path = parameters(method).first path = parameters(method).first
next unless path.str_type? 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]}\"" problem "Dir([\"#{string_content(path)}\"]) is unnecessary; just use \"#{match[0]}\""
end end

View File

@ -13,11 +13,12 @@ module RuboCop
https://downloads.sourceforge.net/project/bittwist/ https://downloads.sourceforge.net/project/bittwist/
https://downloads.sourceforge.net/project/launch4j/ https://downloads.sourceforge.net/project/launch4j/
https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard/archive/ 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://github.com/sindresorhus/macos-wallpaper/archive/
https://raw.githubusercontent.com/liyanage/macosx-shell-scripts/ https://raw.githubusercontent.com/liyanage/macosx-shell-scripts/
https://osxbook.com/book/bonus/chapter8/core/download/gcore https://osxbook.com/book/bonus/chapter8/core/download/gcore
https://naif.jpl.nasa.gov/pub/naif/toolkit/C/MacIntel_OSX_AppleC_64bit/packages/ https://naif.jpl.nasa.gov/pub/naif/toolkit/C/MacIntel_OSX_AppleC_64bit/packages/
https://artifacts.videolan.org/x264/release-macos/
].freeze ].freeze
# These are formulae that, sadly, require an upstream binary to bootstrap. # 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) urls = find_every_func_call_by_name(body_node, :url)
mirrors = find_every_func_call_by_name(body_node, :mirror) 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 urls; doesn't apply to mirrors
gnu_pattern = %r{^(?:https?|ftp)://ftpmirror.gnu.org/(.*)} gnu_pattern = %r{^(?:https?|ftp)://ftpmirror.gnu.org/(.*)}
audit_urls(urls, gnu_pattern) do |match, url| 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 apache_pattern = %r{^https?://(?:[^/]*\.)?apache\.org/(?:dyn/closer\.cgi\?path=/?|dist/)(.*)}i
audit_urls(urls, apache_pattern) do |match, url| 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]}`" problem "#{url} should be `https://www.apache.org/dyn/closer.lua?path=#{match[1]}`"
end 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| audit_urls(mirrors, /.*/) do |_, mirror|
urls.each do |url| urls.each do |url|
url_string = string_content(parameters(url).first) 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") 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})." problem "Use https://downloads.sourceforge.net to get geolocation (url is #{url})."
end end
@ -220,7 +239,7 @@ module RuboCop
# Use new-style archive downloads # Use new-style archive downloads
archive_gh_pattern = %r{https://.*github.*/(?:tar|zip)ball/} archive_gh_pattern = %r{https://.*github.*/(?:tar|zip)ball/}
audit_urls(urls, archive_gh_pattern) do |_, url| 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})." problem "Use /archive/ URLs for GitHub tarballs (url is #{url})."
end end

View File

@ -221,6 +221,7 @@ class SoftwareSpec
end end
end end
# TODO
def add_legacy_patches(list) def add_legacy_patches(list)
list = Patch.normalize_legacy_patches(list) list = Patch.normalize_legacy_patches(list)
list.each { |p| p.owner = self } list.each { |p| p.owner = self }

View File

@ -77,7 +77,7 @@ module Homebrew
case output_type case output_type
when :print when :print
args << "--debug" if ARGV.debug? args << "--debug" if Homebrew.args.debug?
args << "--display-cop-names" if Homebrew.args.display_cop_names? args << "--display-cop-names" if Homebrew.args.display_cop_names?
args << "--format" << "simple" if files args << "--format" << "simple" if files
system(cache_env, "rubocop", *args) system(cache_env, "rubocop", *args)

View File

@ -34,7 +34,7 @@ class SystemCommand
end end
def run! 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 = [] @output = []

View File

@ -88,7 +88,7 @@ class SystemConfig
_, err, status = system_command("java", args: ["-version"], print_stderr: false) _, err, status = system_command("java", args: ["-version"], print_stderr: false)
return "N/A" unless status.success? return "N/A" unless status.success?
err[/java version "([\d\._]+)"/, 1] || "N/A" err[/java version "([\d._]+)"/, 1] || "N/A"
end end
def describe_git def describe_git
@ -100,7 +100,7 @@ class SystemConfig
def describe_curl def describe_curl
out, = system_command(curl_executable, args: ["--version"]) out, = system_command(curl_executable, args: ["--version"])
if /^curl (?<curl_version>[\d\.]+)/ =~ out if /^curl (?<curl_version>[\d.]+)/ =~ out
"#{curl_version} => #{curl_executable}" "#{curl_version} => #{curl_executable}"
else else
"N/A" "N/A"

View File

@ -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

View File

@ -39,11 +39,11 @@ describe Cask::Audit, :cask do
let(:cask) { instance_double(Cask::Cask) } let(:cask) { instance_double(Cask::Cask) }
let(:download) { false } let(:download) { false }
let(:check_token_conflicts) { false } let(:token_conflicts) { false }
let(:fake_system_command) { class_double(SystemCommand) } let(:fake_system_command) { class_double(SystemCommand) }
let(:audit) { let(:audit) {
described_class.new(cask, download: download, described_class.new(cask, download: download,
check_token_conflicts: check_token_conflicts, token_conflicts: token_conflicts,
command: fake_system_command) command: fake_system_command)
} }
@ -517,7 +517,7 @@ describe Cask::Audit, :cask do
describe "token conflicts" do describe "token conflicts" do
let(:cask_token) { "with-binary" } let(:cask_token) { "with-binary" }
let(:check_token_conflicts) { true } let(:token_conflicts) { true }
context "when cask token conflicts with a core formula" do context "when cask token conflicts with a core formula" do
let(:formula_names) { %w[with-binary other-formula] } let(:formula_names) { %w[with-binary other-formula] }

View File

@ -21,7 +21,13 @@ describe Cask::Cmd::Audit, :cask do
expect(Cask::CaskLoader).to receive(:load).with(cask_token).and_return(cask) expect(Cask::CaskLoader).to receive(:load).with(cask_token).and_return(cask)
expect(Cask::Auditor).to receive(:audit) 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) .and_return(true)
described_class.run(cask_token) described_class.run(cask_token)
@ -32,7 +38,13 @@ describe Cask::Cmd::Audit, :cask do
it "does not download the Cask per default" do it "does not download the Cask per default" do
allow(Cask::CaskLoader).to receive(:load).and_return(cask) allow(Cask::CaskLoader).to receive(:load).and_return(cask)
expect(Cask::Auditor).to receive(:audit) 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) .and_return(true)
described_class.run("casktoken") described_class.run("casktoken")
@ -41,7 +53,13 @@ describe Cask::Cmd::Audit, :cask do
it "download a Cask if --download flag is set" do it "download a Cask if --download flag is set" do
allow(Cask::CaskLoader).to receive(:load).and_return(cask) allow(Cask::CaskLoader).to receive(:load).and_return(cask)
expect(Cask::Auditor).to receive(:audit) 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) .and_return(true)
described_class.run("casktoken", "--download") 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 it "does not check for token conflicts per default" do
allow(Cask::CaskLoader).to receive(:load).and_return(cask) allow(Cask::CaskLoader).to receive(:load).and_return(cask)
expect(Cask::Auditor).to receive(:audit) 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) .and_return(true)
described_class.run("casktoken") 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 it "checks for token conflicts if --token-conflicts flag is set" do
allow(Cask::CaskLoader).to receive(:load).and_return(cask) allow(Cask::CaskLoader).to receive(:load).and_return(cask)
expect(Cask::Auditor).to receive(:audit) 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) .and_return(true)
described_class.run("casktoken", "--token-conflicts") described_class.run("casktoken", "--token-conflicts")
end end
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 end

View File

@ -2,6 +2,7 @@
require_relative "shared_examples/requires_cask_token" require_relative "shared_examples/requires_cask_token"
require_relative "shared_examples/invalid_option" require_relative "shared_examples/invalid_option"
require "utils"
describe Cask::Cmd::Info, :cask do describe Cask::Cmd::Info, :cask do
it_behaves_like "a command that requires a Cask token" it_behaves_like "a command that requires a Cask token"
@ -139,7 +140,16 @@ describe Cask::Cmd::Info, :cask do
EOS EOS
end 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 { expect {
described_class.run("https://raw.githubusercontent.com/Homebrew/homebrew-cask" \ described_class.run("https://raw.githubusercontent.com/Homebrew/homebrew-cask" \
"/d0b2c58652ae5eff20a7a4ac93292a08b250912b/Casks/docker.rb") "/d0b2c58652ae5eff20a7a4ac93292a08b250912b/Casks/docker.rb")
@ -155,6 +165,8 @@ describe Cask::Cmd::Info, :cask do
Docker CE Docker CE
==> Artifacts ==> Artifacts
Docker.app (App) 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. ==> Downloading https://raw.githubusercontent.com/Homebrew/homebrew-cask/d0b2c58652ae5eff20a7a4ac93292a08b250912b/Casks/docker.rb.
docker: 2.0.0.2-ce-mac81,30215 (auto_updates) docker: 2.0.0.2-ce-mac81,30215 (auto_updates)
https://www.docker.com/community-edition https://www.docker.com/community-edition
@ -164,6 +176,8 @@ describe Cask::Cmd::Info, :cask do
Docker CE Docker CE
==> Artifacts ==> Artifacts
Docker.app (App) Docker.app (App)
==> Analytics
install: 1,000 (30 days), 2,000 (90 days), 3,000 (365 days)
EOS EOS
end end
end end

View File

@ -9,7 +9,7 @@ end
describe "brew --cache", :integration_test do describe "brew --cache", :integration_test do
it "prints all cache files for a given Formula" do it "prints all cache files for a given Formula" do
expect { brew "--cache", testball } 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 not_to_output.to_stderr
.and be_a_success .and be_a_success
end end

View File

@ -68,7 +68,7 @@ describe "brew install", :integration_test do
# and there will be the git requirement, but we cannot instantiate git # and there will be the git requirement, but we cannot instantiate git
# formula since we only have testball1 formula. # formula since we only have testball1 formula.
expect { brew "install", "testball1", "--HEAD", "--ignore-dependencies" } 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 output(/Cloning into/).to_stderr
.and be_a_success .and be_a_success
expect(HOMEBREW_CELLAR/"testball1/HEAD-d5eb689/foo/test").not_to be_a_file expect(HOMEBREW_CELLAR/"testball1/HEAD-d5eb689/foo/test").not_to be_a_file

View File

@ -3,11 +3,12 @@
shared_examples "parseable arguments" do shared_examples "parseable arguments" do
subject(:method_name) do |example| subject(:method_name) do |example|
example.metadata[:example_group][:parent_example_group][:description] example.metadata[:example_group][:parent_example_group][:description]
.gsub(/^Homebrew\./, "") .delete_prefix("Homebrew.")
end end
let(:command_name) do let(:command_name) do
method_name.gsub(/_args$/, "").tr("_", "-") method_name.delete_suffix("_args")
.tr("_", "-")
end end
it "can parse arguments" do it "can parse arguments" do

Some files were not shown because too many files have changed in this diff Show More