Merge branch 'master' into mlh-outdated-packages

This commit is contained in:
Baffour Adu Boampong 2020-08-03 13:11:20 +00:00 committed by GitHub
commit c7c4921744
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
348 changed files with 3408 additions and 2613 deletions

3
.github/codecov.yml vendored
View File

@ -6,3 +6,6 @@ coverage:
project: project:
default: default:
threshold: 0.05% threshold: 0.05%
patch:
default:
informational: true

View File

@ -103,6 +103,12 @@ jobs:
if [ "$RUNNER_OS" = "macOS" ]; then if [ "$RUNNER_OS" = "macOS" ]; then
brew tap homebrew/cask brew tap homebrew/cask
brew update-reset Library/Taps/homebrew/homebrew-cask brew update-reset Library/Taps/homebrew/homebrew-cask
# don't care about `brew cask style` here.
brew untap adoptopenjdk/openjdk
# don't care about `brew audit` here.
brew untap mongodb/brew
else else
# Fix permissions for 'brew tests' # Fix permissions for 'brew tests'
sudo chmod -R g-w,o-w /home/linuxbrew /home/runner /opt sudo chmod -R g-w,o-w /home/linuxbrew /home/runner /opt
@ -159,6 +165,13 @@ jobs:
- name: Run brew style on official taps - name: Run brew style on official taps
run: brew style --display-cop-names homebrew/bundle homebrew/services homebrew/test-bot run: brew style --display-cop-names homebrew/bundle homebrew/services homebrew/test-bot
- name: Run brew cask style
if: matrix.os == 'macOS-latest'
run: brew cask style
- name: Run brew audit
run: brew audit --skip-style
- name: Run vale for docs linting - name: Run vale for docs linting
run: | run: |
brew install vale brew install vale
@ -174,12 +187,12 @@ jobs:
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
run: docker build -t brew --build-arg=version=16.04 . run: docker build -t brew --build-arg=version=16.04 .
- name: Run brew test-bot - name: Run brew test-bot --only-formulae --test-default-formula
run: | run: |
if [ "$RUNNER_OS" = "Linux" ]; then if [ "$RUNNER_OS" = "Linux" ]; then
docker run --rm brew brew test-bot docker run --rm brew brew test-bot --only-formulae --test-default-formula
else else
brew test-bot brew test-bot --only-formulae --test-default-formula
fi fi
- name: Deploy the Docker image to GitHub and Docker Hub - name: Deploy the Docker image to GitHub and Docker Hub

3
.gitignore vendored
View File

@ -86,11 +86,13 @@
**/vendor/bundle/ruby/*/gems/byebug-*/ **/vendor/bundle/ruby/*/gems/byebug-*/
**/vendor/bundle/ruby/*/gems/coderay-*/ **/vendor/bundle/ruby/*/gems/coderay-*/
**/vendor/bundle/ruby/*/gems/colorize-*/ **/vendor/bundle/ruby/*/gems/colorize-*/
**/vendor/bundle/ruby/*/gems/commander-*/
**/vendor/bundle/ruby/*/gems/connection_pool-*/ **/vendor/bundle/ruby/*/gems/connection_pool-*/
**/vendor/bundle/ruby/*/gems/codecov-*/ **/vendor/bundle/ruby/*/gems/codecov-*/
**/vendor/bundle/ruby/*/gems/diff-lcs-*/ **/vendor/bundle/ruby/*/gems/diff-lcs-*/
**/vendor/bundle/ruby/*/gems/docile-*/ **/vendor/bundle/ruby/*/gems/docile-*/
**/vendor/bundle/ruby/*/gems/domain_name-*/ **/vendor/bundle/ruby/*/gems/domain_name-*/
**/vendor/bundle/ruby/*/gems/highline-*/
**/vendor/bundle/ruby/*/gems/http-cookie-*/ **/vendor/bundle/ruby/*/gems/http-cookie-*/
**/vendor/bundle/ruby/*/gems/hpricot-*/ **/vendor/bundle/ruby/*/gems/hpricot-*/
**/vendor/bundle/ruby/*/gems/jaro_winkler-*/ **/vendor/bundle/ruby/*/gems/jaro_winkler-*/
@ -107,6 +109,7 @@
**/vendor/bundle/ruby/*/gems/ntlm-http-*/ **/vendor/bundle/ruby/*/gems/ntlm-http-*/
**/vendor/bundle/ruby/*/gems/parallel-*/ **/vendor/bundle/ruby/*/gems/parallel-*/
**/vendor/bundle/ruby/*/gems/parallel_tests-*/ **/vendor/bundle/ruby/*/gems/parallel_tests-*/
**/vendor/bundle/ruby/*/gems/parlour-*/
**/vendor/bundle/ruby/*/gems/parser-*/ **/vendor/bundle/ruby/*/gems/parser-*/
**/vendor/bundle/ruby/*/gems/powerpack-*/ **/vendor/bundle/ruby/*/gems/powerpack-*/
**/vendor/bundle/ruby/*/gems/psych-*/ **/vendor/bundle/ruby/*/gems/psych-*/

View File

@ -1 +1,3 @@
See Homebrew's [releases on GitHub](https://github.com/Homebrew/brew/releases) for the changelog. See Homebrew's [releases on GitHub](https://github.com/Homebrew/brew/releases) for the changelog.
Release notes for major and minor releases can also be found in the [Homebrew blog](https://brew.sh/blog/).

View File

@ -1,4 +1,12 @@
inherit_from: ./.rubocop_shared.yml # TODO: Try getting more rules in sync.
require: ./Homebrew/rubocops.rb
AllCops:
TargetRubyVersion: 2.6
DisplayCopNames: false
# enable all pending rubocops
NewCops: enable
# enable all formulae audits # enable all formulae audits
FormulaAudit: FormulaAudit:
@ -8,9 +16,108 @@ FormulaAudit:
FormulaAuditStrict: FormulaAuditStrict:
Enabled: true Enabled: true
# enable all pending rubocops # Use `<<~` for heredocs.
AllCops: Layout/HeredocIndentation:
NewCops: enable Enabled: true
# Not useful in casks and formulae.
Metrics/BlockLength:
Enabled: false
# Keyword arguments don't have the same readability
# problems as normal parameters.
Metrics/ParameterLists:
CountKeywordArgs: false
# Implicitly allow EOS as we use it everywhere.
Naming/HeredocDelimiterNaming:
ForbiddenDelimiters:
- END, EOD, EOF
# Allow dashes in filenames.
Naming/FileName:
Regex: !ruby/regexp /^[\w\@\-\+\.]+(\.rb)?$/
# Both styles are used depending on context,
# e.g. `sha256` and `something_countable_1`.
Naming/VariableNumber:
Enabled: false
# Avoid leaking resources.
Style/AutoResourceCleanup:
Enabled: true
# This makes these a little more obvious.
Style/BarePercentLiterals:
EnforcedStyle: percent_q
# Use consistent style for better readability.
Style/CollectionMethods:
Enabled: true
# Prefer tokens with type annotations for consistency
# between formatting numbers and strings.
Style/FormatStringToken:
EnforcedStyle: annotated
# autocorrectable and more readable
Style/HashEachMethods:
Enabled: true
Style/HashTransformKeys:
Enabled: true
Style/HashTransformValues:
Enabled: true
# Enabled now LineLength is lowish.
Style/IfUnlessModifier:
Enabled: true
# Only use this for numbers >= `1_000_000`.
Style/NumericLiterals:
MinDigits: 7
Strict: true
# Zero-prefixed octal literals are widely used and understood.
Style/NumericLiteralPrefix:
EnforcedOctalStyle: zero_only
# Rescuing `StandardError` is an understood default.
Style/RescueStandardError:
EnforcedStyle: implicit
# Returning `nil` is unnecessary.
Style/ReturnNil:
Enabled: true
# We have no use for using `warn` because we
# are calling Ruby with warnings disabled.
Style/StderrPuts:
Enabled: false
# Use consistent method names.
Style/StringMethods:
Enabled: true
# An array of symbols is more readable than a symbol array
# and also allows for easier grepping.
Style/SymbolArray:
EnforcedStyle: brackets
# Trailing commas make diffs nicer.
Style/TrailingCommaInArguments:
EnforcedStyleForMultiline: comma
Style/TrailingCommaInArrayLiteral:
EnforcedStyleForMultiline: comma
Style/TrailingCommaInHashLiteral:
EnforcedStyleForMultiline: comma
# Does not hinder readability, so might as well enable it.
Performance/CaseWhenSplat:
Enabled: true
# Makes code less readable for minor performance increases.
Performance/Caller:
Enabled: false
# don't allow cops to be disabled in formulae # don't allow cops to be disabled in formulae
Style/DisableCopsWithinSourceCodeDirective: Style/DisableCopsWithinSourceCodeDirective:
@ -54,6 +161,7 @@ Lint/AmbiguousRegexpLiteral:
Lint/ParenthesesAsGroupedExpression: Lint/ParenthesesAsGroupedExpression:
Enabled: false Enabled: false
# most metrics don't make sense to apply for formulae/taps # most metrics don't make sense to apply for formulae/taps
Metrics/AbcSize: Metrics/AbcSize:
Enabled: false Enabled: false
@ -72,7 +180,17 @@ Metrics/PerceivedComplexity:
Layout/LineLength: Layout/LineLength:
Max: 118 Max: 118
# ignore manpage comments and long single-line strings # ignore manpage comments and long single-line strings
IgnoredPatterns: ['#: ', ' url "', ' mirror "', ' plist_options :'] IgnoredPatterns: ['#: ', ' url "', ' mirror "', ' plist_options ',
' appcast "', ' executable: "', ' font "', ' homepage "', ' name "',
' pkg "', ' pkgutil: "', '#{language}', '#{version.',
' "/Library/Application Support/', '"/Library/Caches/', '"/Library/PreferencePanes/',
' "~/Library/Application Support/', '"~/Library/Caches/', '"~/Application Support',
' was verified as official when first introduced to the cask']
# TODO: remove this when possible.
Style/ClassVars:
Exclude:
- '**/developer/bin/*'
# most of our APIs are internal so don't require docs # most of our APIs are internal so don't require docs
Style/Documentation: Style/Documentation:
@ -82,26 +200,18 @@ Style/Documentation:
Style/FrozenStringLiteralComment: Style/FrozenStringLiteralComment:
Enabled: false Enabled: false
# TODO: remove this when possible.
Style/GlobalVars:
Exclude:
- '**/developer/bin/*'
# potential for errors in formulae too high with this # potential for errors in formulae too high with this
Style/GuardClause: Style/GuardClause:
Enabled: false Enabled: false
# depends_on a: :b looks weird in formulae. # avoid hash rockets where possible
Style/HashSyntax: Style/HashSyntax:
EnforcedStyle: hash_rockets EnforcedStyle: ruby19
Exclude:
- '**/Guardfile'
- '**/cmd/**/*.rb'
- '**/lib/**/*.rb'
- '**/spec/**/*.rb'
# autocorrectable and more readable
Style/HashEachMethods:
Enabled: true
Style/HashTransformKeys:
Enabled: true
Style/HashTransformValues:
Enabled: true
# ruby style guide favorite # ruby style guide favorite
Style/StringLiterals: Style/StringLiterals:
@ -118,3 +228,11 @@ Style/TernaryParentheses:
# a bit confusing to non-Rubyists but useful for longer arrays # a bit confusing to non-Rubyists but useful for longer arrays
Style/WordArray: Style/WordArray:
MinSize: 4 MinSize: 4
# would rather freeze too much than too little
Style/MutableConstant:
EnforcedStyle: strict
# unused keyword arguments improve APIs
Lint/UnusedMethodArgument:
AllowUnusedKeywordArguments: true

View File

@ -1,10 +1,8 @@
inherit_from: ./.rubocop_shared.yml inherit_from: ./Homebrew/.rubocop.yml
Cask/HomepageMatchesUrl: Cask/HomepageMatchesUrl:
Description: 'Ensure that the homepage and url match, otherwise add a comment. More info at https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/cask_language_reference/stanzas/url.md#when-url-and-homepage-hostnames-differ-add-a-comment' Description: 'Ensure that the homepage and url match, otherwise add a comment. More info at https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/cask_language_reference/stanzas/url.md#when-url-and-homepage-hostnames-differ-add-a-comment'
Enabled: true Enabled: true
Exclude:
- '**/test/support/fixtures/cask/Casks/**/*.rb'
Cask/HomepageUrlTrailingSlash: Cask/HomepageUrlTrailingSlash:
Description: 'Ensure that the homepage url has a slash after the domain name.' Description: 'Ensure that the homepage url has a slash after the domain name.'
@ -22,44 +20,6 @@ Cask/StanzaOrder:
Description: 'Ensure that cask stanzas are sorted correctly. More info at https://github.com/Homebrew/homebrew-cask/blob/HEAD/CONTRIBUTING.md#stanza-order' Description: 'Ensure that cask stanzas are sorted correctly. More info at https://github.com/Homebrew/homebrew-cask/blob/HEAD/CONTRIBUTING.md#stanza-order'
Enabled: true Enabled: true
Layout/HashAlignment: # don't want this for casks but re-enabled for Library/Homebrew
EnforcedHashRocketStyle: table
EnforcedColonStyle: table
Layout/FirstArrayElementIndentation:
EnforcedStyle: align_brackets
Layout/FirstHashElementIndentation:
EnforcedStyle: align_braces
# Casks often contain long URLs and file paths.
Layout/LineLength:
Enabled: false
# Casks don't need documentation.
Style/Documentation:
Enabled: false
# These would only be distracting in casks.
Style/FrozenStringLiteralComment: Style/FrozenStringLiteralComment:
EnforcedStyle: never Enabled: false
# Don't use hash rockets.
Style/HashSyntax:
EnforcedStyle: ruby19_no_mixed_keys
# This is more readable when the regex contains slashes.
Style/RegexpLiteral:
EnforcedStyle: percent_r
# Use consistent style for all arrays.
Style/WordArray:
EnforcedStyle: brackets
# This makes multi-line arrays more readable and alignable.
Layout/FirstArrayElementLineBreak:
Enabled: true
# This makes multi-line hashes more readable and alignable.
Layout/FirstHashElementLineBreak:
Enabled: true

View File

@ -1,110 +0,0 @@
# TODO: Try getting more rules in sync.
require: ./Homebrew/rubocops.rb
AllCops:
TargetRubyVersion: 2.6
DisplayCopNames: false
# Use `<<~` for heredocs.
Layout/HeredocIndentation:
Enabled: true
# Not useful in casks and formulae.
Metrics/BlockLength:
Enabled: false
# Keyword arguments don't have the same readability
# problems as normal parameters.
Metrics/ParameterLists:
CountKeywordArgs: false
# Implicitly allow EOS as we use it everywhere.
Naming/HeredocDelimiterNaming:
ForbiddenDelimiters:
- END, EOD, EOF
# Allow dashes in filenames.
Naming/FileName:
Regex: !ruby/regexp /^[\w\@\-\+\.]+(\.rb)?$/
# Both styles are used depending on context,
# e.g. `sha256` and `something_countable_1`.
Naming/VariableNumber:
Enabled: false
# Avoid leaking resources.
Style/AutoResourceCleanup:
Enabled: true
# This makes these a little more obvious.
Style/BarePercentLiterals:
EnforcedStyle: percent_q
# Use consistent style for better readability.
Style/CollectionMethods:
Enabled: true
# Prefer tokens with type annotations for consistency
# between formatting numbers and strings.
Style/FormatStringToken:
EnforcedStyle: annotated
# autocorrectable and more readable
Style/HashEachMethods:
Enabled: true
Style/HashTransformKeys:
Enabled: true
Style/HashTransformValues:
Enabled: true
# Enabled now LineLength is lowish.
Style/IfUnlessModifier:
Enabled: true
# Only use this for numbers >= `1_000_000`.
Style/NumericLiterals:
MinDigits: 7
Strict: true
# Zero-prefixed octal literals are widely used and understood.
Style/NumericLiteralPrefix:
EnforcedOctalStyle: zero_only
# Rescuing `StandardError` is an understood default.
Style/RescueStandardError:
EnforcedStyle: implicit
# Returning `nil` is unnecessary.
Style/ReturnNil:
Enabled: true
# We have no use for using `warn` because we
# are calling Ruby with warnings disabled.
Style/StderrPuts:
Enabled: false
# Use consistent method names.
Style/StringMethods:
Enabled: true
# An array of symbols is more readable than a symbol array
# and also allows for easier grepping.
Style/SymbolArray:
EnforcedStyle: brackets
# Trailing commas make diffs nicer.
Style/TrailingCommaInArguments:
EnforcedStyleForMultiline: comma
Style/TrailingCommaInArrayLiteral:
EnforcedStyleForMultiline: comma
Style/TrailingCommaInHashLiteral:
EnforcedStyleForMultiline: comma
# Does not hinder readability, so might as well enable it.
Performance/CaseWhenSplat:
Enabled: true
# Makes code less readable for minor performance increases.
Performance/Caller:
Enabled: false

View File

@ -6,7 +6,6 @@ AllCops:
- 'Library/Homebrew/.simplecov' - 'Library/Homebrew/.simplecov'
Exclude: Exclude:
- 'bin/*' - 'bin/*'
- '**/Casks/**/*'
- '**/vendor/**/*' - '**/vendor/**/*'
# messes up system formatting for formulae but good for Homebrew/brew # messes up system formatting for formulae but good for Homebrew/brew
@ -35,10 +34,6 @@ Lint/NestedMethodDefinition:
Lint/ParenthesesAsGroupedExpression: Lint/ParenthesesAsGroupedExpression:
Enabled: true Enabled: true
# unused keyword arguments improve APIs
Lint/UnusedMethodArgument:
AllowUnusedKeywordArguments: true
# TODO: try to bring down all metrics maximums # TODO: try to bring down all metrics maximums
Metrics/AbcSize: Metrics/AbcSize:
Enabled: true Enabled: true
@ -113,10 +108,7 @@ Style/BlockDelimiters:
# don't group nicely documented or private attr_readers # don't group nicely documented or private attr_readers
Style/AccessorGrouping: Style/AccessorGrouping:
Enabled: true
Exclude: Exclude:
- 'cask/cmd/internal_stanza.rb'
- 'cask/download.rb'
- 'formula.rb' - 'formula.rb'
- 'formulary.rb' - 'formulary.rb'
- 'migrator.rb' - 'migrator.rb'
@ -124,11 +116,6 @@ Style/AccessorGrouping:
- 'system_command.rb' - 'system_command.rb'
- 'tap.rb' - 'tap.rb'
# https://github.com/rubocop-hq/rubocop/issues/8257
Style/BisectedAttrAccessor:
Exclude:
- 'cask/url.rb'
# document our public APIs # document our public APIs
Style/Documentation: Style/Documentation:
Enabled: true Enabled: true
@ -143,19 +130,9 @@ Style/DocumentationMethod:
Style/FrozenStringLiteralComment: Style/FrozenStringLiteralComment:
Enabled: true Enabled: true
EnforcedStyle: always EnforcedStyle: always
Exclude:
- '**/Casks/**/*.rb'
# so many of these in formulae but none in here # so many of these in formulae but none in here
Style/GuardClause: Style/GuardClause:
Enabled: true Enabled: true
# hash-rockets preferred for formulae, a: 1 preferred here
Style/HashSyntax:
EnforcedStyle: ruby19_no_mixed_keys
# would rather freeze too much than too little
Style/MutableConstant:
EnforcedStyle: strict
# LineLength is low enough here to re-enable it.
Style/IfUnlessModifier:
Enabled: true

View File

@ -10,7 +10,7 @@ GEM
ast (2.4.1) ast (2.4.1)
bindata (2.4.8) bindata (2.4.8)
byebug (11.1.3) byebug (11.1.3)
codecov (0.2.2) codecov (0.2.3)
colorize colorize
json json
simplecov simplecov
@ -55,7 +55,7 @@ GEM
parallel parallel
parser (2.7.1.4) parser (2.7.1.4)
ast (~> 2.4.1) ast (~> 2.4.1)
patchelf (1.1.1) patchelf (1.2.0)
elftools (~> 1.1) elftools (~> 1.1)
plist (3.5.0) plist (3.5.0)
rainbow (3.0.0) rainbow (3.0.0)
@ -95,8 +95,8 @@ GEM
rubocop-ast (>= 0.1.0, < 1.0) rubocop-ast (>= 0.1.0, < 1.0)
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-ast (0.2.0) rubocop-ast (0.3.0)
parser (>= 2.7.0.1) parser (>= 2.7.1.4)
rubocop-performance (1.7.1) rubocop-performance (1.7.1)
rubocop (>= 0.82.0) rubocop (>= 0.82.0)
rubocop-rspec (1.42.0) rubocop-rspec (1.42.0)

View File

@ -35,19 +35,13 @@ rescue MissingEnvironmentVariables => e
exec ENV["HOMEBREW_BREW_FILE"], *ARGV exec ENV["HOMEBREW_BREW_FILE"], *ARGV
end end
def output_unsupported_error
$stderr.puts <<~EOS
Please create pull requests instead of asking for help on Homebrew's GitHub,
Discourse, Twitter or IRC.
EOS
end
begin begin
trap("INT", std_trap) # restore default CTRL-C handler trap("INT", std_trap) # restore default CTRL-C handler
empty_argv = ARGV.empty? empty_argv = ARGV.empty?
help_flag_list = %w[-h --help --usage -?] help_flag_list = %w[-h --help --usage -?]
help_flag = !ENV["HOMEBREW_HELP"].nil? help_flag = !ENV["HOMEBREW_HELP"].nil?
help_cmd_index = nil
cmd = nil cmd = nil
ARGV.each_with_index do |arg, i| ARGV.each_with_index do |arg, i|
@ -56,12 +50,17 @@ begin
if arg == "help" && !cmd if arg == "help" && !cmd
# Command-style help: `help <cmd>` is fine, but `<cmd> help` is not. # Command-style help: `help <cmd>` is fine, but `<cmd> help` is not.
help_flag = true help_flag = true
help_cmd_index = i
elsif !cmd && !help_flag_list.include?(arg) elsif !cmd && !help_flag_list.include?(arg)
cmd = ARGV.delete_at(i) cmd = ARGV.delete_at(i)
cmd = Commands::HOMEBREW_INTERNAL_COMMAND_ALIASES.fetch(cmd, cmd) cmd = Commands::HOMEBREW_INTERNAL_COMMAND_ALIASES.fetch(cmd, cmd)
end end
end end
ARGV.delete_at(help_cmd_index) if help_cmd_index
Homebrew.args = Homebrew::CLI::Parser.new.parse(ARGV.dup.freeze, ignore_invalid_options: true)
path = PATH.new(ENV["PATH"]) path = PATH.new(ENV["PATH"])
homebrew_path = PATH.new(ENV["HOMEBREW_PATH"]) homebrew_path = PATH.new(ENV["HOMEBREW_PATH"])
@ -124,7 +123,7 @@ begin
odie "Unknown command: #{cmd}" if !possible_tap || possible_tap.installed? odie "Unknown command: #{cmd}" if !possible_tap || possible_tap.installed?
# Unset HOMEBREW_HELP to avoid confusing the tap # Unset HOMEBREW_HELP to avoid confusing the tap
ENV.delete("HOMEBREW_HELP") if help_flag with_env HOMEBREW_HELP: nil do
tap_commands = [] tap_commands = []
cgroup = Utils.popen_read("cat", "/proc/1/cgroup") cgroup = Utils.popen_read("cat", "/proc/1/cgroup")
if %w[azpl_job actions_job docker garden kubepods].none? { |container| cgroup.include?(container) } if %w[azpl_job actions_job docker garden kubepods].none? { |container| cgroup.include?(container) }
@ -133,7 +132,8 @@ begin
end end
tap_commands += %W[#{HOMEBREW_BREW_FILE} tap #{possible_tap.name}] tap_commands += %W[#{HOMEBREW_BREW_FILE} tap #{possible_tap.name}]
safe_system(*tap_commands) safe_system(*tap_commands)
ENV["HOMEBREW_HELP"] = "1" if help_flag end
exec HOMEBREW_BREW_FILE, cmd, *ARGV exec HOMEBREW_BREW_FILE, cmd, *ARGV
end end
rescue UsageError => e rescue UsageError => e
@ -150,7 +150,12 @@ rescue BuildError => e
Utils::Analytics.report_build_error(e) Utils::Analytics.report_build_error(e)
e.dump e.dump
output_unsupported_error if e.formula.head? || e.formula.deprecated? || e.formula.disabled? if e.formula.head? || e.formula.deprecated? || e.formula.disabled?
$stderr.puts <<~EOS
Please create pull requests instead of asking for help on Homebrew's GitHub,
Discourse, Twitter or IRC.
EOS
end
exit 1 exit 1
rescue RuntimeError, SystemCallError => e rescue RuntimeError, SystemCallError => e
@ -159,8 +164,6 @@ rescue RuntimeError, SystemCallError => e
onoe e onoe e
$stderr.puts e.backtrace if Homebrew.args.debug? $stderr.puts e.backtrace if Homebrew.args.debug?
output_unsupported_error if Homebrew.args.HEAD?
exit 1 exit 1
rescue MethodDeprecatedError => e rescue MethodDeprecatedError => e
onoe e onoe e

View File

@ -12,7 +12,16 @@ then
then then
export LC_ALL="en_US.UTF-8" export LC_ALL="en_US.UTF-8"
else else
export LC_ALL="C.UTF-8" locales=$(locale -a)
c_utf_regex='\bC\.(utf8|UTF-8)\b'
en_us_regex='\ben_US\.(utf8|UTF-8)\b'
utf_regex='\b[a-z][a-z]_[A-Z][A-Z]\.(utf8|UTF-8)\b'
if [[ $locales =~ $c_utf_regex || $locales =~ $en_us_regex || $locales =~ $utf_regex ]]
then
export LC_ALL=${BASH_REMATCH[0]}
else
export LC_ALL=C
fi
fi fi
fi fi
@ -327,6 +336,8 @@ fi
for arg in "$@" for arg in "$@"
do do
[[ $arg = "--" ]] && break
if [[ $arg = "--help" || $arg = "-h" || $arg = "--usage" || $arg = "-?" ]] if [[ $arg = "--help" || $arg = "-h" || $arg = "--usage" || $arg = "-?" ]]
then then
export HOMEBREW_HELP="1" export HOMEBREW_HELP="1"
@ -518,6 +529,7 @@ update-preinstall() {
if [[ "$HOMEBREW_COMMAND" = "install" || "$HOMEBREW_COMMAND" = "upgrade" || if [[ "$HOMEBREW_COMMAND" = "install" || "$HOMEBREW_COMMAND" = "upgrade" ||
"$HOMEBREW_COMMAND" = "bump-formula-pr" || "$HOMEBREW_COMMAND" = "bump-formula-pr" ||
"$HOMEBREW_COMMAND" = "bundle" ||
"$HOMEBREW_COMMAND" = "tap" && $HOMEBREW_ARG_COUNT -gt 1 || "$HOMEBREW_COMMAND" = "tap" && $HOMEBREW_ARG_COUNT -gt 1 ||
"$HOMEBREW_CASK_COMMAND" = "install" || "$HOMEBREW_CASK_COMMAND" = "upgrade" ]] "$HOMEBREW_CASK_COMMAND" = "install" || "$HOMEBREW_CASK_COMMAND" = "upgrade" ]]
then then

View File

@ -83,20 +83,38 @@ class Build
fixopt(dep) unless dep.opt_prefix.directory? fixopt(dep) unless dep.opt_prefix.directory?
end end
ENV.activate_extensions!(args: args) ENV.activate_extensions!(env: args.env)
if superenv?(args: args) if superenv?(args.env)
ENV.keg_only_deps = keg_only_deps ENV.keg_only_deps = keg_only_deps
ENV.deps = formula_deps ENV.deps = formula_deps
ENV.run_time_deps = run_time_deps ENV.run_time_deps = run_time_deps
ENV.x11 = reqs.any? { |rq| rq.is_a?(X11Requirement) } ENV.x11 = reqs.any? { |rq| rq.is_a?(X11Requirement) }
ENV.setup_build_environment(formula, args: args) ENV.setup_build_environment(
formula: formula,
cc: args.cc,
build_bottle: args.build_bottle?,
bottle_arch: args.bottle_arch,
)
post_superenv_hacks post_superenv_hacks
reqs.each { |req| req.modify_build_environment(args: args) } reqs.each do |req|
req.modify_build_environment(
env: args.env, cc: args.cc, build_bottle: args.build_bottle?, bottle_arch: args.bottle_arch,
)
end
deps.each(&:modify_build_environment) deps.each(&:modify_build_environment)
else else
ENV.setup_build_environment(formula, args: args) ENV.setup_build_environment(
reqs.each { |req| req.modify_build_environment(args: args) } formula: formula,
cc: args.cc,
build_bottle: args.build_bottle?,
bottle_arch: args.bottle_arch,
)
reqs.each do |req|
req.modify_build_environment(
env: args.env, cc: args.cc, build_bottle: args.build_bottle?, bottle_arch: args.bottle_arch,
)
end
deps.each(&:modify_build_environment) deps.each(&:modify_build_environment)
keg_only_deps.each do |dep| keg_only_deps.each do |dep|
@ -117,7 +135,7 @@ class Build
} }
with_env(new_env) do with_env(new_env) do
formula.extend(Debrew::Formula) if Homebrew.args.debug? formula.extend(Debrew::Formula) if args.debug?
formula.update_head_version formula.update_head_version
@ -190,7 +208,10 @@ class Build
end end
begin begin
Homebrew.args = Homebrew::CLI::Parser.new.parse(ARGV.dup.freeze, ignore_invalid_options: true)
args = Homebrew.install_args.parse args = Homebrew.install_args.parse
error_pipe = UNIXSocket.open(ENV["HOMEBREW_ERROR_PIPE"], &:recv_io) error_pipe = UNIXSocket.open(ENV["HOMEBREW_ERROR_PIPE"], &:recv_io)
error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)

View File

@ -9,7 +9,6 @@ require "cask/cache"
require "cask/cask" require "cask/cask"
require "cask/cask_loader" require "cask/cask_loader"
require "cask/caskroom" require "cask/caskroom"
require "cask/checkable"
require "cask/cmd" require "cask/cmd"
require "cask/exceptions" require "cask/exceptions"
require "cask/installer" require "cask/installer"

View File

@ -4,6 +4,7 @@ require "timeout"
require "utils/user" require "utils/user"
require "cask/artifact/abstract_artifact" require "cask/artifact/abstract_artifact"
require "cask/pkg"
require "extend/hash_validator" require "extend/hash_validator"
using HashValidator using HashValidator

View File

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require "cask/denylist" require "cask/denylist"
require "cask/checkable"
require "cask/download" require "cask/download"
require "digest" require "digest"
require "utils/curl" require "utils/curl"
@ -10,7 +9,6 @@ require "utils/notability"
module Cask module Cask
class Audit class Audit
include Checkable
extend Predicable extend Predicable
attr_reader :cask, :commit_range, :download attr_reader :cask, :commit_range, :download
@ -62,12 +60,56 @@ module Cask
self self
end end
def success? def errors
!(errors? || warnings?) @errors ||= []
end end
def summary_header def warnings
"audit for #{cask}" @warnings ||= []
end
def add_error(message)
errors << message
end
def add_warning(message)
warnings << message
end
def errors?
errors.any?
end
def warnings?
warnings.any?
end
def result
if errors?
Formatter.error("failed")
elsif warnings?
Formatter.warning("warning")
else
Formatter.success("passed")
end
end
def summary
summary = ["audit for #{cask}: #{result}"]
errors.each do |error|
summary << " #{Formatter.error("-")} #{error}"
end
warnings.each do |warning|
summary << " #{Formatter.warning("-")} #{warning}"
end
summary.join("\n")
end
def success?
!(errors? || warnings?)
end end
private private

View File

@ -2,7 +2,6 @@
module Cask module Cask
class Auditor class Auditor
include Checkable
extend Predicable extend Predicable
def self.audit(cask, audit_download: false, audit_appcast: false, def self.audit(cask, audit_download: false, audit_appcast: false,
@ -39,19 +38,28 @@ module Cask
:audit_strict?, :audit_new_cask?, :audit_token_conflicts?, :quarantine? :audit_strict?, :audit_new_cask?, :audit_token_conflicts?, :quarantine?
def audit def audit
warnings = Set.new
errors = Set.new
if !Homebrew.args.value("language") && language_blocks if !Homebrew.args.value("language") && language_blocks
audit_all_languages language_blocks.each_key do |l|
else audit = audit_languages(l)
audit_cask_instance(cask) puts audit.summary
warnings += audit.warnings
errors += audit.errors
end end
else
audit = audit_cask_instance(cask)
puts audit.summary
warnings += audit.warnings
errors += audit.errors
end
{ warnings: warnings, errors: errors }
end end
private private
def audit_all_languages
language_blocks.keys.all?(&method(:audit_languages))
end
def audit_languages(languages) def audit_languages(languages)
ohai "Auditing language: #{languages.map { |lang| "'#{lang}'" }.to_sentence}" ohai "Auditing language: #{languages.map { |lang| "'#{lang}'" }.to_sentence}"
localized_cask = CaskLoader.load(cask.sourcefile_path) localized_cask = CaskLoader.load(cask.sourcefile_path)
@ -71,8 +79,7 @@ module Cask
quarantine: quarantine?, quarantine: quarantine?,
commit_range: commit_range) commit_range: commit_range)
audit.run! audit.run!
puts audit.summary audit
audit.success?
end end
def language_blocks def language_blocks

View File

@ -1,53 +0,0 @@
# frozen_string_literal: true
module Cask
module Checkable
def errors
@errors ||= []
end
def warnings
@warnings ||= []
end
def add_error(message)
errors << message
end
def add_warning(message)
warnings << message
end
def errors?
errors.any?
end
def warnings?
warnings.any?
end
def result
if errors?
Formatter.error("failed")
elsif warnings?
Formatter.warning("warning")
else
Formatter.success("passed")
end
end
def summary
summary = ["#{summary_header}: #{result}"]
errors.each do |error|
summary << " #{Formatter.error("-")} #{error}"
end
warnings.each do |warning|
summary << " #{Formatter.warning("-")} #{warning}"
end
summary.join("\n")
end
end
end

View File

@ -87,6 +87,10 @@ module Cask
@lookup.fetch(command_name, nil) @lookup.fetch(command_name, nil)
end end
def self.aliases
ALIASES
end
def self.run(*args) def self.run(*args)
new(*args).run new(*args).run
end end

View File

@ -48,13 +48,15 @@ module Cask
failed_casks = casks(alternative: -> { Cask.to_a }) failed_casks = casks(alternative: -> { Cask.to_a })
.reject do |cask| .reject do |cask|
odebug "Auditing Cask #{cask}" odebug "Auditing Cask #{cask}"
Auditor.audit(cask, audit_download: download, result = Auditor.audit(cask, audit_download: download,
audit_appcast: appcast, audit_appcast: appcast,
audit_online: online, audit_online: online,
audit_strict: strict, audit_strict: strict,
audit_new_cask: new_cask_arg?, audit_new_cask: new_cask_arg?,
audit_token_conflicts: token_conflicts, audit_token_conflicts: token_conflicts,
quarantine: quarantine?) quarantine: quarantine?)
result[:warnings].empty? && result[:errors].empty?
end end
return if failed_casks.empty? return if failed_casks.empty?

View File

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require "system_config" require "system_config"
require "cask/checkable"
require "diagnostic" require "diagnostic"
module Cask module Cask

View File

@ -32,12 +32,8 @@ module Cask
option "--yaml", :yaml, false option "--yaml", :yaml, false
option "--inspect", :inspect, false option "--inspect", :inspect, false
attr_accessor :format attr_accessor :format, :stanza
private :format, :format= private :format, :format=
attr_accessor :stanza
private :stanza, :stanza= private :stanza, :stanza=
def initialize(*) def initialize(*)

View File

@ -47,7 +47,7 @@ module Cask
upgradable_casks.each do |(old_cask, new_cask)| upgradable_casks.each do |(old_cask, new_cask)|
upgrade_cask(old_cask, new_cask) upgrade_cask(old_cask, new_cask)
rescue => e rescue => e
caught_exceptions << e caught_exceptions << e.exception("#{new_cask.full_name}: #{e}")
next next
end end

View File

@ -0,0 +1,59 @@
# frozen_string_literal: true
# An adapter for casks to provide dependency information in a formula-like interface
class CaskDependent
def initialize(cask)
@cask = cask
end
def name
@cask.token
end
def full_name
@cask.full_name
end
def runtime_dependencies
recursive_dependencies
end
def deps
@deps ||= begin
@cask.depends_on.formula.map do |f|
Dependency.new f
end
end
end
def requirements
@requirements ||= begin
requirements = []
dsl_reqs = @cask.depends_on
dsl_reqs.arch&.each do |arch|
requirements << ArchRequirement.new([:x86_64]) if arch[:bits] == 64
requirements << ArchRequirement.new([arch[:type]])
end
dsl_reqs.cask.each do |cask_ref|
requirements << Requirement.new([{ cask: cask_ref }])
end
requirements << dsl_reqs.macos if dsl_reqs.macos
requirements << X11Requirement.new if dsl_reqs.x11
requirements
end
end
def recursive_dependencies(&block)
Dependency.expand(self, &block)
end
def recursive_requirements(&block)
Requirement.expand(self, &block)
end
def any_version_installed?
@cask.installed?
end
end

View File

@ -10,31 +10,27 @@ module Homebrew
# undefine tap to allow --tap argument # undefine tap to allow --tap argument
undef tap undef tap
def initialize(argv = ARGV.freeze, set_default_args: false) def initialize
super() super()
@processed_options = [] @processed_options = []
@options_only = args_options_only(argv) @options_only = []
@flags_only = args_flags_only(argv) @flags_only = []
# Can set these because they will be overwritten by freeze_named_args! # Can set these because they will be overwritten by freeze_named_args!
# (whereas other values below will only be overwritten if passed). # (whereas other values below will only be overwritten if passed).
self[:named_args] = argv.reject { |arg| arg.start_with?("-") } self[:named_args] = []
self[:remaining] = []
end
# Set values needed before Parser#parse has been run. def freeze_remaining_args!(remaining_args)
return unless set_default_args self[:remaining] = remaining_args.freeze
self[:build_from_source?] = argv.include?("--build-from-source") || argv.include?("-s")
self[:build_bottle?] = argv.include?("--build-bottle")
self[:force_bottle?] = argv.include?("--force-bottle")
self[:HEAD?] = argv.include?("--HEAD")
self[:devel?] = argv.include?("--devel")
self[:universal?] = argv.include?("--universal")
end end
def freeze_named_args!(named_args) def freeze_named_args!(named_args)
# Reset cache values reliant on named_args # Reset cache values reliant on named_args
@formulae = nil @formulae = nil
@formulae_and_casks = nil
@resolved_formulae = nil @resolved_formulae = nil
@resolved_formulae_casks = nil @resolved_formulae_casks = nil
@formulae_paths = nil @formulae_paths = nil
@ -42,8 +38,7 @@ module Homebrew
@kegs = nil @kegs = nil
@kegs_casks = nil @kegs_casks = nil
self[:named_args] = named_args self[:named_args] = named_args.freeze
self[:named_args].freeze
end end
def freeze_processed_options!(processed_options) def freeze_processed_options!(processed_options)
@ -53,12 +48,8 @@ module Homebrew
@processed_options += processed_options @processed_options += processed_options
@processed_options.freeze @processed_options.freeze
@options_only = args_options_only(cli_args) @options_only = cli_args.select { |a| a.start_with?("-") }.freeze
@flags_only = args_flags_only(cli_args) @flags_only = cli_args.select { |a| a.start_with?("--") }.freeze
end
def passthrough
options_only - CLI::Parser.global_options.values.map(&:first).flatten
end end
def named def named
@ -69,32 +60,37 @@ module Homebrew
named.blank? named.blank?
end end
# If the user passes any flags that trigger building over installing from
# a bottle, they are collected here and returned as an Array for checking.
def collect_build_args
build_flags = []
build_flags << "--HEAD" if HEAD?
build_flags << "--universal" if build_universal?
build_flags << "--build-bottle" if build_bottle?
build_flags << "--build-from-source" if build_from_source?
build_flags
end
def formulae def formulae
require "formula" require "formula"
@formulae ||= (downcased_unique_named - casks).map do |name| @formulae ||= (downcased_unique_named - casks).map do |name|
Formulary.factory(name, spec) Formulary.factory(name, spec, force_bottle: force_bottle?, flags: flags_only)
end.uniq(&:name).freeze end.uniq(&:name).freeze
end end
def formulae_and_casks
@formulae_and_casks ||= begin
formulae_and_casks = []
downcased_unique_named.each do |name|
formulae_and_casks << Formulary.factory(name, spec)
rescue FormulaUnavailableError
begin
formulae_and_casks << Cask::CaskLoader.load(name)
rescue Cask::CaskUnavailableError
raise "No available formula or cask with the name \"#{name}\""
end
end
formulae_and_casks.freeze
end
end
def resolved_formulae def resolved_formulae
require "formula" require "formula"
@resolved_formulae ||= (downcased_unique_named - casks).map do |name| @resolved_formulae ||= (downcased_unique_named - casks).map do |name|
Formulary.resolve(name, spec: spec(nil)) Formulary.resolve(name, spec: spec(nil), force_bottle: force_bottle?, flags: flags_only)
end.uniq(&:name).freeze end.uniq(&:name).freeze
end end
@ -104,7 +100,8 @@ module Homebrew
casks = [] casks = []
downcased_unique_named.each do |name| downcased_unique_named.each do |name|
resolved_formulae << Formulary.resolve(name, spec: spec(nil)) resolved_formulae << Formulary.resolve(name, spec: spec(nil),
force_bottle: force_bottle?, flags: flags_only)
rescue FormulaUnavailableError rescue FormulaUnavailableError
begin begin
casks << Cask::CaskLoader.load(name) casks << Cask::CaskLoader.load(name)
@ -162,18 +159,20 @@ module Homebrew
!(HEAD? || devel?) !(HEAD? || devel?)
end end
# Whether a given formula should be built from source during the current def build_from_source_formulae
# installation run. if build_from_source? || build_bottle?
def build_formula_from_source?(f) formulae.map(&:full_name)
return false if !build_from_source? && !build_bottle? else
[]
formulae.any? { |args_f| args_f.full_name == f.full_name } end
end end
def include_formula_test_deps?(f) def include_test_formulae
return false unless include_test? if include_test?
formulae.map(&:full_name)
formulae.any? { |args_f| args_f.full_name == f.full_name } else
[]
end
end end
def value(name) def value(name)
@ -210,16 +209,6 @@ module Homebrew
@cli_args.freeze @cli_args.freeze
end end
def args_options_only(args)
args.select { |arg| arg.start_with?("-") }
.freeze
end
def args_flags_only(args)
args.select { |arg| arg.start_with?("--") }
.freeze
end
def downcased_unique_named def downcased_unique_named
# Only lowercase names, not paths, bottle filenames or URLs # Only lowercase names, not paths, bottle filenames or URLs
named.map do |arg| named.map do |arg|

View File

@ -13,10 +13,6 @@ 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.freeze, allow_no_named_args: false, &block)
new(argv, &block).parse(allow_no_named_args: allow_no_named_args)
end
def self.from_cmd_path(cmd_path) def self.from_cmd_path(cmd_path)
cmd_args_method_name = Commands.args_method_name(cmd_path) cmd_args_method_name = Commands.args_method_name(cmd_path)
@ -30,18 +26,17 @@ module Homebrew
end end
def self.global_options def self.global_options
{ [
quiet: [["-q", "--quiet"], :quiet, "Suppress any warnings."], ["-q", "--quiet", "Suppress any warnings."],
verbose: [["-v", "--verbose"], :verbose, "Make some output more verbose."], ["-v", "--verbose", "Make some output more verbose."],
debug: [["-d", "--debug"], :debug, "Display any debugging information."], ["-d", "--debug", "Display any debugging information."],
force: [["-f", "--force"], :force, "Override warnings and enable potentially unsafe operations."], ]
}
end end
def initialize(argv = ARGV.freeze, &block) def initialize(&block)
@parser = OptionParser.new @parser = OptionParser.new
@argv = argv
@args = Homebrew::CLI::Args.new(@argv) @args = Homebrew::CLI::Args.new
@constraints = [] @constraints = []
@conflicts = [] @conflicts = []
@ -51,25 +46,32 @@ module Homebrew
@min_named_args = nil @min_named_args = nil
@min_named_type = nil @min_named_type = nil
@hide_from_man_page = false @hide_from_man_page = false
instance_eval(&block) @formula_options = false
self.class.global_options.each do |short, long, desc|
switch short, long, description: desc, env: option_to_name(long)
end
instance_eval(&block) if block_given?
post_initialize post_initialize
end end
def post_initialize def post_initialize
# Disable default handling of `--version` switch.
@parser.base.long.delete("version")
# Disable default handling of `--help` switch.
@parser.on_tail("-h", "--help", "Show this message.") do @parser.on_tail("-h", "--help", "Show this message.") do
puts generate_help_text # Handled in `brew.rb`.
exit 0
end end
end end
def switch(*names, description: nil, env: nil, required_for: nil, depends_on: nil) def switch(*names, description: nil, env: nil, required_for: nil, depends_on: nil)
global_switch = names.first.is_a?(Symbol) global_switch = names.first.is_a?(Symbol)
names, env, default_description = common_switch(*names) if global_switch return if global_switch
if description.nil? && global_switch
description = default_description description = option_to_description(*names) if description.nil?
elsif description.nil?
description = option_to_description(*names)
end
process_option(*names, description) process_option(*names, description)
@parser.on(*names, *wrap_option_desc(description)) do @parser.on(*names, *wrap_option_desc(description)) do
enable_switch(*names, from: :args) enable_switch(*names, from: :args)
@ -154,42 +156,51 @@ module Homebrew
@parser.to_s @parser.to_s
end end
def parse(argv = @argv, allow_no_named_args: false) def parse_remaining(argv, ignore_invalid_options: false)
i = 0
remaining = []
argv, non_options = split_non_options(argv)
while i < argv.count
begin
begin
arg = argv[i]
remaining << arg unless @parser.parse([arg]).empty?
rescue OptionParser::MissingArgument
raise if i + 1 >= argv.count
args = argv[i..(i + 1)]
@parser.parse(args)
i += 1
end
rescue OptionParser::InvalidOption
if ignore_invalid_options
remaining << arg
else
$stderr.puts generate_help_text
raise
end
end
i += 1
end
[remaining, non_options]
end
def parse(argv = ARGV.freeze, ignore_invalid_options: false)
raise "Arguments were already parsed!" if @args_parsed raise "Arguments were already parsed!" if @args_parsed
begin # If we accept formula options, parse once allowing invalid options
named_args = @parser.parse(argv) # so we can get the remaining list containing formula names.
rescue OptionParser::InvalidOption => e if @formula_options
$stderr.puts generate_help_text remaining, non_options = parse_remaining(argv, ignore_invalid_options: true)
raise e
end
check_constraint_violations argv = [*remaining, "--", *non_options]
check_named_args(named_args, allow_no_named_args: allow_no_named_args)
@args.freeze_named_args!(named_args)
@args.freeze_processed_options!(@processed_options)
Homebrew.args = @args
@args_parsed = true formulae(argv).each do |f|
@args
end
def global_option?(name, desc)
Homebrew::CLI::Parser.global_options.key?(name.to_sym) &&
Homebrew::CLI::Parser.global_options[name.to_sym].last == desc
end
def generate_help_text
@parser.to_s
.sub(/^/, "#{Tty.bold}Usage: brew#{Tty.reset} ")
.gsub(/`(.*?)`/m, "#{Tty.bold}\\1#{Tty.reset}")
.gsub(%r{<([^\s]+?://[^\s]+?)>}) { |url| Formatter.url(url) }
.gsub(/<(.*?)>/m, "#{Tty.underline}\\1#{Tty.reset}")
.gsub(/\*(.*?)\*/m, "#{Tty.underline}\\1#{Tty.reset}")
end
def formula_options
formulae.each do |f|
next if f.options.empty? next if f.options.empty?
f.options.each do |o| f.options.each do |o|
@ -202,8 +213,37 @@ module Homebrew
end end
end end
end end
rescue FormulaUnavailableError end
remaining, non_options = parse_remaining(argv, ignore_invalid_options: ignore_invalid_options)
named_args = if ignore_invalid_options
[] []
else
remaining + non_options
end
check_constraint_violations unless ignore_invalid_options
check_named_args(named_args) unless ignore_invalid_options
@args.freeze_named_args!(named_args)
@args.freeze_remaining_args!(non_options.empty? ? remaining : [*remaining, "--", non_options])
@args.freeze_processed_options!(@processed_options)
@args_parsed = true
@args
end
def generate_help_text
@parser.to_s
.sub(/^/, "#{Tty.bold}Usage: brew#{Tty.reset} ")
.gsub(/`(.*?)`/m, "#{Tty.bold}\\1#{Tty.reset}")
.gsub(%r{<([^\s]+?://[^\s]+?)>}) { |url| Formatter.url(url) }
.gsub(/<(.*?)>/m, "#{Tty.underline}\\1#{Tty.reset}")
.gsub(/\*(.*?)\*/m, "#{Tty.underline}\\1#{Tty.reset}")
end
def formula_options
@formula_options = true
end end
def max_named(count) def max_named(count)
@ -257,11 +297,6 @@ module Homebrew
end end
end end
# These are common/global switches accessible throughout Homebrew
def common_switch(name)
Homebrew::CLI::Parser.global_options.fetch(name, name)
end
def option_passed?(name) def option_passed?(name)
@args[name.to_sym] || @args["#{name}?".to_sym] @args[name.to_sym] || @args["#{name}?".to_sym]
end end
@ -329,8 +364,10 @@ module Homebrew
check_constraints check_constraints
end end
def check_named_args(args, allow_no_named_args: false) def check_named_args(args)
min_exception = case @min_named_type min_exception = case @min_named_type
when :cask
Cask::CaskUnspecifiedError.new
when :formula when :formula
FormulaUnspecifiedError.new FormulaUnspecifiedError.new
when :keg when :keg
@ -338,8 +375,8 @@ module Homebrew
else else
MinNamedArgumentsError.new(@min_named_args) MinNamedArgumentsError.new(@min_named_args)
end end
raise min_exception if !allow_no_named_args && !@min_named_args.nil? && args.size < @min_named_args raise min_exception if @min_named_args && args.size < @min_named_args
raise MaxNamedArgumentsError, @max_named_args if !@max_named_args.nil? && args.size > @max_named_args raise MaxNamedArgumentsError, @max_named_args if @max_named_args && args.size > @max_named_args
end end
def process_option(*args) def process_option(*args)
@ -347,11 +384,21 @@ module Homebrew
@processed_options << [option.short.first, option.long.first, option.arg, option.desc.first] @processed_options << [option.short.first, option.long.first, option.arg, option.desc.first]
end end
def formulae def split_non_options(argv)
named_args = @argv.reject { |arg| arg.start_with?("-") } if sep = argv.index("--")
spec = if @argv.include?("--HEAD") [argv.take(sep), argv.drop(sep + 1)]
else
[argv, []]
end
end
def formulae(argv)
argv, non_options = split_non_options(argv)
named_args = argv.reject { |arg| arg.start_with?("-") } + non_options
spec = if argv.include?("--HEAD")
:head :head
elsif @argv.include?("--devel") elsif argv.include?("--devel")
:devel :devel
else else
:stable :stable
@ -361,7 +408,11 @@ 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)
Formulary.factory(arg, spec) begin
Formulary.factory(arg, spec, flags: argv.select { |a| a.start_with?("--") })
rescue FormulaUnavailableError
nil
end
end.compact.uniq(&:name) end.compact.uniq(&:name)
end end
end end

View File

@ -33,13 +33,13 @@ module Homebrew
end end
def __cache def __cache
__cache_args.parse args = __cache_args.parse
if args.no_named? if args.no_named?
puts HOMEBREW_CACHE puts HOMEBREW_CACHE
elsif args.formula? elsif args.formula?
args.named.each do |name| args.named.each do |name|
print_formula_cache name print_formula_cache name, args: args
end end
elsif args.cask? elsif args.cask?
args.named.each do |name| args.named.each do |name|
@ -47,7 +47,7 @@ module Homebrew
end end
else else
args.named.each do |name| args.named.each do |name|
print_formula_cache name print_formula_cache name, args: args
rescue FormulaUnavailableError rescue FormulaUnavailableError
begin begin
print_cask_cache name print_cask_cache name
@ -58,9 +58,9 @@ module Homebrew
end end
end end
def print_formula_cache(name) def print_formula_cache(name, args:)
formula = Formulary.factory name formula = Formulary.factory(name, force_bottle: args.force_bottle?, flags: args.flags_only)
if fetch_bottle?(formula) if fetch_bottle?(formula, args: args)
puts formula.bottle.cached_download puts formula.bottle.cached_download
else else
puts formula.cached_download puts formula.cached_download

View File

@ -20,7 +20,7 @@ module Homebrew
end end
def __cellar def __cellar
__cellar_args.parse args = __cellar_args.parse
if args.no_named? if args.no_named?
puts HOMEBREW_CELLAR puts HOMEBREW_CELLAR

View File

@ -29,9 +29,9 @@ module Homebrew
def __env def __env
args = __env_args.parse args = __env_args.parse
ENV.activate_extensions!(args: args) ENV.activate_extensions!(env: args.env)
ENV.deps = args.formulae if superenv?(args: args) ENV.deps = args.formulae if superenv?(args.env)
ENV.setup_build_environment(args: args) ENV.setup_build_environment
shell = if args.plain? shell = if args.plain?
nil nil

View File

@ -20,7 +20,7 @@ module Homebrew
end end
def __prefix def __prefix
__prefix_args.parse args = __prefix_args.parse
if args.no_named? if args.no_named?
puts HOMEBREW_PREFIX puts HOMEBREW_PREFIX

View File

@ -18,7 +18,7 @@ module Homebrew
end end
def __repository def __repository
__repository_args.parse args = __repository_args.parse
if args.no_named? if args.no_named?
puts HOMEBREW_REPOSITORY puts HOMEBREW_REPOSITORY

View File

@ -22,14 +22,12 @@ module Homebrew
`brew analytics regenerate-uuid`: `brew analytics regenerate-uuid`:
Regenerate the UUID used for Homebrew's analytics. Regenerate the UUID used for Homebrew's analytics.
EOS EOS
switch :verbose
switch :debug
max_named 1 max_named 1
end end
end end
def analytics def analytics
analytics_args.parse args = analytics_args.parse
case args.named.first case args.named.first
when nil, "state" when nil, "state"

View File

@ -27,13 +27,11 @@ module Homebrew
"If you want to delete those too: `rm -rf \"$(brew --cache)\"`" "If you want to delete those too: `rm -rf \"$(brew --cache)\"`"
switch "--prune-prefix", switch "--prune-prefix",
description: "Only prune the symlinks and directories from the prefix and remove no other files." description: "Only prune the symlinks and directories from the prefix and remove no other files."
switch :verbose
switch :debug
end end
end end
def cleanup def cleanup
cleanup_args.parse args = cleanup_args.parse
cleanup = Cleanup.new(*args.named, dry_run: args.dry_run?, scrub: args.s?, days: args.prune&.to_i) cleanup = Cleanup.new(*args.named, dry_run: args.dry_run?, scrub: args.s?, days: args.prune&.to_i)
if args.prune_prefix? if args.prune_prefix?

View File

@ -12,33 +12,39 @@ module Homebrew
Show lists of built-in and external commands. Show lists of built-in and external commands.
EOS EOS
switch :quiet, switch "-q", "--quiet",
description: "List only the names of commands without category headers." description: "List only the names of commands without category headers."
switch "--include-aliases", switch "--include-aliases",
depends_on: "--quiet", depends_on: "--quiet",
description: "Include aliases of internal commands." description: "Include aliases of internal commands."
switch :verbose
switch :debug
max_named 0 max_named 0
end end
end end
def commands def commands
commands_args.parse args = commands_args.parse
if args.quiet? if args.quiet?
puts Formatter.columns(Commands.commands(aliases: args.include_aliases?)) puts Formatter.columns(Commands.commands(aliases: args.include_aliases?))
return return
end end
ohai "Built-in commands", Formatter.columns(Commands.internal_commands) prepend_separator = false
puts
ohai "Built-in developer commands", Formatter.columns(Commands.internal_developer_commands)
external_commands = Commands.external_commands {
return if external_commands.blank? "Built-in commands" => Commands.internal_commands,
"Built-in developer commands" => Commands.internal_developer_commands,
"External commands" => Commands.external_commands,
"Cask commands" => Commands.cask_internal_commands,
"External cask commands" => Commands.cask_external_commands,
}.each do |title, commands|
next if commands.blank?
puts puts if prepend_separator
ohai "External commands", Formatter.columns(external_commands) ohai title, Formatter.columns(commands)
prepend_separator ||= true
end
end end
end end

View File

@ -14,8 +14,7 @@ module Homebrew
Show Homebrew and system configuration info useful for debugging. If you file Show Homebrew and system configuration info useful for debugging. If you file
a bug report, you will be required to provide this information. a bug report, you will be required to provide this information.
EOS EOS
switch :verbose
switch :debug
max_named 0 max_named 0
end end
end end

View File

@ -3,6 +3,8 @@
require "formula" require "formula"
require "ostruct" require "ostruct"
require "cli/parser" require "cli/parser"
require "cask/caskroom"
require "dependencies_helpers"
module Homebrew module Homebrew
extend DependenciesHelpers extend DependenciesHelpers
@ -51,67 +53,73 @@ module Homebrew
description: "Switch into the mode used by the `--all` option, but only list dependencies "\ description: "Switch into the mode used by the `--all` option, but only list dependencies "\
"for each provided <formula>, one formula per line. This is used for "\ "for each provided <formula>, one formula per line. This is used for "\
"debugging the `--installed`/`--all` display mode." "debugging the `--installed`/`--all` display mode."
switch :verbose
switch :debug
conflicts "--installed", "--all" conflicts "--installed", "--all"
formula_options formula_options
end end
end end
def deps def deps
deps_args.parse args = deps_args.parse
Formulary.enable_factory_cache! Formulary.enable_factory_cache!
recursive = !args.send("1?") recursive = !args.send("1?")
installed = args.installed? || args.formulae.all?(&:opt_or_installed_prefix_keg) installed = args.installed? || dependents(args.formulae_and_casks).all?(&:any_version_installed?)
@use_runtime_dependencies = installed && recursive && @use_runtime_dependencies = installed && recursive &&
!args.tree? &&
!args.include_build? && !args.include_build? &&
!args.include_test? && !args.include_test? &&
!args.include_optional? && !args.include_optional? &&
!args.skip_recommended? !args.skip_recommended?
if args.tree? if args.tree?
if args.installed? dependents = if args.named.present?
puts_deps_tree Formula.installed.sort, recursive sorted_dependents(args.formulae_and_casks)
elsif args.installed?
sorted_dependents(Formula.installed + Cask::Caskroom.casks)
else else
raise FormulaUnspecifiedError if args.no_named? raise FormulaUnspecifiedError
puts_deps_tree args.formulae, recursive
end end
puts_deps_tree dependents, recursive, args: args
return return
elsif args.all? elsif args.all?
puts_deps Formula.sort, recursive puts_deps sorted_dependents(Formula.to_a + Cask::Cask.to_a), recursive, args: args
return return
elsif !args.no_named? && args.for_each? elsif !args.no_named? && args.for_each?
puts_deps args.formulae, recursive puts_deps sorted_dependents(args.formulae_and_casks), recursive, args: args
return return
end end
if args.no_named? if args.no_named?
raise FormulaUnspecifiedError unless args.installed? raise FormulaUnspecifiedError unless args.installed?
puts_deps Formula.installed.sort, recursive puts_deps sorted_dependents(Formula.installed + Cask::Caskroom.casks), recursive
return return
end end
all_deps = deps_for_formulae(args.formulae, recursive, &(args.union? ? :| : :&)) dependents = dependents(args.formulae_and_casks)
all_deps = condense_requirements(all_deps)
all_deps.select!(&:installed?) if args.installed? all_deps = deps_for_dependents(dependents, recursive, args: args, &(args.union? ? :| : :&))
all_deps.map!(&method(:dep_display_name)) condense_requirements(all_deps, args: args)
all_deps.map! { |d| dep_display_name(d, args: args) }
all_deps.uniq! all_deps.uniq!
all_deps.sort! unless args.n? all_deps.sort! unless args.n?
puts all_deps puts all_deps
end end
def condense_requirements(deps) def sorted_dependents(formulae_or_casks)
return deps if args.include_requirements? dependents(formulae_or_casks).sort_by(&:name)
deps.select { |dep| dep.is_a? Dependency }
end end
def dep_display_name(dep) def condense_requirements(deps, args:)
deps.select! { |dep| dep.is_a?(Dependency) } unless args.include_requirements?
deps.select! { |dep| dep.is_a?(Requirement) || dep.installed? } if args.installed?
end
def dep_display_name(dep, args:)
str = if dep.is_a? Requirement str = if dep.is_a? Requirement
if args.include_requirements? if args.include_requirements?
":#{dep.display_s}" ":#{dep.display_s}"
@ -136,47 +144,47 @@ module Homebrew
str str
end end
def deps_for_formula(f, recursive = false) def deps_for_dependent(d, recursive = false, args:)
includes, ignores = argv_includes_ignores(ARGV) includes, ignores = args_includes_ignores(args)
deps = f.runtime_dependencies if @use_runtime_dependencies deps = d.runtime_dependencies if @use_runtime_dependencies
if recursive if recursive
deps ||= recursive_includes(Dependency, f, includes, ignores) deps ||= recursive_includes(Dependency, d, includes, ignores)
reqs = recursive_includes(Requirement, f, includes, ignores) reqs = recursive_includes(Requirement, d, includes, ignores)
else else
deps ||= reject_ignores(f.deps, ignores, includes) deps ||= reject_ignores(d.deps, ignores, includes)
reqs = reject_ignores(f.requirements, ignores, includes) reqs = reject_ignores(d.requirements, ignores, includes)
end end
deps + reqs.to_a deps + reqs.to_a
end end
def deps_for_formulae(formulae, recursive = false, &block) def deps_for_dependents(dependents, recursive = false, args:, &block)
formulae.map { |f| deps_for_formula(f, recursive) }.reduce(&block) dependents.map { |d| deps_for_dependent(d, recursive, args: args) }.reduce(&block)
end end
def puts_deps(formulae, recursive = false) def puts_deps(dependents, recursive = false, args:)
formulae.each do |f| dependents.each do |dependent|
deps = deps_for_formula(f, recursive) deps = deps_for_dependent(dependent, recursive, args: args)
deps = condense_requirements(deps) condense_requirements(deps, args: args)
deps.sort_by!(&:name) deps.sort_by!(&:name)
deps.map!(&method(:dep_display_name)) deps.map! { |d| dep_display_name(d, args: args) }
puts "#{f.full_name}: #{deps.join(" ")}" puts "#{dependent.full_name}: #{deps.join(" ")}"
end end
end end
def puts_deps_tree(formulae, recursive = false) def puts_deps_tree(dependents, recursive = false, args:)
formulae.each do |f| dependents.each do |d|
puts f.full_name puts d.full_name
@dep_stack = [] @dep_stack = []
recursive_deps_tree(f, "", recursive) recursive_deps_tree(d, "", recursive, args: args)
puts puts
end end
end end
def recursive_deps_tree(f, prefix, recursive) def recursive_deps_tree(f, prefix, recursive, args:)
includes, ignores = argv_includes_ignores(ARGV) includes, ignores = args_includes_ignores(args)
dependables = @use_runtime_dependencies ? f.runtime_dependencies : f.deps dependables = @use_runtime_dependencies ? f.runtime_dependencies : f.deps
deps = reject_ignores(dependables, ignores, includes) deps = reject_ignores(dependables, ignores, includes)
reqs = reject_ignores(f.requirements, ignores, includes) reqs = reject_ignores(f.requirements, ignores, includes)
@ -193,7 +201,7 @@ module Homebrew
"├──" "├──"
end end
display_s = "#{tree_lines} #{dep_display_name(dep)}" display_s = "#{tree_lines} #{dep_display_name(dep, args: args)}"
is_circular = @dep_stack.include?(dep.name) is_circular = @dep_stack.include?(dep.name)
display_s = "#{display_s} (CIRCULAR DEPENDENCY)" if is_circular display_s = "#{display_s} (CIRCULAR DEPENDENCY)" if is_circular
puts "#{prefix}#{display_s}" puts "#{prefix}#{display_s}"
@ -206,7 +214,9 @@ module Homebrew
"" ""
end end
recursive_deps_tree(Formulary.factory(dep.name), prefix + prefix_addition, true) if dep.is_a? Dependency if dep.is_a? Dependency
recursive_deps_tree(Formulary.factory(dep.name), prefix + prefix_addition, true, args: args)
end
end end
@dep_stack.pop @dep_stack.pop

View File

@ -28,14 +28,14 @@ module Homebrew
switch "-d", "--description", switch "-d", "--description",
description: "Search just descriptions for <text>. If <text> is flanked by slashes, "\ description: "Search just descriptions for <text>. If <text> is flanked by slashes, "\
"it is interpreted as a regular expression." "it is interpreted as a regular expression."
switch :verbose
conflicts "--search", "--name", "--description" conflicts "--search", "--name", "--description"
min_named 1 min_named 1
end end
end end
def desc def desc
desc_args.parse args = desc_args.parse
search_type = if args.search? search_type = if args.search?
:either :either

View File

@ -23,13 +23,11 @@ module Homebrew
"if provided as arguments." "if provided as arguments."
switch "-D", "--audit-debug", switch "-D", "--audit-debug",
description: "Enable debugging and profiling of audit methods." description: "Enable debugging and profiling of audit methods."
switch :verbose
switch :debug
end end
end end
def doctor def doctor
doctor_args.parse args = doctor_args.parse
inject_dump_stats!(Diagnostic::Checks, /^check_*/) if args.audit_debug? inject_dump_stats!(Diagnostic::Checks, /^check_*/) if args.audit_debug?

View File

@ -21,9 +21,9 @@ module Homebrew
description: "Fetch HEAD version instead of stable version." description: "Fetch HEAD version instead of stable version."
switch "--devel", switch "--devel",
description: "Fetch development version instead of stable version." description: "Fetch development version instead of stable version."
switch :force, switch "-f", "--force",
description: "Remove a previously cached version and re-fetch." description: "Remove a previously cached version and re-fetch."
switch :verbose, switch "-v", "--verbose",
description: "Do a verbose VCS checkout, if the URL represents a VCS. This is useful for "\ description: "Do a verbose VCS checkout, if the URL represents a VCS. This is useful for "\
"seeing if an existing VCS cache has been updated." "seeing if an existing VCS cache has been updated."
switch "--retry", switch "--retry",
@ -38,7 +38,7 @@ module Homebrew
switch "--force-bottle", switch "--force-bottle",
description: "Download a bottle if it exists for the current or newest version of macOS, "\ description: "Download a bottle if it exists for the current or newest version of macOS, "\
"even if it would not be used during installation." "even if it would not be used during installation."
switch :debug
conflicts "--devel", "--HEAD" conflicts "--devel", "--HEAD"
conflicts "--build-from-source", "--build-bottle", "--force-bottle" conflicts "--build-from-source", "--build-bottle", "--force-bottle"
min_named :formula min_named :formula
@ -46,7 +46,7 @@ module Homebrew
end end
def fetch def fetch
fetch_args.parse args = fetch_args.parse
if args.deps? if args.deps?
bucket = [] bucket = []
@ -64,9 +64,9 @@ module Homebrew
f.print_tap_action verb: "Fetching" f.print_tap_action verb: "Fetching"
fetched_bottle = false fetched_bottle = false
if fetch_bottle?(f) if fetch_bottle?(f, args: args)
begin begin
fetch_formula(f.bottle) fetch_formula(f.bottle, args: args)
rescue Interrupt rescue Interrupt
raise raise
rescue => e rescue => e
@ -82,40 +82,40 @@ module Homebrew
next if fetched_bottle next if fetched_bottle
fetch_formula(f) fetch_formula(f, args: args)
f.resources.each do |r| f.resources.each do |r|
fetch_resource(r) fetch_resource(r, args: args)
r.patches.each { |p| fetch_patch(p) if p.external? } r.patches.each { |p| fetch_patch(p, args: args) if p.external? }
end end
f.patchlist.each { |p| fetch_patch(p) if p.external? } f.patchlist.each { |p| fetch_patch(p, args: args) if p.external? }
end end
end end
def fetch_resource(r) def fetch_resource(r, args:)
puts "Resource: #{r.name}" puts "Resource: #{r.name}"
fetch_fetchable r fetch_fetchable r, args: args
rescue ChecksumMismatchError => e rescue ChecksumMismatchError => e
retry if retry_fetch? r retry if retry_fetch?(r, args: args)
opoo "Resource #{r.name} reports different #{e.hash_type}: #{e.expected}" opoo "Resource #{r.name} reports different #{e.hash_type}: #{e.expected}"
end end
def fetch_formula(f) def fetch_formula(f, args:)
fetch_fetchable f fetch_fetchable f, args: args
rescue ChecksumMismatchError => e rescue ChecksumMismatchError => e
retry if retry_fetch? f retry if retry_fetch?(f, args: args)
opoo "Formula reports different #{e.hash_type}: #{e.expected}" opoo "Formula reports different #{e.hash_type}: #{e.expected}"
end end
def fetch_patch(p) def fetch_patch(p, args:)
fetch_fetchable p fetch_fetchable p, args: args
rescue ChecksumMismatchError => e rescue ChecksumMismatchError => e
Homebrew.failed = true Homebrew.failed = true
opoo "Patch reports different #{e.hash_type}: #{e.expected}" opoo "Patch reports different #{e.hash_type}: #{e.expected}"
end end
def retry_fetch?(f) def retry_fetch?(f, args:)
@fetch_failed ||= Set.new @fetch_failed ||= Set.new
if args.retry? && @fetch_failed.add?(f) if args.retry? && @fetch_failed.add?(f)
ohai "Retrying download" ohai "Retrying download"
@ -127,7 +127,7 @@ module Homebrew
end end
end end
def fetch_fetchable(f) def fetch_fetchable(f, args:)
f.clear_cache if args.force? f.clear_cache if args.force?
already_fetched = f.cached_download.exist? already_fetched = f.cached_download.exist?
@ -135,7 +135,7 @@ module Homebrew
begin begin
download = f.fetch(verify_download_integrity: false) download = f.fetch(verify_download_integrity: false)
rescue DownloadError rescue DownloadError
retry if retry_fetch? f retry if retry_fetch?(f, args: args)
raise raise
end end

View File

@ -8,6 +8,8 @@ require "socket"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend Install
module_function module_function
def gist_logs_args def gist_logs_args
@ -26,13 +28,12 @@ module Homebrew
switch "-p", "--private", switch "-p", "--private",
description: "The Gist will be marked private and will not appear in listings but will "\ description: "The Gist will be marked private and will not appear in listings but will "\
"be accessible with its link." "be accessible with its link."
switch :verbose
switch :debug
named :formula named :formula
end end
end end
def gistify_logs(f) def gistify_logs(f, args:)
files = load_logs(f.logs) files = load_logs(f.logs)
build_time = f.logs.ctime build_time = f.logs.ctime
timestamp = build_time.strftime("%Y-%m-%d_%H-%M-%S") timestamp = build_time.strftime("%Y-%m-%d_%H-%M-%S")
@ -40,7 +41,7 @@ module Homebrew
s = StringIO.new s = StringIO.new
SystemConfig.dump_verbose_config s SystemConfig.dump_verbose_config s
# Dummy summary file, asciibetically first, to control display title of gist # Dummy summary file, asciibetically first, to control display title of gist
files["# #{f.name} - #{timestamp}.txt"] = { content: brief_build_info(f) } files["# #{f.name} - #{timestamp}.txt"] = { content: brief_build_info(f, with_hostname: args.with_hostname?) }
files["00.config.out"] = { content: s.string } files["00.config.out"] = { content: s.string }
files["00.doctor.out"] = { content: Utils.popen_read("#{HOMEBREW_PREFIX}/bin/brew", "doctor", err: :out) } files["00.doctor.out"] = { content: Utils.popen_read("#{HOMEBREW_PREFIX}/bin/brew", "doctor", err: :out) }
unless f.core_formula? unless f.core_formula?
@ -68,19 +69,19 @@ module Homebrew
else else
"#{f.name} (#{f.full_name}) on #{OS_VERSION} - Homebrew build logs" "#{f.name} (#{f.full_name}) on #{OS_VERSION} - Homebrew build logs"
end end
url = create_gist(files, descr) url = create_gist(files, descr, private: args.private?)
url = create_issue(f.tap, "#{f.name} failed to build on #{MacOS.full_version}", url) if args.new_issue? url = create_issue(f.tap, "#{f.name} failed to build on #{MacOS.full_version}", url) if args.new_issue?
puts url if url puts url if url
end end
def brief_build_info(f) def brief_build_info(f, with_hostname:)
build_time_str = f.logs.ctime.strftime("%Y-%m-%d %H:%M:%S") build_time_str = f.logs.ctime.strftime("%Y-%m-%d %H:%M:%S")
s = +<<~EOS s = +<<~EOS
Homebrew build logs for #{f.full_name} on #{OS_VERSION} Homebrew build logs for #{f.full_name} on #{OS_VERSION}
EOS EOS
if args.with_hostname? if with_hostname
hostname = Socket.gethostname hostname = Socket.gethostname
s << "Host: #{hostname}\n" s << "Host: #{hostname}\n"
end end
@ -121,13 +122,9 @@ module Homebrew
logs logs
end end
def create_private? def create_gist(files, description, private:)
args.private?
end
def create_gist(files, description)
url = "https://api.github.com/gists" url = "https://api.github.com/gists"
data = { "public" => !create_private?, "files" => files, "description" => description } data = { "public" => !private, "files" => files, "description" => description }
scopes = GitHub::CREATE_GIST_SCOPES scopes = GitHub::CREATE_GIST_SCOPES
GitHub.open_api(url, data: data, scopes: scopes)["html_url"] GitHub.open_api(url, data: data, scopes: scopes)["html_url"]
end end
@ -140,10 +137,10 @@ module Homebrew
end end
def gist_logs def gist_logs
gist_logs_args.parse args = gist_logs_args.parse
Install.perform_preinstall_checks(all_fatal: true) Install.perform_preinstall_checks(all_fatal: true)
Install.perform_build_from_source_checks(all_fatal: true) Install.perform_build_from_source_checks(all_fatal: true)
gistify_logs(args.resolved_formulae.first) gistify_logs(args.resolved_formulae.first, args: args)
end end
end end

View File

@ -15,12 +15,11 @@ module Homebrew
Open <formula>'s homepage in a browser, or open Homebrew's own homepage Open <formula>'s homepage in a browser, or open Homebrew's own homepage
if no formula is provided. if no formula is provided.
EOS EOS
switch :debug
end end
end end
def home def home
home_args.parse args = home_args.parse
if args.no_named? if args.no_named?
exec_browser HOMEBREW_WWW exec_browser HOMEBREW_WWW

View File

@ -52,15 +52,15 @@ module Homebrew
switch "--all", switch "--all",
depends_on: "--json", depends_on: "--json",
description: "Print JSON of all available formulae." description: "Print JSON of all available formulae."
switch :verbose, switch "-v", "--verbose",
description: "Show more verbose analytics data for <formula>." description: "Show more verbose analytics data for <formula>."
switch :debug
conflicts "--installed", "--all" conflicts "--installed", "--all"
end end
end end
def info def info
info_args.parse args = info_args.parse
if args.days.present? if args.days.present?
raise UsageError, "--days must be one of #{VALID_DAYS.join(", ")}" unless VALID_DAYS.include?(args.days) raise UsageError, "--days must be one of #{VALID_DAYS.join(", ")}" unless VALID_DAYS.include?(args.days)
@ -83,17 +83,17 @@ module Homebrew
raise FormulaUnspecifiedError if args.no_named? raise FormulaUnspecifiedError if args.no_named?
end end
print_json print_json(args: args)
elsif args.github? elsif args.github?
raise FormulaUnspecifiedError if args.no_named? raise FormulaUnspecifiedError if args.no_named?
exec_browser(*args.formulae.map { |f| github_info(f) }) exec_browser(*args.formulae.map { |f| github_info(f) })
else else
print_info print_info(args: args)
end end
end end
def print_info def print_info(args:)
if args.no_named? if args.no_named?
if args.analytics? if args.analytics?
Utils::Analytics.output(args: args) Utils::Analytics.output(args: args)
@ -126,7 +126,7 @@ module Homebrew
end end
end end
def print_json def print_json(args:)
ff = if args.all? ff = if args.all?
Formula.sort Formula.sort
elsif args.installed? elsif args.installed?
@ -211,7 +211,7 @@ module Homebrew
puts "From: #{Formatter.url(github_info(f))}" puts "From: #{Formatter.url(github_info(f))}"
puts "License: #{f.license}" if f.license puts "License: #{f.license.join(", ")}" if f.license
unless f.deps.empty? unless f.deps.empty?
ohai "Dependencies" ohai "Dependencies"
@ -256,7 +256,7 @@ module Homebrew
def decorate_requirements(requirements) def decorate_requirements(requirements)
req_status = requirements.map do |req| req_status = requirements.map do |req|
req_s = req.display_s req_s = req.display_s
req.satisfied?(args: args) ? pretty_installed(req_s) : pretty_uninstalled(req_s) req.satisfied? ? pretty_installed(req_s) : pretty_uninstalled(req_s)
end end
req_status.join(", ") req_status.join(", ")
end end

View File

@ -10,10 +10,10 @@ require "cli/parser"
require "upgrade" require "upgrade"
module Homebrew module Homebrew
module_function
extend Search extend Search
module_function
def install_args def install_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
@ -24,7 +24,7 @@ module Homebrew
Unless `HOMEBREW_NO_INSTALL_CLEANUP` is set, `brew cleanup` will then be run for the Unless `HOMEBREW_NO_INSTALL_CLEANUP` is set, `brew cleanup` will then be run for the
installed formulae or, every 30 days, for all formulae. installed formulae or, every 30 days, for all formulae.
EOS EOS
switch :debug, switch "-d", "--debug",
description: "If brewing fails, open an interactive debugging session with access to IRB "\ description: "If brewing fails, open an interactive debugging session with access to IRB "\
"or a shell inside the temporary build directory." "or a shell inside the temporary build directory."
flag "--env=", flag "--env=",
@ -71,10 +71,10 @@ module Homebrew
depends_on: "--build-bottle", depends_on: "--build-bottle",
description: "Optimise bottles for the specified architecture rather than the oldest "\ description: "Optimise bottles for the specified architecture rather than the oldest "\
"architecture supported by the version of macOS the bottles are built on." "architecture supported by the version of macOS the bottles are built on."
switch :force, switch "-f", "--force",
description: "Install without checking for previously installed keg-only or "\ description: "Install without checking for previously installed keg-only or "\
"non-migrated versions." "non-migrated versions."
switch :verbose, switch "-v", "--verbose",
description: "Print the verification and postinstall steps." description: "Print the verification and postinstall steps."
switch "--display-times", switch "--display-times",
env: :display_install_times, env: :display_install_times,
@ -115,13 +115,13 @@ module Homebrew
formulae = [] formulae = []
unless Homebrew.args.casks.empty? unless args.casks.empty?
cask_args = [] cask_args = []
cask_args << "--force" if args.force? cask_args << "--force" if args.force?
cask_args << "--debug" if args.debug? cask_args << "--debug" if args.debug?
cask_args << "--verbose" if args.verbose? cask_args << "--verbose" if args.verbose?
Homebrew.args.casks.each do |c| args.casks.each do |c|
ohai "brew cask install #{c} #{cask_args.join " "}" ohai "brew cask install #{c} #{cask_args.join " "}"
system("#{HOMEBREW_PREFIX}/bin/brew", "cask", "install", c, *cask_args) system("#{HOMEBREW_PREFIX}/bin/brew", "cask", "install", c, *cask_args)
end end
@ -129,7 +129,7 @@ module Homebrew
# if the user's flags will prevent bottle only-installations when no # if the user's flags will prevent bottle only-installations when no
# developer tools are available, we need to stop them early on # developer tools are available, we need to stop them early on
FormulaInstaller.prevent_build_flags unless DevelopmentTools.installed? FormulaInstaller.prevent_build_flags(args)
args.formulae.each do |f| args.formulae.each do |f|
# head-only without --HEAD is an error # head-only without --HEAD is an error
@ -255,17 +255,17 @@ module Homebrew
return if formulae.empty? return if formulae.empty?
Install.perform_preinstall_checks Install.perform_preinstall_checks(cc: args.cc)
formulae.each do |f| formulae.each do |f|
Migrator.migrate_if_needed(f) Migrator.migrate_if_needed(f, force: args.force?)
install_formula(f) install_formula(f, args: args)
Cleanup.install_formula_clean!(f) Cleanup.install_formula_clean!(f)
end end
check_installed_dependents(args: args) check_installed_dependents(args: args)
Homebrew.messages.display_messages Homebrew.messages.display_messages(display_times: args.display_times?)
rescue FormulaUnreadableError, FormulaClassUnavailableError, rescue FormulaUnreadableError, FormulaClassUnavailableError,
TapFormulaUnreadableError, TapFormulaClassUnavailableError => e TapFormulaUnreadableError, TapFormulaClassUnavailableError => e
# Need to rescue before `FormulaUnavailableError` (superclass of this) # Need to rescue before `FormulaUnavailableError` (superclass of this)
@ -319,12 +319,13 @@ module Homebrew
end end
end end
def install_formula(f) def install_formula(f, args:)
f.print_tap_action f.print_tap_action
build_options = f.build build_options = f.build
fi = FormulaInstaller.new(f, force_bottle: args.force_bottle?, include_test: args.include_test?, fi = FormulaInstaller.new(f, force_bottle: args.force_bottle?,
build_from_source: args.build_from_source?) include_test_formulae: args.include_test_formulae,
build_from_source_formulae: args.build_from_source_formulae)
fi.options = build_options.used_options fi.options = build_options.used_options
fi.env = args.env fi.env = args.env
fi.force = args.force? fi.force = args.force?

View File

@ -14,7 +14,7 @@ module Homebrew
List installed formulae that are not dependencies of another installed formula. List installed formulae that are not dependencies of another installed formula.
EOS EOS
switch :debug
max_named 0 max_named 0
end end
end end

View File

@ -21,16 +21,15 @@ module Homebrew
switch "-n", "--dry-run", switch "-n", "--dry-run",
description: "List files which would be linked or deleted by "\ description: "List files which would be linked or deleted by "\
"`brew link --overwrite` without actually linking or deleting any files." "`brew link --overwrite` without actually linking or deleting any files."
switch :force, switch "-f", "--force",
description: "Allow keg-only formulae to be linked." description: "Allow keg-only formulae to be linked."
switch :verbose
switch :debug
min_named :keg min_named :keg
end end
end end
def link def link
link_args.parse args = link_args.parse
mode = OpenStruct.new mode = OpenStruct.new

View File

@ -45,16 +45,15 @@ module Homebrew
description: "Reverse the order of the sort to list the oldest entries first." description: "Reverse the order of the sort to list the oldest entries first."
switch "-t", switch "-t",
description: "Sort by time modified, listing most recently modified first." description: "Sort by time modified, listing most recently modified first."
switch :verbose
switch :debug
["--unbrewed", "--multiple", "--pinned", "-l", "-r", "-t"].each { |flag| conflicts "--cask", flag } ["--unbrewed", "--multiple", "--pinned", "-l", "-r", "-t"].each { |flag| conflicts "--cask", flag }
end end
end end
def list def list
list_args.parse args = list_args.parse
return list_casks if args.cask? return list_casks(args: args) if args.cask?
return list_unbrewed if args.unbrewed? return list_unbrewed if args.unbrewed?
@ -67,7 +66,7 @@ module Homebrew
end end
if args.pinned? || args.versions? if args.pinned? || args.versions?
filtered_list filtered_list args: args
elsif args.no_named? elsif args.no_named?
if args.full_name? if args.full_name?
full_names = Formula.installed.map(&:full_name).sort(&tap_and_name_comparison) full_names = Formula.installed.map(&:full_name).sort(&tap_and_name_comparison)
@ -76,7 +75,14 @@ module Homebrew
puts Formatter.columns(full_names) puts Formatter.columns(full_names)
else else
ENV["CLICOLOR"] = nil ENV["CLICOLOR"] = nil
safe_system "ls", *args.passthrough << HOMEBREW_CELLAR
ls_args = []
ls_args << "-1" if args.public_send(:'1?')
ls_args << "-l" if args.l?
ls_args << "-r" if args.r?
ls_args << "-t" if args.t?
safe_system "ls", *ls_args, HOMEBREW_CELLAR
end end
elsif args.verbose? || !$stdout.tty? elsif args.verbose? || !$stdout.tty?
system_command! "find", args: args.kegs.map(&:to_s) + %w[-not -type d -print], print_stdout: true system_command! "find", args: args.kegs.map(&:to_s) + %w[-not -type d -print], print_stdout: true
@ -128,7 +134,7 @@ module Homebrew
safe_system "find", *arguments safe_system "find", *arguments
end end
def filtered_list def filtered_list(args:)
names = if args.no_named? names = if args.no_named?
Formula.racks Formula.racks
else else
@ -157,9 +163,9 @@ module Homebrew
end end
end end
def list_casks def list_casks(args:)
cask_list = Cask::Cmd::List.new args.named cask_list = Cask::Cmd::List.new args.named
cask_list.one = ARGV.include? "-1" cask_list.one = args.public_send(:'1?')
cask_list.versions = args.versions? cask_list.versions = args.versions?
cask_list.full_name = args.full_name? cask_list.full_name = args.full_name?
cask_list.run cask_list.run

View File

@ -20,14 +20,17 @@ module Homebrew
description: "Also print diffstat from commit." description: "Also print diffstat from commit."
switch "--oneline", switch "--oneline",
description: "Print only one line per commit." description: "Print only one line per commit."
flag "-1", "--max-count", switch "-1",
description: "Print only one or a specified number of commits." description: "Print only one commit."
flag "-n", "--max-count=",
description: "Print only a specified number of commits."
max_named 1 max_named 1
conflicts "-1", "--max-count"
end end
end end
def log def log
log_args.parse args = log_args.parse
# As this command is simplifying user-run commands then let's just use a # As this command is simplifying user-run commands then let's just use a
# user path, too. # user path, too.
@ -38,11 +41,11 @@ module Homebrew
else else
path = Formulary.path(args.named.first) path = Formulary.path(args.named.first)
tap = Tap.from_path(path) tap = Tap.from_path(path)
git_log path.dirname, path, tap git_log path.dirname, path, tap, args: args
end end
end end
def git_log(cd_dir, path = nil, tap = nil) def git_log(cd_dir, path = nil, tap = nil, args:)
cd cd_dir cd cd_dir
repo = Utils.popen_read("git rev-parse --show-toplevel").chomp repo = Utils.popen_read("git rev-parse --show-toplevel").chomp
if tap if tap
@ -62,8 +65,14 @@ module Homebrew
git -C "#{git_cd}" fetch --unshallow git -C "#{git_cd}" fetch --unshallow
EOS EOS
end end
system_args = args.options_only
system_args += ["--follow", "--", path] if path.present? git_args = []
system "git", "log", *system_args git_args << "--patch" if args.patch?
git_args << "--stat" if args.stat?
git_args << "--oneline" if args.oneline?
git_args << "-1" if args.public_send(:'1?')
git_args << "--max-count" << args.max_count if args.max_count
git_args += ["--follow", "--", path] if path.present?
system "git", "log", *git_args
end end
end end

View File

@ -14,17 +14,16 @@ module Homebrew
Migrate renamed packages to new names, where <formula> are old names of Migrate renamed packages to new names, where <formula> are old names of
packages. packages.
EOS EOS
switch :force, switch "-f", "--force",
description: "Treat installed <formula> and provided <formula> as if they are from "\ description: "Treat installed <formula> and provided <formula> as if they are from "\
"the same taps and migrate them anyway." "the same taps and migrate them anyway."
switch :verbose
switch :debug
min_named :formula min_named :formula
end end
end end
def migrate def migrate
migrate_args.parse args = migrate_args.parse
args.resolved_formulae.each do |f| args.resolved_formulae.each do |f|
if f.oldname if f.oldname
@ -34,7 +33,7 @@ module Homebrew
raise "#{rack} is a symlink" if rack.symlink? raise "#{rack} is a symlink" if rack.symlink?
end end
migrator = Migrator.new(f) migrator = Migrator.new(f, force: args.force?)
migrator.migrate migrator.migrate
end end
end end

View File

@ -20,13 +20,11 @@ module Homebrew
comma_array "--hide", comma_array "--hide",
description: "Act as if none of the specified <hidden> are installed. <hidden> should be "\ description: "Act as if none of the specified <hidden> are installed. <hidden> should be "\
"a comma-separated list of formulae." "a comma-separated list of formulae."
switch :verbose
switch :debug
end end
end end
def missing def missing
missing_args.parse args = missing_args.parse
return unless HOMEBREW_CELLAR.exist? return unless HOMEBREW_CELLAR.exist?

View File

@ -23,18 +23,18 @@ module Homebrew
description: "Show options for all available formulae." description: "Show options for all available formulae."
flag "--command=", flag "--command=",
description: "Show options for the specified <command>." description: "Show options for the specified <command>."
switch :debug
conflicts "--installed", "--all", "--command" conflicts "--installed", "--all", "--command"
end end
end end
def options def options
options_args.parse args = options_args.parse
if args.all? if args.all?
puts_options Formula.to_a.sort puts_options Formula.to_a.sort, args: args
elsif args.installed? elsif args.installed?
puts_options Formula.installed.sort puts_options Formula.installed.sort, args: args
elsif !args.command.nil? elsif !args.command.nil?
path = Commands.path(args.command) path = Commands.path(args.command)
odie "Unknown command: #{args.command}" unless path odie "Unknown command: #{args.command}" unless path
@ -54,7 +54,7 @@ module Homebrew
elsif args.no_named? elsif args.no_named?
raise FormulaUnspecifiedError raise FormulaUnspecifiedError
else else
puts_options args.formulae puts_options args.formulae, args: args
end end
end end
@ -72,7 +72,7 @@ module Homebrew
options options
end end
def puts_options(formulae) def puts_options(formulae, args:)
formulae.each do |f| formulae.each do |f|
next if f.options.empty? next if f.options.empty?

View File

@ -3,6 +3,8 @@
require "formula" require "formula"
require "keg" require "keg"
require "cli/parser" require "cli/parser"
require "cask/cmd"
require "cask/caskroom"
module Homebrew module Homebrew
module_function module_function
@ -15,51 +17,85 @@ module Homebrew
List installed formulae that have an updated version available. By default, version List installed formulae that have an updated version available. By default, version
information is displayed in interactive shells, and suppressed otherwise. information is displayed in interactive shells, and suppressed otherwise.
EOS EOS
switch :quiet, switch "-q", "--quiet",
description: "List only the names of outdated kegs (takes precedence over `--verbose`)." description: "List only the names of outdated kegs (takes precedence over `--verbose`)."
switch :verbose, switch "-v", "--verbose",
description: "Include detailed version information." description: "Include detailed version information."
flag "--json", flag "--json",
description: "Print output in JSON format. Currently the default and only accepted "\ description: "Print output in JSON format. There are two versions: v1 and v2. " \
"value for <version> is `v1`. See the docs for examples of using the JSON "\ "v1 is deprecated and is currently the default if no version is specified. " \
"output: <https://docs.brew.sh/Querying-Brew>" "v2 prints outdated formulae and casks. "
switch "--fetch-HEAD", switch "--fetch-HEAD",
description: "Fetch the upstream repository to detect if the HEAD installation of the "\ description: "Fetch the upstream repository to detect if the HEAD installation of the "\
"formula is outdated. Otherwise, the repository's HEAD will only be checked for "\ "formula is outdated. Otherwise, the repository's HEAD will only be checked for "\
"updates when a new stable or development version has been released." "updates when a new stable or development version has been released."
switch :debug switch "--greedy",
description: "Print outdated casks with `auto_updates` or `version :latest`."
switch "--formula",
description: "Treat all arguments as formulae."
switch "--cask",
description: "Treat all arguments as casks."
conflicts "--quiet", "--verbose", "--json" conflicts "--quiet", "--verbose", "--json"
conflicts "--formula", "--cask"
end end
end end
def outdated def outdated
outdated_args.parse args = outdated_args.parse
formulae = if args.resolved_formulae.blank? case json_version(args.json)
Formula.installed when :v1, :default
# TODO: enable for next major/minor release
# odeprecated "brew outdated --json#{json_version == :v1 ? "=v1" : ""}", "brew outdated --json=v2"
outdated = if args.formula? || !args.cask?
outdated_formulae args: args
else else
args.resolved_formulae outdated_casks args: args
end end
if args.json
raise UsageError, "invalid JSON version: #{args.json}" unless ["v1", true].include? args.json
outdated = print_outdated_json(formulae) puts JSON.generate(json_info(outdated, args: args))
when :v2
formulae, casks = if args.formula?
[outdated_formulae(args: args), []]
elsif args.cask?
[[], outdated_casks(args: args)]
else else
outdated = print_outdated(formulae) outdated_formulae_casks args: args
end
Homebrew.failed = args.resolved_formulae.present? && !outdated.empty?
end end
def print_outdated(formulae) json = {
verbose = ($stdout.tty? || args.verbose?) && !args.quiet? "formulae" => json_info(formulae, args: args),
fetch_head = args.fetch_HEAD? "casks" => json_info(casks, args: args),
}
puts JSON.generate(json)
outdated_formulae = formulae.select { |f| f.outdated?(fetch_head: fetch_head) } outdated = formulae + casks
.sort
outdated_formulae.each do |f| else
if verbose outdated = if args.formula?
outdated_kegs = f.outdated_kegs(fetch_head: fetch_head) outdated_formulae args: args
elsif args.cask?
outdated_casks args: args
else
outdated_formulae_casks(args: args).flatten
end
print_outdated(outdated, args: args)
end
Homebrew.failed = args.named.present? && outdated.present?
end
def print_outdated(formulae_or_casks, args:)
formulae_or_casks.each do |formula_or_cask|
if formula_or_cask.is_a?(Formula)
f = formula_or_cask
if verbose? args: args
outdated_kegs = f.outdated_kegs(fetch_head: args.fetch_HEAD?)
current_version = if f.alias_changed? current_version = if f.alias_changed?
latest = f.latest_formula latest = f.latest_formula
@ -71,8 +107,7 @@ module Homebrew
f.pkg_version.to_s f.pkg_version.to_s
end end
outdated_versions = outdated_kegs outdated_versions = outdated_kegs.group_by { |keg| Formulary.from_keg(keg).full_name }
.group_by { |keg| Formulary.from_keg(keg).full_name }
.sort_by { |full_name, _kegs| full_name } .sort_by { |full_name, _kegs| full_name }
.map do |full_name, kegs| .map do |full_name, kegs|
"#{full_name} (#{kegs.map(&:version).join(", ")})" "#{full_name} (#{kegs.map(&:version).join(", ")})"
@ -84,30 +119,86 @@ module Homebrew
else else
puts f.full_installed_specified_name puts f.full_installed_specified_name
end end
else
c = formula_or_cask
puts c.outdated_info(args.greedy?, verbose?(args: args), false)
end
end end
end end
def print_outdated_json(formulae) def json_info(formulae_or_casks, args:)
json = [] formulae_or_casks.map do |formula_or_cask|
fetch_head = args.fetch_HEAD? if formula_or_cask.is_a?(Formula)
outdated_formulae = formulae.select { |f| f.outdated?(fetch_head: fetch_head) } f = formula_or_cask
outdated = outdated_formulae.each do |f| outdated_versions = f.outdated_kegs(fetch_head: args.fetch_HEAD?).map(&:version)
outdated_versions = f.outdated_kegs(fetch_head: fetch_head).map(&:version)
current_version = if f.head? && outdated_versions.any? { |v| v.to_s == f.pkg_version.to_s } current_version = if f.head? && outdated_versions.any? { |v| v.to_s == f.pkg_version.to_s }
"HEAD" "HEAD"
else else
f.pkg_version.to_s f.pkg_version.to_s
end end
json << { name: f.full_name, { name: f.full_name,
installed_versions: outdated_versions.map(&:to_s), installed_versions: outdated_versions.map(&:to_s),
current_version: current_version, current_version: current_version,
pinned: f.pinned?, pinned: f.pinned?,
pinned_version: f.pinned_version } pinned_version: f.pinned_version }
end else
puts JSON.generate(json) c = formula_or_cask
outdated c.outdated_info(args.greedy?, verbose?(args: args), true)
end
end
end
def verbose?(args:)
($stdout.tty? || args.verbose?) && !args.quiet?
end
def json_version(version)
version_hash = {
nil => nil,
true => :default,
"v1" => :v1,
"v2" => :v2,
}
raise UsageError, "invalid JSON version: #{version}" unless version_hash.include?(version)
version_hash[version]
end
def outdated_formulae(args:)
select_outdated((args.resolved_formulae.presence || Formula.installed), args: args).sort
end
def outdated_casks(args:)
if args.named.present?
select_outdated(args.named.uniq.map(&Cask::CaskLoader.method(:load)), args: args)
else
select_outdated(Cask::Caskroom.casks, args: args)
end
end
def outdated_formulae_casks(args:)
formulae, casks = args.resolved_formulae_casks
if formulae.blank? && casks.blank?
formulae = Formula.installed
casks = Cask::Caskroom.casks
end
[select_outdated(formulae, args: args).sort, select_outdated(casks, args: args)]
end
def select_outdated(formulae_or_casks, args:)
formulae_or_casks.select do |formula_or_cask|
if formula_or_cask.is_a?(Formula)
formula_or_cask.outdated?(fetch_head: args.fetch_HEAD?)
else
formula_or_cask.outdated?(args.greedy?)
end
end
end end
end end

View File

@ -14,13 +14,13 @@ module Homebrew
Pin the specified <formula>, preventing them from being upgraded when Pin the specified <formula>, preventing them from being upgraded when
issuing the `brew upgrade` <formula> command. See also `unpin`. issuing the `brew upgrade` <formula> command. See also `unpin`.
EOS EOS
switch :debug
min_named :formula min_named :formula
end end
end end
def pin def pin
pin_args.parse args = pin_args.parse
args.resolved_formulae.each do |f| args.resolved_formulae.each do |f|
if f.pinned? if f.pinned?

View File

@ -14,9 +14,7 @@ module Homebrew
Rerun the post-install steps for <formula>. Rerun the post-install steps for <formula>.
EOS EOS
switch :force
switch :verbose
switch :debug
min_named :keg min_named :keg
end end
end end
@ -27,7 +25,6 @@ module Homebrew
args.resolved_formulae.each do |f| args.resolved_formulae.each do |f|
ohai "Postinstalling #{f}" ohai "Postinstalling #{f}"
fi = FormulaInstaller.new(f) fi = FormulaInstaller.new(f)
fi.force = args.force?
fi.post_install fi.post_install
end end
end end

View File

@ -19,16 +19,14 @@ module Homebrew
switch "--aliases", switch "--aliases",
description: "Verify any alias symlinks in each tap." description: "Verify any alias symlinks in each tap."
switch "--syntax", switch "--syntax",
description: "Syntax-check all of Homebrew's Ruby files." description: "Syntax-check all of Homebrew's Ruby files (if no `<tap>` is passed)."
switch :verbose
switch :debug
end end
end end
def readall def readall
readall_args.parse args = readall_args.parse
if args.syntax? if args.syntax? && args.no_named?
scan_files = "#{HOMEBREW_LIBRARY_PATH}/**/*.rb" scan_files = "#{HOMEBREW_LIBRARY_PATH}/**/*.rb"
ruby_files = Dir.glob(scan_files).reject { |file| file =~ %r{/(vendor)/} } ruby_files = Dir.glob(scan_files).reject { |file| file =~ %r{/(vendor)/} }

View File

@ -3,6 +3,7 @@
require "formula_installer" require "formula_installer"
require "development_tools" require "development_tools"
require "messages" require "messages"
require "install"
require "reinstall" require "reinstall"
require "cli/parser" require "cli/parser"
require "cleanup" require "cleanup"
@ -25,7 +26,7 @@ module Homebrew
Unless `HOMEBREW_NO_INSTALL_CLEANUP` is set, `brew cleanup` will then be run for the Unless `HOMEBREW_NO_INSTALL_CLEANUP` is set, `brew cleanup` will then be run for the
reinstalled formulae or, every 30 days, for all formulae. reinstalled formulae or, every 30 days, for all formulae.
EOS EOS
switch :debug, switch "-d", "--debug",
description: "If brewing fails, open an interactive debugging session with access to IRB "\ description: "If brewing fails, open an interactive debugging session with access to IRB "\
"or a shell inside the temporary build directory." "or a shell inside the temporary build directory."
switch "-s", "--build-from-source", switch "-s", "--build-from-source",
@ -39,10 +40,10 @@ module Homebrew
"macOS, even if it would not normally be used for installation." "macOS, even if it would not normally be used for installation."
switch "--keep-tmp", switch "--keep-tmp",
description: "Retain the temporary files created during installation." description: "Retain the temporary files created during installation."
switch :force, switch "-f", "--force",
description: "Install without checking for previously installed keg-only or "\ description: "Install without checking for previously installed keg-only or "\
"non-migrated versions." "non-migrated versions."
switch :verbose, switch "-v", "--verbose",
description: "Print the verification and postinstall steps." description: "Print the verification and postinstall steps."
switch "--display-times", switch "--display-times",
env: :display_install_times, env: :display_install_times,
@ -56,7 +57,7 @@ module Homebrew
def reinstall def reinstall
args = reinstall_args.parse args = reinstall_args.parse
FormulaInstaller.prevent_build_flags unless DevelopmentTools.installed? FormulaInstaller.prevent_build_flags(args)
Install.perform_preinstall_checks Install.perform_preinstall_checks
@ -66,14 +67,14 @@ module Homebrew
onoe "#{f.full_name} is pinned. You must unpin it to reinstall." onoe "#{f.full_name} is pinned. You must unpin it to reinstall."
next next
end end
Migrator.migrate_if_needed(f) Migrator.migrate_if_needed(f, force: args.force?)
reinstall_formula(f, args: args) reinstall_formula(f, args: args)
Cleanup.install_formula_clean!(f) Cleanup.install_formula_clean!(f)
end end
check_installed_dependents(args: args) check_installed_dependents(args: args)
Homebrew.messages.display_messages Homebrew.messages.display_messages(display_times: args.display_times?)
return if casks.blank? return if casks.blank?

View File

@ -51,14 +51,13 @@ module Homebrew
switch s, switch s,
description: "Search for <text> in the given package manager's list." description: "Search for <text> in the given package manager's list."
end end
switch :verbose
switch :debug
conflicts(*package_manager_switches) conflicts(*package_manager_switches)
end end
end end
def search def search
search_args.parse args = search_args.parse
if package_manager = PACKAGE_MANAGERS.find { |name,| args[:"#{name}?"] } if package_manager = PACKAGE_MANAGERS.find { |name,| args[:"#{name}?"] }
_, url = package_manager _, url = package_manager

View File

@ -14,14 +14,13 @@ module Homebrew
Symlink all of the specified <version> of <formula>'s installation into Homebrew's prefix. Symlink all of the specified <version> of <formula>'s installation into Homebrew's prefix.
EOS EOS
switch :verbose
switch :debug
named 2 named 2
end end
end end
def switch def switch
switch_args.parse args = switch_args.parse
name = args.named.first name = args.named.first
rack = Formulary.to_rack(name) rack = Formulary.to_rack(name)

View File

@ -20,12 +20,11 @@ module Homebrew
description: "Print a JSON representation of <tap>. Currently the default and only accepted "\ description: "Print a JSON representation of <tap>. Currently the default and only accepted "\
"value for <version> is `v1`. See the docs for examples of using the JSON "\ "value for <version> is `v1`. See the docs for examples of using the JSON "\
"output: <https://docs.brew.sh/Querying-Brew>" "output: <https://docs.brew.sh/Querying-Brew>"
switch :debug
end end
end end
def tap_info def tap_info
tap_info_args.parse args = tap_info_args.parse
taps = if args.installed? taps = if args.installed?
Tap Tap

View File

@ -36,14 +36,13 @@ module Homebrew
description: "Migrate tapped formulae from symlink-based to directory-based structure." description: "Migrate tapped formulae from symlink-based to directory-based structure."
switch "--list-pinned", switch "--list-pinned",
description: "List all pinned taps." description: "List all pinned taps."
switch :quiet
switch :debug
max_named 2 max_named 2
end end
end end
def tap def tap
tap_args.parse args = tap_args.parse
if args.repair? if args.repair?
Tap.each(&:link_completions_and_manpages) Tap.each(&:link_completions_and_manpages)
@ -63,7 +62,7 @@ module Homebrew
tap = Tap.fetch(args.named.first) tap = Tap.fetch(args.named.first)
begin begin
tap.install clone_target: args.named.second, tap.install clone_target: args.named.second,
force_auto_update: force_auto_update?, force_auto_update: force_auto_update?(args: args),
quiet: args.quiet?, quiet: args.quiet?,
full_clone: full_clone full_clone: full_clone
rescue TapRemoteMismatchError => e rescue TapRemoteMismatchError => e
@ -74,7 +73,7 @@ module Homebrew
end end
end end
def force_auto_update? def force_auto_update?(args:)
# if no relevant flag is present, return nil, meaning "no change" # if no relevant flag is present, return nil, meaning "no change"
true if args.force_auto_update? true if args.force_auto_update?
end end

View File

@ -19,18 +19,18 @@ module Homebrew
Uninstall <formula>. Uninstall <formula>.
EOS EOS
switch :force, switch "-f", "--force",
description: "Delete all installed versions of <formula>." description: "Delete all installed versions of <formula>."
switch "--ignore-dependencies", switch "--ignore-dependencies",
description: "Don't fail uninstall, even if <formula> is a dependency of any installed "\ description: "Don't fail uninstall, even if <formula> is a dependency of any installed "\
"formulae." "formulae."
switch :debug
min_named :formula min_named :formula
end end
end end
def uninstall def uninstall
uninstall_args.parse args = uninstall_args.parse
if args.force? if args.force?
casks = [] casks = []
@ -54,7 +54,9 @@ module Homebrew
kegs_by_rack = all_kegs.group_by(&:rack) kegs_by_rack = all_kegs.group_by(&:rack)
end end
handle_unsatisfied_dependents(kegs_by_rack) handle_unsatisfied_dependents(kegs_by_rack,
ignore_dependencies: args.ignore_dependencies?,
named_args: args.named)
return if Homebrew.failed? return if Homebrew.failed?
kegs_by_rack.each do |rack, kegs| kegs_by_rack.each do |rack, kegs|
@ -142,40 +144,41 @@ module Homebrew
end end
end end
def handle_unsatisfied_dependents(kegs_by_rack) def handle_unsatisfied_dependents(kegs_by_rack, ignore_dependencies: false, named_args: [])
return if args.ignore_dependencies? return if ignore_dependencies
all_kegs = kegs_by_rack.values.flatten(1) all_kegs = kegs_by_rack.values.flatten(1)
check_for_dependents all_kegs check_for_dependents(all_kegs, named_args: named_args)
rescue MethodDeprecatedError rescue MethodDeprecatedError
# Silently ignore deprecations when uninstalling. # Silently ignore deprecations when uninstalling.
nil nil
end end
def check_for_dependents(kegs) def check_for_dependents(kegs, named_args: [])
return false unless result = Keg.find_some_installed_dependents(kegs) return false unless result = Keg.find_some_installed_dependents(kegs)
if Homebrew::EnvConfig.developer? if Homebrew::EnvConfig.developer?
DeveloperDependentsMessage.new(*result).output DeveloperDependentsMessage.new(*result, named_args: named_args).output
else else
NondeveloperDependentsMessage.new(*result).output NondeveloperDependentsMessage.new(*result, named_args: named_args).output
end end
true true
end end
class DependentsMessage class DependentsMessage
attr_reader :reqs, :deps attr_reader :reqs, :deps, :named_args
def initialize(requireds, dependents) def initialize(requireds, dependents, named_args: [])
@reqs = requireds @reqs = requireds
@deps = dependents @deps = dependents
@named_args = named_args
end end
protected protected
def sample_command def sample_command
"brew uninstall --ignore-dependencies #{Array(Homebrew.args.named).join(" ")}" "brew uninstall --ignore-dependencies #{named_args.join(" ")}"
end end
def are_required_by_deps def are_required_by_deps

View File

@ -18,14 +18,13 @@ module Homebrew
switch "-n", "--dry-run", switch "-n", "--dry-run",
description: "List files which would be unlinked without actually unlinking or "\ description: "List files which would be unlinked without actually unlinking or "\
"deleting any files." "deleting any files."
switch :verbose
switch :debug
min_named :keg min_named :keg
end end
end end
def unlink def unlink
unlink_args.parse args = unlink_args.parse
mode = OpenStruct.new mode = OpenStruct.new
mode.dry_run = true if args.dry_run? mode.dry_run = true if args.dry_run?

View File

@ -14,14 +14,13 @@ module Homebrew
Unpin <formula>, allowing them to be upgraded by `brew upgrade` <formula>. Unpin <formula>, allowing them to be upgraded by `brew upgrade` <formula>.
See also `pin`. See also `pin`.
EOS EOS
switch :verbose
switch :debug
min_named :formula min_named :formula
end end
end end
def unpin def unpin
unpin_args.parse args = unpin_args.parse
args.resolved_formulae.each do |f| args.resolved_formulae.each do |f|
if f.pinned? if f.pinned?

View File

@ -12,13 +12,13 @@ module Homebrew
Remove a tapped formula repository. Remove a tapped formula repository.
EOS EOS
switch :debug
min_named 1 min_named 1
end end
end end
def untap def untap
untap_args.parse args = untap_args.parse
args.named.each do |tapname| args.named.each do |tapname|
tap = Tap.fetch(tapname) tap = Tap.fetch(tapname)

View File

@ -11,7 +11,7 @@ require "cli/parser"
module Homebrew module Homebrew
module_function module_function
def update_preinstall_header def update_preinstall_header(args:)
@update_preinstall_header ||= begin @update_preinstall_header ||= begin
ohai "Auto-updated Homebrew!" if args.preinstall? ohai "Auto-updated Homebrew!" if args.preinstall?
true true
@ -27,16 +27,16 @@ module Homebrew
EOS EOS
switch "--preinstall", switch "--preinstall",
description: "Run in 'auto-update' mode (faster, less output)." description: "Run in 'auto-update' mode (faster, less output)."
switch :force switch "-f", "--force",
switch :quiet description: "Treat installed and updated formulae as if they are from "\
switch :verbose "the same taps and migrate them anyway."
switch :debug
hide_from_man_page! hide_from_man_page!
end end
end end
def update_report def update_report
update_report_args.parse args = update_report_args.parse
if !Utils::Analytics.messages_displayed? && if !Utils::Analytics.messages_displayed? &&
!Utils::Analytics.disabled? && !Utils::Analytics.disabled? &&
@ -80,7 +80,7 @@ module Homebrew
odie "update-report should not be called directly!" if initial_revision.empty? || current_revision.empty? odie "update-report should not be called directly!" if initial_revision.empty? || current_revision.empty?
if initial_revision != current_revision if initial_revision != current_revision
update_preinstall_header update_preinstall_header args: args
puts "Updated Homebrew from #{shorten_revision(initial_revision)} to #{shorten_revision(current_revision)}." puts "Updated Homebrew from #{shorten_revision(initial_revision)} to #{shorten_revision(current_revision)}."
updated = true updated = true
end end
@ -102,12 +102,12 @@ module Homebrew
end end
if reporter.updated? if reporter.updated?
updated_taps << tap.name updated_taps << tap.name
hub.add(reporter) hub.add(reporter, preinstall: args.preinstall?)
end end
end end
unless updated_taps.empty? unless updated_taps.empty?
update_preinstall_header update_preinstall_header args: args
puts "Updated #{updated_taps.count} #{"tap".pluralize(updated_taps.count)} (#{updated_taps.to_sentence})." puts "Updated #{updated_taps.count} #{"tap".pluralize(updated_taps.count)} (#{updated_taps.to_sentence})."
updated = true updated = true
end end
@ -120,7 +120,7 @@ module Homebrew
else else
hub.dump(updated_formula_report: !args.preinstall?) hub.dump(updated_formula_report: !args.preinstall?)
hub.reporters.each(&:migrate_tap_migration) hub.reporters.each(&:migrate_tap_migration)
hub.reporters.each(&:migrate_formula_rename) hub.reporters.each { |r| r.migrate_formula_rename(force: args.force?) }
CacheStoreDatabase.use(:descriptions) do |db| CacheStoreDatabase.use(:descriptions) do |db|
DescriptionCacheStore.new(db) DescriptionCacheStore.new(db)
.update_from_report!(hub) .update_from_report!(hub)
@ -184,7 +184,7 @@ class Reporter
raise ReporterRevisionUnsetError, current_revision_var if @current_revision.empty? raise ReporterRevisionUnsetError, current_revision_var if @current_revision.empty?
end end
def report def report(preinstall: false)
return @report if @report return @report if @report
@report = Hash.new { |h, k| h[k] = [] } @report = Hash.new { |h, k| h[k] = [] }
@ -221,7 +221,7 @@ class Reporter
name = tap.formula_file_to_name(src) name = tap.formula_file_to_name(src)
# Skip reporting updated formulae to speed up automatic updates. # Skip reporting updated formulae to speed up automatic updates.
if Homebrew.args.preinstall? if preinstall
@report[:M] << name @report[:M] << name
next next
end end
@ -371,7 +371,7 @@ class Reporter
end end
end end
def migrate_formula_rename def migrate_formula_rename(force:)
Formula.installed.each do |formula| Formula.installed.each do |formula|
next unless Migrator.needs_migration?(formula) next unless Migrator.needs_migration?(formula)
@ -395,7 +395,7 @@ class Reporter
next next
end end
Migrator.migrate_if_needed(f) Migrator.migrate_if_needed(f, force: force)
end end
end end
@ -423,9 +423,9 @@ class ReporterHub
@hash.fetch(key, []) @hash.fetch(key, [])
end end
def add(reporter) def add(reporter, preinstall: false)
@reporters << reporter @reporters << reporter
report = reporter.report.delete_if { |_k, v| v.empty? } report = reporter.report(preinstall: preinstall).delete_if { |_k, v| v.empty? }
@hash.update(report) { |_key, oldval, newval| oldval.concat(newval) } @hash.update(report) { |_key, oldval, newval| oldval.concat(newval) }
end end

View File

@ -1,8 +1,9 @@
#: * `update`, `up` [<options>] #: * `update` [<options>]
#: #:
#: Fetch the newest version of Homebrew and all formulae from GitHub using `git`(1) and perform any necessary migrations. #: Fetch the newest version of Homebrew and all formulae from GitHub using `git`(1) and perform any necessary migrations.
#: #:
#: --merge Use `git merge` to apply updates (rather than `git rebase`). #: --merge Use `git merge` to apply updates (rather than `git rebase`).
#: --preinstall Run on auto-updates (e.g. before `brew install`). Skips some slower steps.
#: -f, --force Always do a slower, full update check (even if unnecessary). #: -f, --force Always do a slower, full update check (even if unnecessary).
#: -v, --verbose Print the directories checked and `git` operations performed. #: -v, --verbose Print the directories checked and `git` operations performed.
#: -d, --debug Display a trace of all shell commands as they are executed. #: -d, --debug Display a trace of all shell commands as they are executed.

View File

@ -4,6 +4,9 @@ require "cli/parser"
require "formula_installer" require "formula_installer"
require "install" require "install"
require "upgrade" require "upgrade"
require "cask/cmd"
require "cask/utils"
require "cask/macos"
module Homebrew module Homebrew
module_function module_function
@ -20,7 +23,7 @@ module Homebrew
Unless `HOMEBREW_NO_INSTALL_CLEANUP` is set, `brew cleanup` will then be run for the Unless `HOMEBREW_NO_INSTALL_CLEANUP` is set, `brew cleanup` will then be run for the
upgraded formulae or, every 30 days, for all formulae. upgraded formulae or, every 30 days, for all formulae.
EOS EOS
switch :debug, switch "-d", "--debug",
description: "If brewing fails, open an interactive debugging session with access to IRB "\ description: "If brewing fails, open an interactive debugging session with access to IRB "\
"or a shell inside the temporary build directory." "or a shell inside the temporary build directory."
switch "-s", "--build-from-source", switch "-s", "--build-from-source",
@ -40,16 +43,18 @@ module Homebrew
description: "Set a successful exit status even if pinned formulae are not upgraded." description: "Set a successful exit status even if pinned formulae are not upgraded."
switch "--keep-tmp", switch "--keep-tmp",
description: "Retain the temporary files created during installation." description: "Retain the temporary files created during installation."
switch :force, switch "-f", "--force",
description: "Install without checking for previously installed keg-only or "\ description: "Install without checking for previously installed keg-only or "\
"non-migrated versions." "non-migrated versions."
switch :verbose, switch "-v", "--verbose",
description: "Print the verification and postinstall steps." description: "Print the verification and postinstall steps."
switch "--display-times", switch "--display-times",
env: :display_install_times, env: :display_install_times,
description: "Print install times for each formula at the end of the run." description: "Print install times for each formula at the end of the run."
switch "-n", "--dry-run", switch "-n", "--dry-run",
description: "Show what would be upgraded, but do not actually upgrade anything." description: "Show what would be upgraded, but do not actually upgrade anything."
switch "--greedy",
description: "Upgrade casks with `auto_updates` or `version :latest`"
conflicts "--build-from-source", "--force-bottle" conflicts "--build-from-source", "--force-bottle"
formula_options formula_options
end end
@ -58,22 +63,32 @@ module Homebrew
def upgrade def upgrade
args = upgrade_args.parse args = upgrade_args.parse
FormulaInstaller.prevent_build_flags unless DevelopmentTools.installed? formulae, casks = args.resolved_formulae_casks
# If one or more formulae are specified, but no casks were
# specified, we want to make note of that so we don't
# try to upgrade all outdated casks.
named_formulae_specified = !formulae.empty? && casks.empty?
named_casks_specified = !casks.empty? && formulae.empty?
upgrade_outdated_formulae(formulae, args: args) unless named_casks_specified
upgrade_outdated_casks(casks, args: args) unless named_formulae_specified
end
def upgrade_outdated_formulae(formulae, args:)
FormulaInstaller.prevent_build_flags(args)
Install.perform_preinstall_checks Install.perform_preinstall_checks
if args.no_named? if formulae.blank?
outdated = Formula.installed.select do |f| outdated = Formula.installed.select do |f|
f.outdated?(fetch_head: args.fetch_HEAD?) f.outdated?(fetch_head: args.fetch_HEAD?)
end end
exit 0 if outdated.empty?
else else
outdated = args.resolved_formulae.select do |f| outdated, not_outdated = formulae.partition do |f|
f.outdated?(fetch_head: args.fetch_HEAD?) f.outdated?(fetch_head: args.fetch_HEAD?)
end end
(args.resolved_formulae - outdated).each do |f| not_outdated.each do |f|
versions = f.installed_kegs.map(&:version) versions = f.installed_kegs.map(&:version)
if versions.empty? if versions.empty?
ofail "#{f.full_specified_name} not installed" ofail "#{f.full_specified_name} not installed"
@ -82,9 +97,10 @@ module Homebrew
opoo "#{f.full_specified_name} #{version} already installed" opoo "#{f.full_specified_name} #{version} already installed"
end end
end end
return if outdated.empty?
end end
return if outdated.blank?
pinned = outdated.select(&:pinned?) pinned = outdated.select(&:pinned?)
outdated -= pinned outdated -= pinned
formulae_to_install = outdated.map(&:latest_formula) formulae_to_install = outdated.map(&:latest_formula)
@ -113,6 +129,14 @@ module Homebrew
check_installed_dependents(args: args) check_installed_dependents(args: args)
Homebrew.messages.display_messages Homebrew.messages.display_messages(display_times: args.display_times?)
end
def upgrade_outdated_casks(casks, args:)
cask_upgrade = Cask::Cmd::Upgrade.new(casks)
cask_upgrade.force = args.force?
cask_upgrade.dry_run = args.dry_run?
cask_upgrade.greedy = args.greedy?
cask_upgrade.run
end end
end end

View File

@ -6,6 +6,8 @@
require "formula" require "formula"
require "cli/parser" require "cli/parser"
require "cask/caskroom"
require "dependencies_helpers"
module Homebrew module Homebrew
extend DependenciesHelpers extend DependenciesHelpers
@ -38,14 +40,14 @@ module Homebrew
description: "Show usage of <formula> by development builds." description: "Show usage of <formula> by development builds."
switch "--HEAD", switch "--HEAD",
description: "Show usage of <formula> by HEAD builds." description: "Show usage of <formula> by HEAD builds."
switch :debug
conflicts "--devel", "--HEAD" conflicts "--devel", "--HEAD"
min_named :formula min_named :formula
end end
end end
def uses def uses
uses_args.parse args = uses_args.parse
odeprecated "brew uses --devel" if args.devel? odeprecated "brew uses --devel" if args.devel?
odeprecated "brew uses --HEAD" if args.HEAD? odeprecated "brew uses --HEAD" if args.HEAD?
@ -68,20 +70,36 @@ module Homebrew
!args.include_optional? && !args.include_optional? &&
!args.skip_recommended? !args.skip_recommended?
recursive = args.recursive?
includes, ignores = args_includes_ignores(args)
uses = if use_runtime_dependents && !used_formulae_missing uses = if use_runtime_dependents && !used_formulae_missing
used_formulae.map(&:runtime_installed_formula_dependents) used_formulae.map(&:runtime_installed_formula_dependents)
.reduce(&:&) .reduce(&:&)
.select(&:any_version_installed?) .select(&:any_version_installed?) +
select_used_dependents(dependents(Cask::Caskroom.casks), used_formulae, recursive, includes, ignores)
else else
formulae = args.installed? ? Formula.installed : Formula deps = if args.installed?
recursive = args.recursive? dependents(Formula.installed + Cask::Caskroom.casks)
includes, ignores = argv_includes_ignores(ARGV) else
dependents(Formula.to_a + Cask::Cask.to_a)
end
formulae.select do |f| select_used_dependents(deps, used_formulae, recursive, includes, ignores)
end
return if uses.empty?
puts Formatter.columns(uses.map(&:full_name).sort)
odie "Missing formulae should not have dependents!" if used_formulae_missing
end
def select_used_dependents(dependents, used_formulae, recursive, includes, ignores)
dependents.select do |d|
deps = if recursive deps = if recursive
recursive_includes(Dependency, f, includes, ignores) recursive_includes(Dependency, d, includes, ignores)
else else
reject_ignores(f.deps, ignores, includes) reject_ignores(d.deps, ignores, includes)
end end
used_formulae.all? do |ff| used_formulae.all? do |ff|
@ -102,10 +120,4 @@ module Homebrew
end end
end end
end end
return if uses.empty?
puts Formatter.columns(uses.map(&:full_name).sort)
odie "Missing formulae should not have dependents!" if used_formulae_missing
end
end end

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require "cask/cmd"
module Commands module Commands
module_function module_function
@ -89,6 +91,7 @@ module Commands
cmds += internal_developer_commands cmds += internal_developer_commands
cmds += external_commands cmds += external_commands
cmds += internal_commands_aliases if aliases cmds += internal_commands_aliases if aliases
cmds += cask_commands(aliases: aliases).map { |cmd| "cask #{cmd}" }
cmds.sort cmds.sort
end end
@ -129,11 +132,39 @@ module Commands
Tap.cmd_directories.flat_map do |path| Tap.cmd_directories.flat_map do |path|
find_commands(path).select(&:executable?) find_commands(path).select(&:executable?)
.map(&method(:basename_without_extension)) .map(&method(:basename_without_extension))
.map { |p| p.to_s.sub(/^brew(cask)?-/, '\1 ').strip } .map { |p| p.to_s.delete_prefix("brew-").strip }
end.map(&:to_s) end.map(&:to_s)
.sort .sort
end end
def cask_commands(aliases: false)
cmds = cask_internal_commands
cmds += cask_internal_command_aliases if aliases
cmds += cask_external_commands
cmds
end
def cask_internal_commands
Cask::Cmd.commands
end
def cask_internal_command_aliases
Cask::Cmd.aliases.keys
end
def cask_external_commands
PATH.new(Tap.cmd_directories, ENV["HOMEBREW_PATH"]).flat_map do |search_path|
find_commands(search_path).map do |possible_command|
path = possible_command.to_path
command_name = path.match(/brewcask-(.*)\.rb/) { |data| data[1].delete_suffix(".rb") }
if command_name.blank? && possible_command.executable?
command_name = path.match(/brewcask-(.*)/) { |data| data[1] }
end
command_name
end.compact
end
end
def basename_without_extension(path) def basename_without_extension(path)
path.basename(path.extname) path.basename(path.extname)
end end

View File

@ -1,6 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require "delegate" require "delegate"
require "cask_dependent"
class Dependencies < DelegateClass(Array) class Dependencies < DelegateClass(Array)
def initialize(*args) def initialize(*args)
@ -55,71 +56,3 @@ class Requirements < DelegateClass(Set)
"#<#{self.class.name}: {#{to_a.join(", ")}}>" "#<#{self.class.name}: {#{to_a.join(", ")}}>"
end end
end end
module DependenciesHelpers
def argv_includes_ignores(argv)
includes = []
ignores = []
if argv.include? "--include-build"
includes << "build?"
else
ignores << "build?"
end
if argv.include? "--include-test"
includes << "test?"
else
ignores << "test?"
end
if argv.include? "--include-optional"
includes << "optional?"
else
ignores << "optional?"
end
ignores << "recommended?" if args.skip_recommended?
[includes, ignores]
end
def recursive_includes(klass, formula, includes, ignores)
type = if klass == Dependency
:dependencies
elsif klass == Requirement
:requirements
else
raise ArgumentError, "Invalid class argument: #{klass}"
end
formula.send("recursive_#{type}") do |dependent, dep|
if dep.recommended?
klass.prune if ignores.include?("recommended?") || dependent.build.without?(dep)
elsif dep.optional?
klass.prune if !includes.include?("optional?") && !dependent.build.with?(dep)
elsif dep.build? || dep.test?
keep = false
keep ||= dep.test? && includes.include?("test?") && dependent == formula
keep ||= dep.build? && includes.include?("build?")
klass.prune unless keep
end
# If a tap isn't installed, we can't find the dependencies of one of
# its formulae, and an exception will be thrown if we try.
if type == :dependencies &&
dep.is_a?(TapDependency) &&
!dep.tap.installed?
Dependency.keep_but_prune_recursive_deps
end
end
end
def reject_ignores(dependables, ignores, includes)
dependables.reject do |dep|
next false unless ignores.any? { |ignore| dep.send(ignore) }
includes.none? { |include| dep.send(include) }
end
end
end

View File

@ -0,0 +1,82 @@
# frozen_string_literal: true
require "cask_dependent"
module DependenciesHelpers
def args_includes_ignores(args)
includes = []
ignores = []
if args.include_build?
includes << "build?"
else
ignores << "build?"
end
if args.include_test?
includes << "test?"
else
ignores << "test?"
end
if args.include_optional?
includes << "optional?"
else
ignores << "optional?"
end
ignores << "recommended?" if args.skip_recommended?
[includes, ignores]
end
def recursive_includes(klass, root_dependent, includes, ignores)
type = if klass == Dependency
:dependencies
elsif klass == Requirement
:requirements
else
raise ArgumentError, "Invalid class argument: #{klass}"
end
root_dependent.send("recursive_#{type}") do |dependent, dep|
if dep.recommended?
klass.prune if ignores.include?("recommended?") || dependent.build.without?(dep)
elsif dep.optional?
klass.prune if !includes.include?("optional?") && !dependent.build.with?(dep)
elsif dep.build? || dep.test?
keep = false
keep ||= dep.test? && includes.include?("test?") && dependent == root_dependent
keep ||= dep.build? && includes.include?("build?")
klass.prune unless keep
end
# If a tap isn't installed, we can't find the dependencies of one of
# its formulae, and an exception will be thrown if we try.
if type == :dependencies &&
dep.is_a?(TapDependency) &&
!dep.tap.installed?
Dependency.keep_but_prune_recursive_deps
end
end
end
def reject_ignores(dependables, ignores, includes)
dependables.reject do |dep|
next false unless ignores.any? { |ignore| dep.send(ignore) }
includes.none? { |include| dep.send(include) }
end
end
def dependents(formulae_or_casks)
formulae_or_casks.map do |formula_or_cask|
if formula_or_cask.is_a?(Formula)
formula_or_cask
else
CaskDependent.new(formula_or_cask)
end
end
end
module_function :dependents
end

View File

@ -61,8 +61,7 @@ module Homebrew
comma_array "--except-cops", comma_array "--except-cops",
description: "Specify a comma-separated <cops> list to skip checking for violations of the listed "\ description: "Specify a comma-separated <cops> list to skip checking for violations of the listed "\
"RuboCop cops." "RuboCop cops."
switch :verbose
switch :debug
conflicts "--only", "--except" conflicts "--only", "--except"
conflicts "--only-cops", "--except-cops", "--strict" conflicts "--only-cops", "--except-cops", "--strict"
conflicts "--only-cops", "--except-cops", "--only" conflicts "--only-cops", "--except-cops", "--only"
@ -88,8 +87,8 @@ module Homebrew
git = args.git? git = args.git?
skip_style = args.skip_style? || args.no_named? skip_style = args.skip_style? || args.no_named?
ENV.activate_extensions!(args: args) ENV.activate_extensions!
ENV.setup_build_environment(args: args) ENV.setup_build_environment
audit_formulae = args.no_named? ? Formula : args.resolved_formulae audit_formulae = args.no_named? ? Formula : args.resolved_formulae
style_files = args.formulae_paths unless skip_style style_files = args.formulae_paths unless skip_style
@ -127,6 +126,7 @@ module Homebrew
} }
options[:style_offenses] = style_results.file_offenses(f.path) if style_results options[:style_offenses] = style_results.file_offenses(f.path) if style_results
options[:display_cop_names] = args.display_cop_names? options[:display_cop_names] = args.display_cop_names?
options[:build_stable] = args.build_stable?
fa = FormulaAuditor.new(f, options) fa = FormulaAuditor.new(f, options)
fa.audit fa.audit
@ -207,6 +207,7 @@ module Homebrew
@new_formula = options[:new_formula] && !@versioned_formula @new_formula = options[:new_formula] && !@versioned_formula
@strict = options[:strict] @strict = options[:strict]
@online = options[:online] @online = options[:online]
@build_stable = options[:build_stable]
@git = options[:git] @git = options[:git]
@display_cop_names = options[:display_cop_names] @display_cop_names = options[:display_cop_names]
@only = options[:only] @only = options[:only]
@ -248,7 +249,7 @@ module Homebrew
unversioned_name = unversioned_formula.basename(".rb") unversioned_name = unversioned_formula.basename(".rb")
problem "#{formula} is versioned but no #{unversioned_name} formula exists" problem "#{formula} is versioned but no #{unversioned_name} formula exists"
end end
elsif Homebrew.args.build_stable? && formula.stable? && elsif @build_stable && formula.stable? &&
!(versioned_formulae = formula.versioned_formulae).empty? !(versioned_formulae = formula.versioned_formulae).empty?
versioned_aliases = formula.aliases.grep(/.@\d/) versioned_aliases = formula.aliases.grep(/.@\d/)
_, last_alias_version = versioned_formulae.map(&:name).last.split("@") _, last_alias_version = versioned_formulae.map(&:name).last.split("@")
@ -267,6 +268,12 @@ module Homebrew
valid_alias_names.map! { |a| "#{formula.tap}/#{a}" } valid_alias_names.map! { |a| "#{formula.tap}/#{a}" }
end end
# Fix naming based on what people expect.
if alias_name_major_minor == "adoptopenjdk@1.8"
valid_alias_names << "adoptopenjdk@8"
valid_alias_names.delete "adoptopenjdk@1"
end
valid_versioned_aliases = versioned_aliases & valid_alias_names valid_versioned_aliases = versioned_aliases & valid_alias_names
invalid_versioned_aliases = versioned_aliases - valid_alias_names invalid_versioned_aliases = versioned_aliases - valid_alias_names
@ -282,7 +289,7 @@ module Homebrew
end end
end end
unless invalid_versioned_aliases.empty? if invalid_versioned_aliases.present?
problem <<~EOS problem <<~EOS
Formula has invalid versioned aliases: Formula has invalid versioned aliases:
#{invalid_versioned_aliases.join("\n ")} #{invalid_versioned_aliases.join("\n ")}
@ -330,20 +337,28 @@ module Homebrew
def audit_license def audit_license
if formula.license.present? if formula.license.present?
if @spdx_data["licenses"].any? { |lic| lic["licenseId"] == formula.license } non_standard_licenses = []
formula.license.each do |license|
next if @spdx_data["licenses"].any? { |spdx| spdx["licenseId"] == license }
non_standard_licenses << license
end
if non_standard_licenses.present?
problem "Formula #{formula.name} contains non-standard SPDX licenses: #{non_standard_licenses}."
end
return unless @online return unless @online
user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if @new_formula user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if @new_formula
return if user.blank? return if user.blank?
github_license = GitHub.get_repo_license(user, repo) github_license = GitHub.get_repo_license(user, repo)
return if github_license && [formula.license, "NOASSERTION"].include?(github_license) return if github_license && (formula.license + ["NOASSERTION"]).include?(github_license)
problem "License mismatch - GitHub license is: #{github_license}, "\ problem "License mismatch - GitHub license is: #{Array(github_license)}, "\
"but Formulae license states: #{formula.license}." "but Formulae license states: #{formula.license}."
else
problem "#{formula.license} is not a standard SPDX license."
end
elsif @new_formula elsif @new_formula
problem "No license specified for package." problem "No license specified for package."
end end
@ -375,12 +390,13 @@ module Homebrew
end end
if self.class.aliases.include?(dep.name) && if self.class.aliases.include?(dep.name) &&
(dep_f.core_formula? || !dep_f.versioned_formula?) dep_f.core_formula? && !dep_f.versioned_formula?
problem "Dependency '#{dep.name}' from homebrew/core is an alias; " \ problem "Dependency '#{dep.name}' from homebrew/core is an alias; " \
"use the canonical name '#{dep.to_formula.full_name}'." "use the canonical name '#{dep.to_formula.full_name}'."
end end
if @new_formula && if @core_tap &&
@new_formula &&
dep_f.keg_only? && dep_f.keg_only? &&
dep_f.keg_only_reason.provided_by_macos? && dep_f.keg_only_reason.provided_by_macos? &&
dep_f.keg_only_reason.applicable? && dep_f.keg_only_reason.applicable? &&
@ -456,6 +472,7 @@ module Homebrew
end end
end end
# openssl@1.1 only needed for Linux
VERSIONED_KEG_ONLY_ALLOWLIST = %w[ VERSIONED_KEG_ONLY_ALLOWLIST = %w[
autoconf@2.13 autoconf@2.13
bash-completion@2 bash-completion@2
@ -463,6 +480,7 @@ module Homebrew
libsigc++@2 libsigc++@2
lua@5.1 lua@5.1
numpy@1.16 numpy@1.16
openssl@1.1
python@3.8 python@3.8
].freeze ].freeze
@ -478,7 +496,9 @@ module Homebrew
end end
end end
return if VERSIONED_KEG_ONLY_ALLOWLIST.include?(formula.name) || formula.name.start_with?("gcc@") return if VERSIONED_KEG_ONLY_ALLOWLIST.include?(formula.name)
return if formula.name.start_with?("adoptopenjdk@")
return if formula.name.start_with?("gcc@")
problem "Versioned formulae in homebrew/core should use `keg_only :versioned_formula`" problem "Versioned formulae in homebrew/core should use `keg_only :versioned_formula`"
end end

View File

@ -76,21 +76,20 @@ module Homebrew
"to the formula file." "to the formula file."
flag "--root-url=", flag "--root-url=",
description: "Use the specified <URL> as the root of the bottle's URL instead of Homebrew's default." description: "Use the specified <URL> as the root of the bottle's URL instead of Homebrew's default."
switch :verbose
switch :debug
conflicts "--no-rebuild", "--keep-old" conflicts "--no-rebuild", "--keep-old"
min_named 1 min_named 1
end end
end end
def bottle def bottle
bottle_args.parse args = bottle_args.parse
return merge if args.merge? return merge(args: args) if args.merge?
ensure_relocation_formulae_installed! unless args.skip_relocation? ensure_relocation_formulae_installed! unless args.skip_relocation?
args.resolved_formulae.each do |f| args.resolved_formulae.each do |f|
bottle_formula f bottle_formula f, args: args
end end
end end
@ -103,7 +102,7 @@ module Homebrew
end end
end end
def keg_contain?(string, keg, ignores, formula_and_runtime_deps_names = nil) def keg_contain?(string, keg, ignores, formula_and_runtime_deps_names = nil, args:)
@put_string_exists_header, @put_filenames = nil @put_string_exists_header, @put_filenames = nil
print_filename = lambda do |str, filename| print_filename = lambda do |str, filename|
@ -177,10 +176,10 @@ module Homebrew
end end
end end
keg_contain_absolute_symlink_starting_with?(string, keg) || result keg_contain_absolute_symlink_starting_with?(string, keg, args: args) || result
end end
def keg_contain_absolute_symlink_starting_with?(string, keg) def keg_contain_absolute_symlink_starting_with?(string, keg, args:)
absolute_symlinks_start_with_string = [] absolute_symlinks_start_with_string = []
keg.find do |pn| keg.find do |pn|
next unless pn.symlink? && (link = pn.readlink).absolute? next unless pn.symlink? && (link = pn.readlink).absolute?
@ -211,7 +210,7 @@ module Homebrew
system "/usr/bin/sudo", "--non-interactive", "/usr/sbin/purge" system "/usr/bin/sudo", "--non-interactive", "/usr/sbin/purge"
end end
def bottle_formula(f) def bottle_formula(f, args:)
return ofail "Formula not installed or up-to-date: #{f.full_name}" unless f.latest_version_installed? return ofail "Formula not installed or up-to-date: #{f.full_name}" unless f.latest_version_installed?
unless tap = f.tap unless tap = f.tap
@ -328,14 +327,14 @@ module Homebrew
if args.skip_relocation? if args.skip_relocation?
skip_relocation = true skip_relocation = true
else else
relocatable = false if keg_contain?(prefix_check, keg, ignores, formula_and_runtime_deps_names) relocatable = false if keg_contain?(prefix_check, keg, ignores, formula_and_runtime_deps_names, args: args)
relocatable = false if keg_contain?(repository, keg, ignores) relocatable = false if keg_contain?(repository, keg, ignores, args: args)
relocatable = false if keg_contain?(cellar, keg, ignores, formula_and_runtime_deps_names) relocatable = false if keg_contain?(cellar, keg, ignores, formula_and_runtime_deps_names, args: args)
if prefix != prefix_check if prefix != prefix_check
relocatable = false if keg_contain_absolute_symlink_starting_with?(prefix, keg) relocatable = false if keg_contain_absolute_symlink_starting_with?(prefix, keg, args: args)
relocatable = false if keg_contain?("#{prefix}/etc", keg, ignores) relocatable = false if keg_contain?("#{prefix}/etc", keg, ignores, args: args)
relocatable = false if keg_contain?("#{prefix}/var", keg, ignores) relocatable = false if keg_contain?("#{prefix}/var", keg, ignores, args: args)
relocatable = false if keg_contain?("#{prefix}/share/vim", keg, ignores) relocatable = false if keg_contain?("#{prefix}/share/vim", keg, ignores, args: args)
end end
skip_relocation = relocatable && !keg.require_relocation? skip_relocation = relocatable && !keg.require_relocation?
end end
@ -434,7 +433,7 @@ module Homebrew
end end
end end
def merge def merge(args:)
bottles_hash = args.named.reduce({}) do |hash, json_file| bottles_hash = args.named.reduce({}) do |hash, json_file|
hash.deep_merge(JSON.parse(IO.read(json_file))) do |key, first, second| hash.deep_merge(JSON.parse(IO.read(json_file))) do |key, first, second|
if key == "cellar" if key == "cellar"
@ -484,7 +483,7 @@ module Homebrew
update_or_add = "update" update_or_add = "update"
if args.keep_old? if args.keep_old?
mismatches = [] mismatches = []
bottle_block_contents = s[/ bottle do(.+?)end\n/m, 1] bottle_block_contents = s.inreplace_string[/ bottle do(.+?)end\n/m, 1]
bottle_block_contents.lines.each do |line| bottle_block_contents.lines.each do |line|
line = line.strip line = line.strip
next if line.empty? next if line.empty?

View File

@ -2,6 +2,7 @@
require "formula" require "formula"
require "cli/parser" require "cli/parser"
require "utils/pypi"
module Homebrew module Homebrew
module_function module_function
@ -62,17 +63,16 @@ module Homebrew
flag "--revision=", flag "--revision=",
depends_on: "--tag=", depends_on: "--tag=",
description: "Specify the new git commit <revision> corresponding to the specified <tag>." description: "Specify the new git commit <revision> corresponding to the specified <tag>."
switch :force switch "-f", "--force",
switch :quiet description: "Ignore duplicate open PRs. Remove all mirrors if --mirror= was not specified."
switch :verbose
switch :debug
conflicts "--no-audit", "--strict" conflicts "--no-audit", "--strict"
conflicts "--url", "--tag" conflicts "--url", "--tag"
max_named 1 max_named 1
end end
end end
def use_correct_linux_tap(formula) def use_correct_linux_tap(formula, args:)
if OS.linux? && formula.tap.core_tap? if OS.linux? && formula.tap.core_tap?
tap_full_name = formula.tap.full_name.gsub("linuxbrew", "homebrew") tap_full_name = formula.tap.full_name.gsub("linuxbrew", "homebrew")
homebrew_core_url = "https://github.com/#{tap_full_name}" homebrew_core_url = "https://github.com/#{tap_full_name}"
@ -109,7 +109,7 @@ module Homebrew
end end
def bump_formula_pr def bump_formula_pr
bump_formula_pr_args.parse args = bump_formula_pr_args.parse
# As this command is simplifying user-run commands then let's just use a # As this command is simplifying user-run commands then let's just use a
# user path, too. # user path, too.
@ -124,11 +124,11 @@ module Homebrew
formula ||= determine_formula_from_url(new_url) if new_url formula ||= determine_formula_from_url(new_url) if new_url
raise FormulaUnspecifiedError unless formula raise FormulaUnspecifiedError unless formula
tap_full_name, origin_branch, previous_branch = use_correct_linux_tap(formula) tap_full_name, origin_branch, previous_branch = use_correct_linux_tap(formula, args: args)
check_open_pull_requests(formula, tap_full_name) check_open_pull_requests(formula, tap_full_name, args: args)
new_version = args.version new_version = args.version
check_all_pull_requests(formula, tap_full_name, version: new_version) if new_version check_all_pull_requests(formula, tap_full_name, version: new_version, args: args) if new_version
requested_spec = :stable requested_spec = :stable
formula_spec = formula.stable formula_spec = formula.stable
@ -159,10 +159,10 @@ module Homebrew
old_version = old_formula_version.to_s old_version = old_formula_version.to_s
forced_version = new_version.present? forced_version = new_version.present?
new_url_hash = if new_url && new_hash new_url_hash = if new_url && new_hash
check_all_pull_requests(formula, tap_full_name, url: new_url) unless new_version check_all_pull_requests(formula, tap_full_name, url: new_url, args: args) unless new_version
true true
elsif new_tag && new_revision elsif new_tag && new_revision
check_all_pull_requests(formula, tap_full_name, url: old_url, tag: new_tag) unless new_version check_all_pull_requests(formula, tap_full_name, url: old_url, tag: new_tag, args: args) unless new_version
false false
elsif !hash_type elsif !hash_type
odie "#{formula}: no --tag= or --version= argument specified!" if !new_tag && !new_version odie "#{formula}: no --tag= or --version= argument specified!" if !new_tag && !new_version
@ -173,7 +173,7 @@ module Homebrew
and old tag are both #{new_tag}. and old tag are both #{new_tag}.
EOS EOS
end end
check_all_pull_requests(formula, tap_full_name, url: old_url, tag: new_tag) unless new_version check_all_pull_requests(formula, tap_full_name, url: old_url, tag: new_tag, args: args) unless new_version
resource_path, forced_version = fetch_resource(formula, new_version, old_url, tag: new_tag) resource_path, forced_version = fetch_resource(formula, new_version, old_url, tag: new_tag)
new_revision = Utils.popen_read("git -C \"#{resource_path}\" rev-parse -q --verify HEAD") new_revision = Utils.popen_read("git -C \"#{resource_path}\" rev-parse -q --verify HEAD")
new_revision = new_revision.strip new_revision = new_revision.strip
@ -181,6 +181,7 @@ module Homebrew
elsif !new_url && !new_version elsif !new_url && !new_version
odie "#{formula}: no --url= or --version= argument specified!" odie "#{formula}: no --url= or --version= argument specified!"
else else
new_url ||= PyPI.update_pypi_url(old_url, new_version)
new_url ||= old_url.gsub(old_version, new_version) new_url ||= old_url.gsub(old_version, new_version)
if new_url == old_url if new_url == old_url
odie <<~EOS odie <<~EOS
@ -189,7 +190,7 @@ module Homebrew
#{new_url} #{new_url}
EOS EOS
end end
check_all_pull_requests(formula, tap_full_name, url: new_url) unless new_version check_all_pull_requests(formula, tap_full_name, url: new_url, args: args) unless new_version
resource_path, forced_version = fetch_resource(formula, new_version, new_url) resource_path, forced_version = fetch_resource(formula, new_version, new_url)
tar_file_extensions = %w[.tar .tb2 .tbz .tbz2 .tgz .tlz .txz .tZ] tar_file_extensions = %w[.tar .tb2 .tbz .tbz2 .tgz .tlz .txz .tZ]
if tar_file_extensions.any? { |extension| new_url.include? extension } if tar_file_extensions.any? { |extension| new_url.include? extension }
@ -293,7 +294,7 @@ module Homebrew
"", "",
] ]
end end
new_contents = inreplace_pairs(formula.path, replacement_pairs.uniq.compact) new_contents = inreplace_pairs(formula.path, replacement_pairs.uniq.compact, args: args)
new_formula_version = formula_version(formula, requested_spec, new_contents) new_formula_version = formula_version(formula, requested_spec, new_contents)
@ -330,10 +331,15 @@ module Homebrew
alias_rename.map! { |a| formula.tap.alias_dir/a } alias_rename.map! { |a| formula.tap.alias_dir/a }
end end
run_audit(formula, alias_rename, old_contents) ohai "brew update-python-resources #{formula.name}"
if !args.dry_run? || (args.dry_run? && args.write?)
PyPI.update_python_resources! formula, new_formula_version, silent: true, ignore_non_pypi_packages: true
end
run_audit(formula, alias_rename, old_contents, args: args)
formula.path.parent.cd do formula.path.parent.cd do
branch = "#{formula.name}-#{new_formula_version}" branch = "bump-#{formula.name}-#{new_formula_version}"
git_dir = Utils.popen_read("git rev-parse --git-dir").chomp git_dir = Utils.popen_read("git rev-parse --git-dir").chomp
shallow = !git_dir.empty? && File.exist?("#{git_dir}/shallow") shallow = !git_dir.empty? && File.exist?("#{git_dir}/shallow")
changed_files = [formula.path] changed_files = [formula.path]
@ -445,10 +451,10 @@ module Homebrew
[remote_url, username] [remote_url, username]
end end
def inreplace_pairs(path, replacement_pairs) def inreplace_pairs(path, replacement_pairs, args:)
if args.dry_run? if args.dry_run?
contents = path.open("r") { |f| Formulary.ensure_utf8_encoding(f).read } str = path.open("r") { |f| Formulary.ensure_utf8_encoding(f).read }
contents.extend(StringInreplaceExtension) contents = StringInreplaceExtension.new(str)
replacement_pairs.each do |old, new| replacement_pairs.each do |old, new|
ohai "replace #{old.inspect} with #{new.inspect}" unless args.quiet? ohai "replace #{old.inspect} with #{new.inspect}" unless args.quiet?
raise "No old value for new value #{new}! Did you pass the wrong arguments?" unless old raise "No old value for new value #{new}! Did you pass the wrong arguments?" unless old
@ -457,8 +463,8 @@ module Homebrew
end end
raise Utils::InreplaceError, path => contents.errors unless contents.errors.empty? raise Utils::InreplaceError, path => contents.errors unless contents.errors.empty?
path.atomic_write(contents) if args.write? path.atomic_write(contents.inreplace_string) if args.write?
contents contents.inreplace_string
else else
Utils::Inreplace.inreplace(path) do |s| Utils::Inreplace.inreplace(path) do |s|
replacement_pairs.each do |old, new| replacement_pairs.each do |old, new|
@ -485,10 +491,10 @@ module Homebrew
def check_open_pull_requests(formula, tap_full_name) def check_open_pull_requests(formula, tap_full_name)
# check for open requests # check for open requests
pull_requests = GitHub.fetch_pull_requests(formula.name, tap_full_name, state: "open") pull_requests = GitHub.fetch_pull_requests(formula.name, tap_full_name, state: "open")
check_for_duplicate_pull_requests(pull_requests) check_for_duplicate_pull_requests(pull_requests, args: args)
end end
def check_all_pull_requests(formula, tap_full_name, version: nil, url: nil, tag: nil) def check_all_pull_requests(formula, tap_full_name, version: nil, url: nil, tag: nil, args:)
unless version unless version
specs = {} specs = {}
specs[:tag] = tag if tag specs[:tag] = tag if tag
@ -496,10 +502,10 @@ module Homebrew
end end
# if we haven't already found open requests, try for an exact match across all requests # if we haven't already found open requests, try for an exact match across all requests
pull_requests = GitHub.fetch_pull_requests("#{formula.name} #{version}", tap_full_name) if pull_requests.blank? pull_requests = GitHub.fetch_pull_requests("#{formula.name} #{version}", tap_full_name) if pull_requests.blank?
check_for_duplicate_pull_requests(pull_requests) check_for_duplicate_pull_requests(pull_requests, args: args)
end end
def check_for_duplicate_pull_requests(pull_requests) def check_for_duplicate_pull_requests(pull_requests, args:)
return if pull_requests.blank? return if pull_requests.blank?
duplicates_message = <<~EOS duplicates_message = <<~EOS
@ -531,7 +537,7 @@ module Homebrew
[versioned_alias, "#{name}@#{new_alias_version}"] [versioned_alias, "#{name}@#{new_alias_version}"]
end end
def run_audit(formula, alias_rename, old_contents) def run_audit(formula, alias_rename, old_contents, args:)
if args.dry_run? if args.dry_run?
if args.no_audit? if args.no_audit?
ohai "Skipping `brew audit`" ohai "Skipping `brew audit`"

View File

@ -18,16 +18,13 @@ module Homebrew
description: "Print what would be done rather than doing it." description: "Print what would be done rather than doing it."
flag "--message=", flag "--message=",
description: "Append <message> to the default commit message." description: "Append <message> to the default commit message."
switch :force
switch :quiet
switch :verbose
switch :debug
named :formula named :formula
end end
end end
def bump_revision def bump_revision
bump_revision_args.parse args = bump_revision_args.parse
# As this command is simplifying user-run commands then let's just use a # As this command is simplifying user-run commands then let's just use a
# user path, too. # user path, too.
@ -43,9 +40,14 @@ module Homebrew
end end
old = if formula.license old = if formula.license
license_string = if formula.license.length > 1
formula.license
else
"\"#{formula.license.first}\""
end
# insert replacement revision after license # insert replacement revision after license
<<~EOS <<~EOS
license "#{formula.license}" license #{license_string}
EOS EOS
elsif formula.path.read.include?("stable do\n") elsif formula.path.read.include?("stable do\n")
# insert replacement revision after homepage # insert replacement revision after homepage
@ -60,7 +62,7 @@ module Homebrew
else else
# insert replacement revision after :revision # insert replacement revision after :revision
<<~EOS <<~EOS
:revision => "#{formula_spec.specs[:revision]}" revision: "#{formula_spec.specs[:revision]}"
EOS EOS
end end
replacement = old + " revision 1\n" replacement = old + " revision 1\n"

View File

@ -17,7 +17,7 @@ module Homebrew
end end
def cat def cat
cat_args.parse args = cat_args.parse
cd HOMEBREW_REPOSITORY cd HOMEBREW_REPOSITORY
pager = if Homebrew::EnvConfig.bat? pager = if Homebrew::EnvConfig.bat?
@ -26,6 +26,6 @@ module Homebrew
else else
"cat" "cat"
end end
safe_system pager, args.formulae_paths.first, *args.passthrough safe_system pager, args.formulae_paths.first
end end
end end

View File

@ -13,14 +13,13 @@ module Homebrew
Display the path to the file being used when invoking `brew` <cmd>. Display the path to the file being used when invoking `brew` <cmd>.
EOS EOS
switch :verbose
switch :debug
min_named 1 min_named 1
end end
end end
def command def command
command_args.parse args = command_args.parse
args.named.each do |cmd| args.named.each do |cmd|
path = Commands.path(cmd) path = Commands.path(cmd)

View File

@ -4,6 +4,7 @@ require "formula"
require "formula_creator" require "formula_creator"
require "missing_formula" require "missing_formula"
require "cli/parser" require "cli/parser"
require "utils/pypi"
module Homebrew module Homebrew
module_function module_function
@ -53,9 +54,9 @@ module Homebrew
description: "Explicitly set the <license> of the new formula." description: "Explicitly set the <license> of the new formula."
flag "--tap=", flag "--tap=",
description: "Generate the new formula within the given tap, specified as <user>`/`<repo>." description: "Generate the new formula within the given tap, specified as <user>`/`<repo>."
switch :force switch "-f", "--force",
switch :verbose description: "Ignore errors for disallowed formula names and named that shadow aliases."
switch :debug
conflicts "--autotools", "--cmake", "--crystal", "--go", "--meson", "--node", "--perl", "--python", "--rust" conflicts "--autotools", "--cmake", "--crystal", "--go", "--meson", "--node", "--perl", "--python", "--rust"
named 1 named 1
end end
@ -136,6 +137,8 @@ module Homebrew
fc.generate! fc.generate!
PyPI.update_python_resources! Formula[fc.name], ignore_non_pypi_packages: true if args.python?
puts "Please run `brew audit --new-formula #{fc.name}` before submitting, thanks." puts "Please run `brew audit --new-formula #{fc.name}` before submitting, thanks."
exec_editor fc.path exec_editor fc.path
end end

View File

@ -19,14 +19,13 @@ module Homebrew
description: "Explicitly set the <name> of the package being installed." description: "Explicitly set the <name> of the package being installed."
flag "--version=", flag "--version=",
description: "Explicitly set the <version> of the package being installed." description: "Explicitly set the <version> of the package being installed."
switch :verbose
switch :debug
max_named 0 max_named 0
end end
end end
def diy def diy
diy_args.parse args = diy_args.parse
path = Pathname.getwd path = Pathname.getwd

View File

@ -14,13 +14,11 @@ module Homebrew
Open <formula> in the editor set by `EDITOR` or `HOMEBREW_EDITOR`, or open the Open <formula> in the editor set by `EDITOR` or `HOMEBREW_EDITOR`, or open the
Homebrew repository for editing if no formula is provided. Homebrew repository for editing if no formula is provided.
EOS EOS
switch :verbose
switch :debug
end end
end end
def edit def edit
edit_args.parse args = edit_args.parse
unless (HOMEBREW_REPOSITORY/".git").directory? unless (HOMEBREW_REPOSITORY/".git").directory?
raise <<~EOS raise <<~EOS

View File

@ -89,14 +89,15 @@ module Homebrew
EOS EOS
flag "--version=", flag "--version=",
description: "Extract the specified <version> of <formula> instead of the most recent." description: "Extract the specified <version> of <formula> instead of the most recent."
switch :force switch "-f", "--force",
switch :debug description: "Overwrite the destination formula if it already exists."
named 2 named 2
end end
end end
def extract def extract
extract_args.parse args = extract_args.parse
if args.named.first !~ HOMEBREW_TAP_FORMULA_REGEX if args.named.first !~ HOMEBREW_TAP_FORMULA_REGEX
name = args.named.first.downcase name = args.named.first.downcase

View File

@ -13,14 +13,13 @@ module Homebrew
Display the path where <formula> is located. Display the path where <formula> is located.
EOS EOS
switch :verbose
switch :debug
min_named :formula min_named :formula
end end
end end
def formula def formula
formula_args.parse args = formula_args.parse
args.formulae_paths.each(&method(:puts)) args.formulae_paths.each(&method(:puts))
end end

View File

@ -13,7 +13,7 @@ module Homebrew
Install Homebrew's Bundler gems. Install Homebrew's Bundler gems.
EOS EOS
switch :debug
max_named 0 max_named 0
end end
end end

View File

@ -18,8 +18,7 @@ module Homebrew
module_function module_function
def irb_args def irb_args
# work around IRB modifying ARGV. Homebrew::CLI::Parser.new do
Homebrew::CLI::Parser.new(ARGV.dup.freeze) do
usage_banner <<~EOS usage_banner <<~EOS
`irb` [<options>] `irb` [<options>]
@ -34,7 +33,8 @@ module Homebrew
end end
def irb def irb
irb_args.parse # work around IRB modifying ARGV.
args = irb_args.parse(ARGV.dup.freeze)
if args.examples? if args.examples?
puts "'v8'.f # => instance of the v8 formula" puts "'v8'.f # => instance of the v8 formula"

View File

@ -24,13 +24,11 @@ module Homebrew
switch "--cached", switch "--cached",
description: "Print the cached linkage values stored in `HOMEBREW_CACHE`, set by a previous "\ description: "Print the cached linkage values stored in `HOMEBREW_CACHE`, set by a previous "\
"`brew linkage` run." "`brew linkage` run."
switch :verbose
switch :debug
end end
end end
def linkage def linkage
linkage_args.parse args = linkage_args.parse
CacheStoreDatabase.use(:linkage) do |db| CacheStoreDatabase.use(:linkage) do |db|
kegs = if args.kegs.empty? kegs = if args.kegs.empty?

View File

@ -31,12 +31,12 @@ module Homebrew
end end
def man def man
man_args.parse args = man_args.parse
odie "`brew man --link` is now done automatically by `brew update`." if args.link? odie "`brew man --link` is now done automatically by `brew update`." if args.link?
Commands.rebuild_internal_commands_completion_list Commands.rebuild_internal_commands_completion_list
regenerate_man_pages regenerate_man_pages(preserve_date: args.fail_if_changed?)
if system "git", "-C", HOMEBREW_REPOSITORY, "diff", "--quiet", "docs/Manpage.md", "manpages", "completions" if system "git", "-C", HOMEBREW_REPOSITORY, "diff", "--quiet", "docs/Manpage.md", "manpages", "completions"
puts "No changes to manpage or completions output detected." puts "No changes to manpage or completions output detected."
@ -45,15 +45,15 @@ module Homebrew
end end
end end
def regenerate_man_pages def regenerate_man_pages(preserve_date:)
Homebrew.install_bundler_gems! Homebrew.install_bundler_gems!
markup = build_man_page markup = build_man_page
convert_man_page(markup, TARGET_DOC_PATH/"Manpage.md") convert_man_page(markup, TARGET_DOC_PATH/"Manpage.md", preserve_date: preserve_date)
convert_man_page(markup, TARGET_MAN_PATH/"brew.1") convert_man_page(markup, TARGET_MAN_PATH/"brew.1", preserve_date: preserve_date)
cask_markup = (SOURCE_PATH/"brew-cask.1.md").read cask_markup = (SOURCE_PATH/"brew-cask.1.md").read
convert_man_page(cask_markup, TARGET_MAN_PATH/"brew-cask.1") convert_man_page(cask_markup, TARGET_MAN_PATH/"brew-cask.1", preserve_date: preserve_date)
end end
def build_man_page def build_man_page
@ -94,14 +94,13 @@ module Homebrew
path.basename.to_s.sub(/\.(rb|sh)$/, "").sub(/^--/, "~~") path.basename.to_s.sub(/\.(rb|sh)$/, "").sub(/^--/, "~~")
end end
def convert_man_page(markup, target) def convert_man_page(markup, target, preserve_date:)
manual = target.basename(".1") manual = target.basename(".1")
organisation = "Homebrew" organisation = "Homebrew"
# Set the manpage date to the existing one if we're checking for changes. # Set the manpage date to the existing one if we're checking for changes.
# This avoids the only change being e.g. a new date. # This avoids the only change being e.g. a new date.
date = if args.fail_if_changed? && date = if preserve_date && target.extname == ".1" && target.exist?
target.extname == ".1" && target.exist?
/"(\d{1,2})" "([A-Z][a-z]+) (\d{4})" "#{organisation}" "#{manual}"/ =~ target.read /"(\d{1,2})" "([A-Z][a-z]+) (\d{4})" "#{organisation}" "#{manual}"/ =~ target.read
Date.parse("#{Regexp.last_match(1)} #{Regexp.last_match(2)} #{Regexp.last_match(3)}") Date.parse("#{Regexp.last_match(1)} #{Regexp.last_match(2)} #{Regexp.last_match(3)}")
else else
@ -148,7 +147,7 @@ module Homebrew
def generate_cmd_manpages(cmd_paths) def generate_cmd_manpages(cmd_paths)
man_page_lines = [] man_page_lines = []
man_args = Homebrew.args
# preserve existing manpage order # preserve existing manpage order
cmd_paths.sort_by(&method(:sort_key_for_path)) cmd_paths.sort_by(&method(:sort_key_for_path))
.each do |cmd_path| .each do |cmd_path|
@ -162,14 +161,14 @@ module Homebrew
man_page_lines << cmd_man_page_lines man_page_lines << cmd_man_page_lines
end end
Homebrew.args = man_args
man_page_lines.compact.join("\n") man_page_lines.compact.join("\n")
end end
def cmd_parser_manpage_lines(cmd_parser) def cmd_parser_manpage_lines(cmd_parser)
lines = [format_usage_banner(cmd_parser.usage_banner_text)] lines = [format_usage_banner(cmd_parser.usage_banner_text)]
lines += cmd_parser.processed_options.map do |short, long, _, desc| lines += cmd_parser.processed_options.map do |short, long, _, desc|
next if !long.nil? && cmd_parser.global_option?(cmd_parser.option_to_name(long), desc) next if !long.nil? && Homebrew::CLI::Parser.global_options.include?([short, long, desc])
generate_option_doc(short, long, desc) generate_option_doc(short, long, desc)
end.reject(&:blank?) end.reject(&:blank?)
@ -191,7 +190,7 @@ module Homebrew
end end
# Omit the common global_options documented separately in the man page. # Omit the common global_options documented separately in the man page.
next if line.match?(/--(debug|force|help|quiet|verbose) /) next if line.match?(/--(debug|help|quiet|verbose) /)
# Format one option or a comma-separated pair of short and long options. # Format one option or a comma-separated pair of short and long options.
lines << line.gsub(/^ +(-+[a-z-]+), (-+[a-z-]+) +/, "* `\\1`, `\\2`:\n ") lines << line.gsub(/^ +(-+[a-z-]+), (-+[a-z-]+) +/, "* `\\1`, `\\2`:\n ")
@ -203,8 +202,7 @@ module Homebrew
def global_options_manpage def global_options_manpage
lines = ["These options are applicable across multiple subcommands.\n"] lines = ["These options are applicable across multiple subcommands.\n"]
lines += Homebrew::CLI::Parser.global_options.values.map do |names, _, desc| lines += Homebrew::CLI::Parser.global_options.map do |short, long, desc|
short, long = names
generate_option_doc(short, long, desc) generate_option_doc(short, long, desc)
end end
lines.join("\n") lines.join("\n")

View File

@ -19,8 +19,7 @@ module Homebrew
description: "Upload to the specified Bintray repository (default: `mirror`)." description: "Upload to the specified Bintray repository (default: `mirror`)."
switch "--no-publish", switch "--no-publish",
description: "Upload to Bintray, but don't publish." description: "Upload to Bintray, but don't publish."
switch :verbose
switch :debug
hide_from_man_page! hide_from_man_page!
min_named :formula min_named :formula
end end

View File

@ -25,23 +25,21 @@ module Homebrew
description: "Run `brew pr-publish` on matching pull requests." description: "Run `brew pr-publish` on matching pull requests."
switch "--ignore-failures", switch "--ignore-failures",
description: "Include pull requests that have failing status checks." description: "Include pull requests that have failing status checks."
switch :verbose
switch :debug
max_named 0 max_named 0
end end
end end
def pr_automerge def pr_automerge
pr_automerge_args.parse args = pr_automerge_args.parse
ENV["HOMEBREW_FORCE_HOMEBREW_ON_LINUX"] = "1" unless OS.mac? without_labels = args.without_labels || ["do not merge", "new formula"]
without_labels = Homebrew.args.without_labels || ["do not merge", "new formula"] tap = Tap.fetch(args.tap || CoreTap.instance.name)
tap = Tap.fetch(Homebrew.args.tap || CoreTap.instance.name)
query = "is:pr is:open repo:#{tap.full_name}" query = "is:pr is:open repo:#{tap.full_name}"
query += Homebrew.args.ignore_failures? ? " -status:pending" : " status:success" query += args.ignore_failures? ? " -status:pending" : " status:success"
query += " review:approved" unless Homebrew.args.without_approval? query += " review:approved" unless args.without_approval?
query += " label:\"#{with_label}\"" if Homebrew.args.with_label query += " label:\"#{args.with_label}\"" if args.with_label
without_labels&.each { |label| query += " -label:\"#{label}\"" } without_labels&.each { |label| query += " -label:\"#{label}\"" }
odebug "Searching: #{query}" odebug "Searching: #{query}"
@ -59,7 +57,9 @@ module Homebrew
end end
if args.publish? if args.publish?
safe_system "#{HOMEBREW_PREFIX}/bin/brew", "pr-publish", *pr_urls publish_args = ["pr-publish"]
publish_args << "--tap=#{tap}" if tap
safe_system HOMEBREW_BREW_FILE, *publish_args, *pr_urls
else else
ohai "Now run:", " brew pr-publish \\\n #{pr_urls.join " \\\n "}" ohai "Now run:", " brew pr-publish \\\n #{pr_urls.join " \\\n "}"
end end

View File

@ -12,26 +12,35 @@ module Homebrew
`pr-publish` [<options>] <pull_request> [<pull_request> ...] `pr-publish` [<options>] <pull_request> [<pull_request> ...]
Publish bottles for a pull request with GitHub Actions. Publish bottles for a pull request with GitHub Actions.
Requires write access to the `homebrew/core` repository. Requires write access to the repository.
EOS EOS
switch :verbose flag "--tap=",
description: "Target tap repository (default: `homebrew/core`)."
flag "--workflow=",
description: "Target workflow filename (default: `publish-commit-bottles.yml`)."
min_named 1 min_named 1
end end
end end
def pr_publish def pr_publish
pr_publish_args.parse args = pr_publish_args.parse
ENV["HOMEBREW_FORCE_HOMEBREW_ON_LINUX"] = "1" unless OS.mac? tap = Tap.fetch(args.tap || CoreTap.instance.name)
workflow = args.workflow || "publish-commit-bottles.yml"
ref = "master"
args.named.uniq.each do |arg| args.named.uniq.each do |arg|
arg = "#{CoreTap.instance.default_remote}/pull/#{arg}" if arg.to_i.positive? arg = "#{tap.default_remote}/pull/#{arg}" if arg.to_i.positive?
url_match = arg.match HOMEBREW_PULL_OR_COMMIT_URL_REGEX url_match = arg.match HOMEBREW_PULL_OR_COMMIT_URL_REGEX
_, user, repo, issue = *url_match _, user, repo, issue = *url_match
odie "Not a GitHub pull request: #{arg}" unless issue odie "Not a GitHub pull request: #{arg}" unless issue
tap = Tap.fetch(user, repo) if repo.match?(HOMEBREW_OFFICIAL_REPO_PREFIXES_REGEX) if args.tap.present? && !"#{user}/#{repo}".casecmp(tap.full_name).zero?
odie "Pull request URL is for #{user}/#{repo} but --tap=#{tap.full_name}!"
end
ohai "Dispatching #{tap} pull request ##{issue}" ohai "Dispatching #{tap} pull request ##{issue}"
GitHub.dispatch_event(user, repo, "Publish ##{issue}", pull_request: issue) GitHub.workflow_dispatch_event(user, repo, workflow, ref, pull_request: issue)
end end
end end
end end

View File

@ -49,8 +49,7 @@ module Homebrew
flag "--bintray-mirror=", flag "--bintray-mirror=",
description: "Use the specified Bintray repository to automatically mirror stable URLs "\ description: "Use the specified Bintray repository to automatically mirror stable URLs "\
"defined in the formulae (default: `mirror`)." "defined in the formulae (default: `mirror`)."
switch :verbose
switch :debug
min_named 1 min_named 1
end end
end end
@ -130,7 +129,7 @@ module Homebrew
end end
end end
def check_branch(path, ref) def check_branch(path, ref, args:)
branch = Utils.popen_read("git", "-C", path, "symbolic-ref", "--short", "HEAD").strip branch = Utils.popen_read("git", "-C", path, "symbolic-ref", "--short", "HEAD").strip
return if branch == ref || args.clean? || args.branch_okay? return if branch == ref || args.clean? || args.branch_okay?
@ -155,8 +154,8 @@ module Homebrew
else else
odebug "Mirroring #{mirror_url}" odebug "Mirroring #{mirror_url}"
mirror_args = ["mirror", f.full_name] mirror_args = ["mirror", f.full_name]
mirror_args << "--debug" if Homebrew.args.debug? mirror_args << "--debug" if args.debug?
mirror_args << "--verbose" if Homebrew.args.verbose? mirror_args << "--verbose" if args.verbose?
mirror_args << "--bintray-org=#{org}" if org mirror_args << "--bintray-org=#{org}" if org
mirror_args << "--bintray-repo=#{repo}" if repo mirror_args << "--bintray-repo=#{repo}" if repo
mirror_args << "--no-publish" unless publish mirror_args << "--no-publish" unless publish
@ -233,7 +232,7 @@ module Homebrew
_, user, repo, pr = *url_match _, user, repo, pr = *url_match
odie "Not a GitHub pull request: #{arg}" unless pr odie "Not a GitHub pull request: #{arg}" unless pr
check_branch tap.path, "master" check_branch tap.path, "master", args: args
ohai "Fetching #{tap} pull request ##{pr}" ohai "Fetching #{tap} pull request ##{pr}"
Dir.mktmpdir pr do |dir| Dir.mktmpdir pr do |dir|
@ -259,8 +258,8 @@ module Homebrew
next if args.no_upload? next if args.no_upload?
upload_args = ["pr-upload"] upload_args = ["pr-upload"]
upload_args << "--debug" if Homebrew.args.debug? upload_args << "--debug" if args.debug?
upload_args << "--verbose" if Homebrew.args.verbose? upload_args << "--verbose" if args.verbose?
upload_args << "--no-publish" if args.no_publish? upload_args << "--no-publish" if args.no_publish?
upload_args << "--dry-run" if args.dry_run? upload_args << "--dry-run" if args.dry_run?
upload_args << "--warn-on-upload-failure" if args.warn_on_upload_failure? upload_args << "--warn-on-upload-failure" if args.warn_on_upload_failure?

View File

@ -27,8 +27,21 @@ module Homebrew
description: "Upload to the specified Bintray organisation (default: `homebrew`)." description: "Upload to the specified Bintray organisation (default: `homebrew`)."
flag "--root-url=", flag "--root-url=",
description: "Use the specified <URL> as the root of the bottle's URL instead of Homebrew's default." description: "Use the specified <URL> as the root of the bottle's URL instead of Homebrew's default."
switch :verbose end
switch :debug end
def check_bottled_formulae(json_files)
hashes = json_files.reduce({}) do |hash, json|
hash.deep_merge(JSON.parse(IO.read(json)))
end
hashes.each do |name, hash|
formula_path = HOMEBREW_REPOSITORY/hash["formula"]["path"]
formula_version = Formulary.factory(formula_path).pkg_version
bottle_version = PkgVersion.parse hash["formula"]["pkg_version"]
next if formula_version == bottle_version
odie "Bottles are for #{name} #{bottle_version} but formula is version #{formula_version}!"
end end
end end
@ -38,20 +51,23 @@ module Homebrew
bintray_org = args.bintray_org || "homebrew" bintray_org = args.bintray_org || "homebrew"
bintray = Bintray.new(org: bintray_org) bintray = Bintray.new(org: bintray_org)
json_files = Dir["*.json"]
odie "No JSON files found in the current working directory" if json_files.empty?
bottle_args = ["bottle", "--merge", "--write"] bottle_args = ["bottle", "--merge", "--write"]
bottle_args << "--verbose" if args.verbose? bottle_args << "--verbose" if args.verbose?
bottle_args << "--debug" if args.debug? bottle_args << "--debug" if args.debug?
bottle_args << "--keep-old" if args.keep_old? bottle_args << "--keep-old" if args.keep_old?
bottle_args << "--root-url=#{args.root_url}" if args.root_url bottle_args << "--root-url=#{args.root_url}" if args.root_url
odie "No JSON files found in the current working directory" if Dir["*.json"].empty? bottle_args += json_files
bottle_args += Dir["*.json"]
if args.dry_run? if args.dry_run?
puts "brew #{bottle_args.join " "}" puts "brew #{bottle_args.join " "}"
puts "Upload bottles described by these JSON files to Bintray:\n #{Dir["*.json"].join("\n ")}" puts "Upload bottles described by these JSON files to Bintray:\n #{json_files.join("\n ")}"
else else
check_bottled_formulae(json_files)
safe_system HOMEBREW_BREW_FILE, *bottle_args safe_system HOMEBREW_BREW_FILE, *bottle_args
bintray.upload_bottle_json(Dir["*.json"], bintray.upload_bottle_json(json_files,
publish_package: !args.no_publish?, publish_package: !args.no_publish?,
warn_on_error: args.warn_on_upload_failure?) warn_on_error: args.warn_on_upload_failure?)
end end

View File

@ -37,8 +37,7 @@ module Homebrew
description: "Do not warn if pulling to a branch besides master (useful for testing)." description: "Do not warn if pulling to a branch besides master (useful for testing)."
switch "--no-pbcopy", switch "--no-pbcopy",
description: "Do not copy anything to the system clipboard." description: "Do not copy anything to the system clipboard."
switch :verbose
switch :debug
min_named 1 min_named 1
end end
end end
@ -48,7 +47,7 @@ module Homebrew
odie "You meant `git pull --rebase`." if ARGV[0] == "--rebase" odie "You meant `git pull --rebase`." if ARGV[0] == "--rebase"
pull_args.parse args = pull_args.parse
# Passthrough Git environment variables for e.g. git am # Passthrough Git environment variables for e.g. git am
Utils.set_git_name_email!(author: false, committer: true) Utils.set_git_name_email!(author: false, committer: true)

View File

@ -21,7 +21,7 @@ module Homebrew
end end
def release_notes def release_notes
release_notes_args.parse args = release_notes_args.parse
previous_tag = args.named.first previous_tag = args.named.first
previous_tag ||= Utils.popen_read( previous_tag ||= Utils.popen_read(

View File

@ -13,23 +13,26 @@ module Homebrew
Run a Ruby instance with Homebrew's libraries loaded, e.g. Run a Ruby instance with Homebrew's libraries loaded, e.g.
`brew ruby -e "puts :gcc.f.deps"` or `brew ruby script.rb`. `brew ruby -e "puts :gcc.f.deps"` or `brew ruby script.rb`.
EOS EOS
switch "-r", flag "-r=",
description: "Load a library using `require`." description: "Load a library using `require`."
switch "-e", flag "-e=",
description: "Execute the given text string as a script." description: "Execute the given text string as a script."
switch :verbose
switch :debug
end end
end end
def ruby def ruby
ruby_args.parse args = ruby_args.parse
ruby_sys_args = []
ruby_sys_args << "-r#{args.r}" if args.r
ruby_sys_args << "-e #{args.e}" if args.e
ruby_sys_args += args.named
begin begin
safe_system RUBY_PATH, safe_system RUBY_PATH,
"-I", $LOAD_PATH.join(File::PATH_SEPARATOR), "-I", $LOAD_PATH.join(File::PATH_SEPARATOR),
"-rglobal", "-rdev-cmd/irb", "-rglobal", "-rdev-cmd/irb",
*ARGV *ruby_sys_args
rescue ErrorDuringExecution => e rescue ErrorDuringExecution => e
exit e.status.exitstatus exit e.status.exitstatus
end end

View File

@ -20,8 +20,7 @@ module Homebrew
EOS EOS
flag "--env=", flag "--env=",
description: "Use the standard `PATH` instead of superenv's when `std` is passed." description: "Use the standard `PATH` instead of superenv's when `std` is passed."
switch :verbose
switch :debug
max_named 0 max_named 0
end end
end end
@ -29,14 +28,14 @@ module Homebrew
def sh def sh
args = sh_args.parse args = sh_args.parse
ENV.activate_extensions!(args: args) ENV.activate_extensions!(env: args.env)
if superenv?(args: args) if superenv?(args.env)
ENV.set_x11_env_if_installed ENV.set_x11_env_if_installed
ENV.deps = Formula.installed.select { |f| f.keg_only? && f.opt_prefix.directory? } ENV.deps = Formula.installed.select { |f| f.keg_only? && f.opt_prefix.directory? }
end end
ENV.setup_build_environment(args: args) ENV.setup_build_environment
if superenv?(args: args) if superenv?(args.env)
# superenv stopped adding brew's bin but generally users will want it # superenv stopped adding brew's bin but generally users will want it
ENV["PATH"] = PATH.new(ENV["PATH"]).insert(1, HOMEBREW_PREFIX/"bin") ENV["PATH"] = PATH.new(ENV["PATH"]).insert(1, HOMEBREW_PREFIX/"bin")
end end

View File

@ -29,14 +29,13 @@ module Homebrew
comma_array "--except-cops", comma_array "--except-cops",
description: "Specify a comma-separated <cops> list to skip checking for violations of the "\ description: "Specify a comma-separated <cops> list to skip checking for violations of the "\
"listed RuboCop cops." "listed RuboCop cops."
switch :verbose
switch :debug
conflicts "--only-cops", "--except-cops" conflicts "--only-cops", "--except-cops"
end end
end end
def style def style
style_args.parse args = style_args.parse
target = if args.no_named? target = if args.no_named?
nil nil
@ -51,7 +50,7 @@ module Homebrew
only_cops = args.only_cops only_cops = args.only_cops
except_cops = args.except_cops except_cops = args.except_cops
options = { fix: args.fix? } options = { fix: args.fix?, display_cop_names: args.display_cop_names? }
if only_cops if only_cops
options[:only_cops] = only_cops options[:only_cops] = only_cops
elsif except_cops elsif except_cops

View File

@ -13,14 +13,13 @@ module Homebrew
Generate the template files for a new tap. Generate the template files for a new tap.
EOS EOS
switch :verbose
switch :debug
named 1 named 1
end end
end end
def tap_new def tap_new
tap_new_args.parse args = tap_new_args.parse
tap_name = args.named.first tap_name = args.named.first
tap = Tap.fetch(args.named.first) tap = Tap.fetch(args.named.first)

View File

@ -25,15 +25,16 @@ module Homebrew
description: "Test the head version of a formula." description: "Test the head version of a formula."
switch "--keep-tmp", switch "--keep-tmp",
description: "Retain the temporary files created for the test." description: "Retain the temporary files created for the test."
switch :verbose switch "--retry",
switch :debug description: "Retry if a testing fails."
conflicts "--devel", "--HEAD" conflicts "--devel", "--HEAD"
min_named :formula min_named :formula
end end
end end
def test def test
test_args.parse args = test_args.parse
require "formula_assertions" require "formula_assertions"
require "formula_free_port" require "formula_free_port"
@ -70,7 +71,7 @@ module Homebrew
next next
end end
puts "Testing #{f.full_name}" oh1 "Testing #{f.full_name}"
env = ENV.to_hash env = ENV.to_hash
@ -108,6 +109,7 @@ module Homebrew
end end
end end
rescue Exception => e # rubocop:disable Lint/RescueException rescue Exception => e # rubocop:disable Lint/RescueException
retry if retry_test?(f, args: args)
ofail "#{f.full_name}: failed" ofail "#{f.full_name}: failed"
puts e, e.backtrace puts e, e.backtrace
ensure ensure
@ -115,4 +117,16 @@ module Homebrew
end end
end end
end end
def retry_test?(f, args:)
@test_failed ||= Set.new
if args.retry? && @test_failed.add?(f)
oh1 "Testing #{f.full_name} (again)"
f.clear_cache
true
else
Homebrew.failed = true
false
end
end
end end

View File

@ -29,14 +29,13 @@ module Homebrew
"specific line." "specific line."
flag "--seed=", flag "--seed=",
description: "Randomise tests with the specified <value> instead of a random seed." description: "Randomise tests with the specified <value> instead of a random seed."
switch :verbose
switch :debug
max_named 0 max_named 0
end end
end end
def tests def tests
tests_args.parse args = tests_args.parse
Homebrew.install_bundler_gems! Homebrew.install_bundler_gems!
gem_user_dir = Gem.user_dir gem_user_dir = Gem.user_dir

View File

@ -22,16 +22,16 @@ module Homebrew
switch "-g", "--git", switch "-g", "--git",
description: "Initialise a Git repository in the unpacked source. This is useful for creating "\ description: "Initialise a Git repository in the unpacked source. This is useful for creating "\
"patches for the software." "patches for the software."
switch :force switch "-f", "--force",
switch :verbose description: "Overwrite the destination directory if it already exists."
switch :debug
conflicts "--git", "--patch" conflicts "--git", "--patch"
min_named :formula min_named :formula
end end
end end
def unpack def unpack
unpack_args.parse args = unpack_args.parse
formulae = args.formulae formulae = args.formulae
@ -55,12 +55,13 @@ module Homebrew
oh1 "Unpacking #{Formatter.identifier(f.full_name)} to: #{stage_dir}" oh1 "Unpacking #{Formatter.identifier(f.full_name)} to: #{stage_dir}"
ENV["VERBOSE"] = "1" # show messages about tar # show messages about tar
with_env VERBOSE: "1" do
f.brew do f.brew do
f.patch if args.patch? f.patch if args.patch?
cp_r getwd, stage_dir, preserve: true cp_r getwd, stage_dir, preserve: true
end end
ENV["VERBOSE"] = nil end
next unless args.git? next unless args.git?

View File

@ -26,7 +26,7 @@ module Homebrew
end end
def update_license_data def update_license_data
update_license_data_args.parse args = update_license_data_args.parse
ohai "Updating SPDX license data..." ohai "Updating SPDX license data..."
latest_tag = GitHub.open_api(SPDX_API_URL)["tag_name"] latest_tag = GitHub.open_api(SPDX_API_URL)["tag_name"]

View File

@ -0,0 +1,37 @@
# frozen_string_literal: true
require "cli/parser"
require "utils/pypi"
module Homebrew
module_function
def update_python_resources_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`update-python-resources` [<options>] <formula>
Update versions for PyPI resource blocks in <formula>.
EOS
switch "-p", "--print-only",
description: "Print the updated resource blocks instead of changing <formula>."
switch "-s", "--silent",
description: "Suppress any output."
switch "--ignore-non-pypi-packages",
description: "Don't fail if <formula> is not a PyPI package."
flag "--version=",
description: "Use the specified <version> when finding resources for <formula>. "\
"If no version is specified, the current version for <formula> will be used."
min_named :formula
end
end
def update_python_resources
args = update_python_resources_args.parse
args.formulae.each do |formula|
PyPI.update_python_resources! formula, args.version, print_only: args.print_only?, silent: args.silent?,
ignore_non_pypi_packages: args.ignore_non_pypi_packages?
end
end
end

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