This commit is contained in:
metacollin 2020-11-19 20:18:12 -07:00
commit 87ff28431f
432 changed files with 7375 additions and 3507 deletions

View File

@ -6,7 +6,6 @@ on:
env: env:
HOMEBREW_DEVELOPER: 1 HOMEBREW_DEVELOPER: 1
HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_GITHUB_ACTIONS_BIG_SUR_TESTING: 1 # TODO: remove when Big Sur is released.
jobs: jobs:
tests: tests:
if: github.repository == 'Homebrew/brew' if: github.repository == 'Homebrew/brew'

2
.gitignore vendored
View File

@ -24,6 +24,7 @@
# Ignore Bundler files # Ignore Bundler files
**/.bundle/bin **/.bundle/bin
**/.bundle/cache **/.bundle/cache
**/vendor/bundle/ruby/*/bundler.lock
**/vendor/bundle/ruby/*/bin **/vendor/bundle/ruby/*/bin
**/vendor/bundle/ruby/*/build_info/ **/vendor/bundle/ruby/*/build_info/
**/vendor/bundle/ruby/*/cache **/vendor/bundle/ruby/*/cache
@ -127,6 +128,7 @@
**/vendor/bundle/ruby/*/gems/rspec-mocks-*/ **/vendor/bundle/ruby/*/gems/rspec-mocks-*/
**/vendor/bundle/ruby/*/gems/rspec-retry-*/ **/vendor/bundle/ruby/*/gems/rspec-retry-*/
**/vendor/bundle/ruby/*/gems/rspec-support-*/ **/vendor/bundle/ruby/*/gems/rspec-support-*/
**/vendor/bundle/ruby/*/gems/rspec-sorbet-*/
**/vendor/bundle/ruby/*/gems/rspec-wait-*/ **/vendor/bundle/ruby/*/gems/rspec-wait-*/
**/vendor/bundle/ruby/*/gems/rubocop-1*/ **/vendor/bundle/ruby/*/gems/rubocop-1*/
**/vendor/bundle/ruby/*/gems/rubocop-ast-*/ **/vendor/bundle/ruby/*/gems/rubocop-ast-*/

View File

@ -18,6 +18,7 @@ AllCops:
- 'Homebrew/sorbet/rbi/gems/**/*.rbi' - 'Homebrew/sorbet/rbi/gems/**/*.rbi'
- 'Homebrew/sorbet/rbi/hidden-definitions/**/*.rbi' - 'Homebrew/sorbet/rbi/hidden-definitions/**/*.rbi'
- 'Homebrew/sorbet/rbi/todo.rbi' - 'Homebrew/sorbet/rbi/todo.rbi'
- 'Homebrew/sorbet/rbi/upstream.rbi'
- 'Homebrew/bin/*' - 'Homebrew/bin/*'
- 'Homebrew/vendor/**/*' - 'Homebrew/vendor/**/*'
@ -69,7 +70,7 @@ Naming/HeredocDelimiterNaming:
Naming/MethodName: Naming/MethodName:
IgnoredPatterns: IgnoredPatterns:
- '\AHEAD\?\Z' - '\A(fetch_)?HEAD\?\Z'
# Allow dashes in filenames. # Allow dashes in filenames.
Naming/FileName: Naming/FileName:
@ -108,7 +109,9 @@ Style/HashTransformValues:
# Allow for license expressions # Allow for license expressions
Style/HashAsLastArrayItem: Style/HashAsLastArrayItem:
Exclude: Exclude:
- 'Taps/*/*/{Formula/,}*.rb' - 'Taps/*/*/*.rb'
- '/**/Formula/*.rb'
- '**/Formula/*.rb'
# Enabled now LineLength is lowish. # Enabled now LineLength is lowish.
Style/IfUnlessModifier: Style/IfUnlessModifier:
@ -118,6 +121,8 @@ Style/IfUnlessModifier:
Style/NumericLiterals: Style/NumericLiterals:
MinDigits: 7 MinDigits: 7
Strict: true Strict: true
Exclude:
- '**/Brewfile'
# Zero-prefixed octal literals are widely used and understood. # Zero-prefixed octal literals are widely used and understood.
Style/NumericLiteralPrefix: Style/NumericLiteralPrefix:
@ -161,11 +166,17 @@ Performance/CaseWhenSplat:
Performance/Caller: Performance/Caller:
Enabled: false Enabled: false
# Makes code less readable for minor performance increases.
Performance/MethodObjectAsBlock:
Enabled: false
# Don't allow cops to be disabled in casks and formulae. # Don't allow cops to be disabled in casks and formulae.
Style/DisableCopsWithinSourceCodeDirective: Style/DisableCopsWithinSourceCodeDirective:
Enabled: true Enabled: true
Include: Include:
- 'Taps/*/*/{Formula/,Casks/,}*.rb' - 'Taps/*/*/*.rb'
- '/**/{Formula,Casks}/*.rb'
- '**/{Formula,Casks}/*.rb'
# make our hashes consistent # make our hashes consistent
Layout/HashAlignment: Layout/HashAlignment:
@ -175,7 +186,9 @@ Layout/HashAlignment:
# `system` is a special case and aligns on second argument, so allow this for formulae. # `system` is a special case and aligns on second argument, so allow this for formulae.
Layout/ArgumentAlignment: Layout/ArgumentAlignment:
Exclude: Exclude:
- 'Taps/*/*/{Formula/,}*.rb' - 'Taps/*/*/*.rb'
- '/**/Formula/*.rb'
- '**/Formula/*.rb'
# this is a bit less "floaty" # this is a bit less "floaty"
Layout/CaseIndentation: Layout/CaseIndentation:
@ -197,6 +210,12 @@ Layout/RescueEnsureAlignment:
Lint/AmbiguousBlockAssociation: Lint/AmbiguousBlockAssociation:
Enabled: false Enabled: false
Lint/DuplicateBranch:
Exclude:
- 'Taps/*/*/*.rb'
- '/**/{Formula,Casks}/*.rb'
- '**/{Formula,Casks}/*.rb'
# needed for lazy_object magic # needed for lazy_object magic
Naming/MemoizedInstanceVariableName: Naming/MemoizedInstanceVariableName:
Exclude: Exclude:
@ -206,7 +225,9 @@ Naming/MemoizedInstanceVariableName:
# TODO: fix these as `ruby -w` complains about them. # TODO: fix these as `ruby -w` complains about them.
Lint/AmbiguousRegexpLiteral: Lint/AmbiguousRegexpLiteral:
Exclude: Exclude:
- 'Taps/*/*/{Formula/,}*.rb' - 'Taps/*/*/*.rb'
- '/**/Formula/*.rb'
- '**/Formula/*.rb'
# useful for metaprogramming in RSpec # useful for metaprogramming in RSpec
Lint/ConstantDefinitionInBlock: Lint/ConstantDefinitionInBlock:
@ -216,30 +237,46 @@ Lint/ConstantDefinitionInBlock:
# so many of these in formulae and can't be autocorrected # so many of these in formulae and can't be autocorrected
Lint/ParenthesesAsGroupedExpression: Lint/ParenthesesAsGroupedExpression:
Exclude: Exclude:
- 'Taps/*/*/{Formula/,}*.rb' - 'Taps/*/*/*.rb'
- '/**/Formula/*.rb'
- '**/Formula/*.rb'
# Most metrics don't make sense to apply for casks/formulae/taps. # Most metrics don't make sense to apply for casks/formulae/taps.
Metrics/AbcSize: Metrics/AbcSize:
Exclude: Exclude:
- 'Taps/**/*' - 'Taps/**/*'
- '/**/{Formula,Casks}/*.rb'
- '**/{Formula,Casks}/*.rb'
Metrics/BlockLength: Metrics/BlockLength:
Exclude: Exclude:
- 'Taps/**/*' - 'Taps/**/*'
- '/**/{Formula,Casks}/*.rb'
- '**/{Formula,Casks}/*.rb'
Metrics/ClassLength: Metrics/ClassLength:
Exclude: Exclude:
- 'Taps/**/*' - 'Taps/**/*'
- '/**/{Formula,Casks}/*.rb'
- '**/{Formula,Casks}/*.rb'
Metrics/CyclomaticComplexity: Metrics/CyclomaticComplexity:
Exclude: Exclude:
- 'Taps/**/*' - 'Taps/**/*'
- '/**/{Formula,Casks}/*.rb'
- '**/{Formula,Casks}/*.rb'
Metrics/MethodLength: Metrics/MethodLength:
Exclude: Exclude:
- 'Taps/**/*' - 'Taps/**/*'
- '/**/{Formula,Casks}/*.rb'
- '**/{Formula,Casks}/*.rb'
Metrics/ModuleLength: Metrics/ModuleLength:
Exclude: Exclude:
- 'Taps/**/*' - 'Taps/**/*'
- '/**/{Formula,Casks}/*.rb'
- '**/{Formula,Casks}/*.rb'
Metrics/PerceivedComplexity: Metrics/PerceivedComplexity:
Exclude: Exclude:
- 'Taps/**/*' - 'Taps/**/*'
- '/**/{Formula,Casks}/*.rb'
- '**/{Formula,Casks}/*.rb'
# allow those that are standard # allow those that are standard
# TODO: try to remove some of these # TODO: try to remove some of these
@ -280,7 +317,9 @@ Layout/LineLength:
Sorbet/FalseSigil: Sorbet/FalseSigil:
Exclude: Exclude:
- 'Taps/**/*.rb' - 'Taps/**/*'
- '/**/{Formula,Casks}/*.rb'
- '**/{Formula,Casks}/*.rb'
- 'Homebrew/test/**/Casks/**/*.rb' - 'Homebrew/test/**/Casks/**/*.rb'
Sorbet/StrictSigil: Sorbet/StrictSigil:
@ -297,15 +336,9 @@ Sorbet/ConstantsFromStrings:
Style/AccessModifierDeclarations: Style/AccessModifierDeclarations:
Enabled: false Enabled: false
# don't group nicely documented or private attr_readers # Conflicts with type signatures on `attr_*`s.
Style/AccessorGrouping: Style/AccessorGrouping:
Exclude: Enabled: false
- 'Homebrew/formula.rb'
- 'Homebrew/formulary.rb'
- 'Homebrew/migrator.rb'
- 'Homebrew/resource.rb'
- 'Homebrew/system_command.rb'
- 'Homebrew/tap.rb'
# make rspec formatting more flexible # make rspec formatting more flexible
Style/BlockDelimiters: Style/BlockDelimiters:
@ -322,6 +355,8 @@ Style/ClassVars:
Style/Documentation: Style/Documentation:
Exclude: Exclude:
- 'Taps/**/*' - 'Taps/**/*'
- '/**/{Formula,Casks}/*.rb'
- '**/{Formula,Casks}/*.rb'
- '**/*.rbi' - '**/*.rbi'
Style/DocumentationMethod: Style/DocumentationMethod:
@ -332,9 +367,12 @@ Style/DocumentationMethod:
Style/FrozenStringLiteralComment: Style/FrozenStringLiteralComment:
EnforcedStyle: always EnforcedStyle: always
Exclude: Exclude:
- 'Taps/*/*/{Formula,Casks,}/*.rb' - 'Taps/*/*/*.rb'
- '/**/{Formula,Casks}/*.rb'
- '**/{Formula,Casks}/*.rb'
- 'Homebrew/test/**/Casks/**/*.rb' - 'Homebrew/test/**/Casks/**/*.rb'
- '**/*.rbi' - '**/*.rbi'
- '**/Brewfile'
# TODO: remove this when possible. # TODO: remove this when possible.
Style/GlobalVars: Style/GlobalVars:
@ -344,7 +382,9 @@ Style/GlobalVars:
# potential for errors in formulae too high with this # potential for errors in formulae too high with this
Style/GuardClause: Style/GuardClause:
Exclude: Exclude:
- 'Taps/*/*/{Formula/,Casks/,}*.rb' - 'Taps/*/*/*.rb'
- '/**/{Formula,Casks}/*.rb'
- '**/{Formula,Casks}/*.rb'
# avoid hash rockets where possible # avoid hash rockets where possible
Style/HashSyntax: Style/HashSyntax:
@ -353,7 +393,9 @@ Style/HashSyntax:
# so many of these in formulae and can't be autocorrected # so many of these in formulae and can't be autocorrected
Style/StringConcatenation: Style/StringConcatenation:
Exclude: Exclude:
- 'Taps/*/*/{Formula/,Casks/,}*.rb' - 'Taps/*/*/*.rb'
- '/**/{Formula,Casks}/*.rb'
- '**/{Formula,Casks}/*.rb'
# ruby style guide favorite # ruby style guide favorite
Style/StringLiterals: Style/StringLiterals:

View File

@ -10,6 +10,7 @@ gem "ronn", require: false
gem "rspec", require: false gem "rspec", require: false
gem "rspec-its", require: false gem "rspec-its", require: false
gem "rspec-retry", require: false gem "rspec-retry", require: false
gem "rspec-sorbet", require: false
gem "rspec-wait", require: false gem "rspec-wait", require: false
gem "rubocop", require: false gem "rubocop", require: false
gem "simplecov", require: false gem "simplecov", require: false

View File

@ -44,7 +44,7 @@ GEM
method_source (1.0.0) method_source (1.0.0)
mime-types (3.3.1) mime-types (3.3.1)
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2020.0512) mime-types-data (3.2020.1104)
mini_portile2 (2.4.0) mini_portile2 (2.4.0)
minitest (5.14.2) minitest (5.14.2)
mustache (1.1.1) mustache (1.1.1)
@ -95,39 +95,42 @@ GEM
rspec-support (~> 3.10.0) rspec-support (~> 3.10.0)
rspec-retry (0.6.2) rspec-retry (0.6.2)
rspec-core (> 3.3) rspec-core (> 3.3)
rspec-sorbet (1.7.0)
sorbet
sorbet-runtime
rspec-support (3.10.0) rspec-support (3.10.0)
rspec-wait (0.0.9) rspec-wait (0.0.9)
rspec (>= 3, < 4) rspec (>= 3, < 4)
rubocop (1.2.0) rubocop (1.3.1)
parallel (~> 1.10) parallel (~> 1.10)
parser (>= 2.7.1.5) parser (>= 2.7.1.5)
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8) regexp_parser (>= 1.8)
rexml rexml
rubocop-ast (>= 1.0.1) rubocop-ast (>= 1.1.1)
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 (1.1.1) rubocop-ast (1.1.1)
parser (>= 2.7.1.5) parser (>= 2.7.1.5)
rubocop-performance (1.8.1) rubocop-performance (1.9.0)
rubocop (>= 0.87.0) rubocop (>= 0.90.0, < 2.0)
rubocop-ast (>= 0.4.0) rubocop-ast (>= 0.4.0)
rubocop-rspec (2.0.0) rubocop-rspec (2.0.0)
rubocop (~> 1.0) rubocop (~> 1.0)
rubocop-ast (>= 1.1.0) rubocop-ast (>= 1.1.0)
rubocop-sorbet (0.5.1) rubocop-sorbet (0.5.1)
rubocop rubocop
ruby-macho (2.2.0) ruby-macho (2.5.0)
ruby-progressbar (1.10.1) ruby-progressbar (1.10.1)
simplecov (0.19.1) simplecov (0.19.1)
docile (~> 1.1) docile (~> 1.1)
simplecov-html (~> 0.11) simplecov-html (~> 0.11)
simplecov-html (0.12.3) simplecov-html (0.12.3)
sorbet (0.5.6042) sorbet (0.5.6076)
sorbet-static (= 0.5.6042) sorbet-static (= 0.5.6076)
sorbet-runtime (0.5.6040) sorbet-runtime (0.5.6076)
sorbet-runtime-stub (0.2.0) sorbet-runtime-stub (0.2.0)
sorbet-static (0.5.6042-universal-darwin-14) sorbet-static (0.5.6076-universal-darwin-14)
spoom (1.0.4) spoom (1.0.4)
colorize colorize
sorbet (~> 0.5.5) sorbet (~> 0.5.5)
@ -142,14 +145,14 @@ GEM
thor (>= 0.19.2) thor (>= 0.19.2)
thor (1.0.1) thor (1.0.1)
thread_safe (0.3.6) thread_safe (0.3.6)
tzinfo (1.2.7) tzinfo (1.2.8)
thread_safe (~> 0.1) thread_safe (~> 0.1)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.7) unf_ext (0.0.7.7)
unicode-display_width (1.7.0) unicode-display_width (1.7.0)
webrobots (0.1.2) webrobots (0.1.2)
zeitwerk (2.4.0) zeitwerk (2.4.1)
PLATFORMS PLATFORMS
ruby ruby
@ -167,6 +170,7 @@ DEPENDENCIES
rspec rspec
rspec-its rspec-its
rspec-retry rspec-retry
rspec-sorbet
rspec-wait rspec-wait
rubocop rubocop
rubocop-performance rubocop-performance

View File

@ -67,13 +67,9 @@ class PATH
sig { params(other: T.untyped).returns(T::Boolean) } sig { params(other: T.untyped).returns(T::Boolean) }
def ==(other) def ==(other)
if other.respond_to?(:to_ary) && to_ary == other.to_ary (other.respond_to?(:to_ary) && to_ary == other.to_ary) ||
true (other.respond_to?(:to_str) && to_str == other.to_str) ||
elsif other.respond_to?(:to_str) && to_str == other.to_str
true
else
false false
end
end end
sig { returns(T::Boolean) } sig { returns(T::Boolean) }

View File

@ -8,6 +8,8 @@ require "json"
# #
# @api private # @api private
class Bintray class Bintray
extend T::Sig
include Context include Context
API_URL = "https://api.bintray.com" API_URL = "https://api.bintray.com"
@ -15,6 +17,7 @@ class Bintray
class Error < RuntimeError class Error < RuntimeError
end end
sig { returns(String) }
def inspect def inspect
"#<Bintray: org=#{@bintray_org}>" "#<Bintray: org=#{@bintray_org}>"
end end

View File

@ -164,7 +164,7 @@ rescue BuildError => e
if e.formula.head? || e.formula.deprecated? || e.formula.disabled? if e.formula.head? || e.formula.deprecated? || e.formula.disabled?
$stderr.puts <<~EOS $stderr.puts <<~EOS
Please create pull requests instead of asking for help on Homebrew's GitHub, Please create pull requests instead of asking for help on Homebrew's GitHub,
Discourse, Twitter or any other official channels. Twitter or any other official channels.
EOS EOS
end end

View File

@ -53,11 +53,7 @@ class Build
def expand_reqs def expand_reqs
formula.recursive_requirements do |dependent, req| formula.recursive_requirements do |dependent, req|
build = effective_build_options_for(dependent) build = effective_build_options_for(dependent)
if req.prune_from_option?(build) if req.prune_from_option?(build) || req.prune_if_build_and_not_dependent?(dependent, formula) || req.test?
Requirement.prune
elsif req.prune_if_build_and_not_dependent?(dependent, formula)
Requirement.prune
elsif req.test?
Requirement.prune Requirement.prune
end end
end end
@ -66,14 +62,12 @@ class Build
def expand_deps def expand_deps
formula.recursive_dependencies do |dependent, dep| formula.recursive_dependencies do |dependent, dep|
build = effective_build_options_for(dependent) build = effective_build_options_for(dependent)
if dep.prune_from_option?(build) if dep.prune_from_option?(build) ||
Dependency.prune dep.prune_if_build_and_not_dependent?(dependent, formula) ||
elsif dep.prune_if_build_and_not_dependent?(dependent, formula) (dep.test? && !dep.build?)
Dependency.prune Dependency.prune
elsif dep.build? elsif dep.build?
Dependency.keep_but_prune_recursive_deps Dependency.keep_but_prune_recursive_deps
elsif dep.test?
Dependency.prune
end end
end end
end end

View File

@ -1,34 +1,44 @@
# typed: false # typed: true
# frozen_string_literal: true # frozen_string_literal: true
# Settings for the build environment. # Settings for the build environment.
# #
# @api private # @api private
class BuildEnvironment class BuildEnvironment
extend T::Sig
sig { params(settings: Symbol).void }
def initialize(*settings) def initialize(*settings)
@settings = Set.new(*settings) @settings = Set.new(settings)
end end
sig { params(args: T::Enumerable[Symbol]).returns(T.self_type) }
def merge(*args) def merge(*args)
@settings.merge(*args) @settings.merge(*args)
self self
end end
sig { params(o: Symbol).returns(T.self_type) }
def <<(o) def <<(o)
@settings << o @settings << o
self self
end end
sig { returns(T::Boolean) }
def std? def std?
@settings.include? :std @settings.include? :std
end end
sig { returns(T::Boolean) }
def userpaths? def userpaths?
@settings.include? :userpaths @settings.include? :userpaths
end end
# DSL for specifying build environment settings. # DSL for specifying build environment settings.
module DSL module DSL
extend T::Sig
sig { params(settings: Symbol).returns(BuildEnvironment) }
def env(*settings) def env(*settings)
@env ||= BuildEnvironment.new @env ||= BuildEnvironment.new
@env.merge(settings) @env.merge(settings)
@ -50,16 +60,18 @@ class BuildEnvironment
].freeze ].freeze
private_constant :KEYS private_constant :KEYS
sig { params(env: T.untyped).returns(T::Array[String]) }
def self.keys(env) def self.keys(env)
KEYS & env.keys KEYS & env.keys
end end
sig { params(env: T.untyped, f: IO).void }
def self.dump(env, f = $stdout) def self.dump(env, f = $stdout)
keys = self.keys(env) keys = self.keys(env)
keys -= %w[CC CXX OBJC OBJCXX] if env["CC"] == env["HOMEBREW_CC"] keys -= %w[CC CXX OBJC OBJCXX] if env["CC"] == env["HOMEBREW_CC"]
keys.each do |key| keys.each do |key|
value = env[key] value = env.fetch(key)
s = +"#{key}: #{value}" s = +"#{key}: #{value}"
case key case key
when "CC", "CXX", "LD" when "CC", "CXX", "LD"

View File

@ -7,6 +7,8 @@ module Cask
# #
# @api private # @api private
class AbstractArtifact class AbstractArtifact
extend T::Sig
include Comparable include Comparable
extend Predicable extend Predicable
@ -132,6 +134,7 @@ module Cask
cask.config cask.config
end end
sig { returns(String) }
def to_s def to_s
"#{summarize} (#{self.class.english_name})" "#{summarize} (#{self.class.english_name})"
end end

View File

@ -15,6 +15,8 @@ module Cask
# #
# @api private # @api private
class AbstractUninstall < AbstractArtifact class AbstractUninstall < AbstractArtifact
extend T::Sig
ORDERED_DIRECTIVES = [ ORDERED_DIRECTIVES = [
:early_script, :early_script,
:launchctl, :launchctl,
@ -53,6 +55,7 @@ module Cask
directives.to_h directives.to_h
end end
sig { returns(String) }
def summarize def summarize
to_h.flat_map { |key, val| Array(val).map { |v| "#{key.inspect} => #{v.inspect}" } }.join(", ") to_h.flat_map { |key, val| Array(val).map { |v| "#{key.inspect} => #{v.inspect}" } }.join(", ")
end end
@ -128,6 +131,7 @@ module Cask
end end
end end
sig { returns(String) }
def automation_access_instructions def automation_access_instructions
"Enable Automation Access for “Terminal > System Events” in " \ "Enable Automation Access for “Terminal > System Events” in " \
"“System Preferences > Security > Privacy > Automation” if you haven't already." "“System Preferences > Security > Privacy > Automation” if you haven't already."

View File

@ -12,6 +12,9 @@ module Cask
# #
# @api private # @api private
class Artifact < Moved class Artifact < Moved
extend T::Sig
sig { returns(String) }
def self.english_name def self.english_name
"Generic Artifact" "Generic Artifact"
end end

View File

@ -9,6 +9,9 @@ module Cask
# #
# @api private # @api private
class Mdimporter < Moved class Mdimporter < Moved
extend T::Sig
sig { returns(String) }
def self.english_name def self.english_name
"Spotlight metadata importer" "Spotlight metadata importer"
end end

View File

@ -9,6 +9,9 @@ module Cask
# #
# @api private # @api private
class Moved < Relocated class Moved < Relocated
extend T::Sig
sig { returns(String) }
def self.english_description def self.english_description
"#{english_name}s" "#{english_name}s"
end end

View File

@ -9,6 +9,9 @@ module Cask
# #
# @api private # @api private
class Prefpane < Moved class Prefpane < Moved
extend T::Sig
sig { returns(String) }
def self.english_name def self.english_name
"Preference Pane" "Preference Pane"
end end

View File

@ -9,6 +9,9 @@ module Cask
# #
# @api private # @api private
class Qlplugin < Moved class Qlplugin < Moved
extend T::Sig
sig { returns(String) }
def self.english_name def self.english_name
"QuickLook Plugin" "QuickLook Plugin"
end end

View File

@ -12,6 +12,8 @@ module Cask
# #
# @api private # @api private
class Relocated < AbstractArtifact class Relocated < AbstractArtifact
extend T::Sig
def self.from_args(cask, *args) def self.from_args(cask, *args)
source_string, target_hash = args source_string, target_hash = args
@ -49,6 +51,7 @@ module Cask
end end
end end
sig { returns(String) }
def summarize def summarize
target_string = @target_string.empty? ? "" : " -> #{@target_string}" target_string = @target_string.empty? ? "" : " -> #{@target_string}"
"#{@source_string}#{target_string}" "#{@source_string}#{target_string}"

View File

@ -9,16 +9,20 @@ module Cask
# #
# @api private # @api private
class StageOnly < AbstractArtifact class StageOnly < AbstractArtifact
extend T::Sig
def self.from_args(cask, *args) def self.from_args(cask, *args)
raise CaskInvalidError.new(cask.token, "'stage_only' takes only a single argument: true") if args != [true] raise CaskInvalidError.new(cask.token, "'stage_only' takes only a single argument: true") if args != [true]
new(cask) new(cask)
end end
sig { returns(T::Array[T::Boolean]) }
def to_a def to_a
[true] [true]
end end
sig { returns(String) }
def summarize def summarize
"true" "true"
end end

View File

@ -9,10 +9,14 @@ module Cask
# #
# @api private # @api private
class Suite < Moved class Suite < Moved
extend T::Sig
sig { returns(String) }
def self.english_name def self.english_name
"App Suite" "App Suite"
end end
sig { returns(Symbol) }
def self.dirmethod def self.dirmethod
:appdir :appdir
end end

View File

@ -9,10 +9,14 @@ module Cask
# #
# @api private # @api private
class Symlinked < Relocated class Symlinked < Relocated
extend T::Sig
sig { returns(String) }
def self.link_type_english_name def self.link_type_english_name
"Symlink" "Symlink"
end end
sig { returns(String) }
def self.english_description def self.english_description
"#{english_name} #{link_type_english_name}s" "#{english_name} #{link_type_english_name}s"
end end

View File

@ -13,6 +13,8 @@ module Cask
# #
# @api private # @api private
class Audit class Audit
extend T::Sig
extend Predicable extend Predicable
attr_reader :cask, :download attr_reader :cask, :download
@ -117,6 +119,7 @@ module Cask
end end
end end
sig { returns(String) }
def summary def summary
summary = ["audit for #{cask}: #{result}"] summary = ["audit for #{cask}: #{result}"]
@ -416,6 +419,7 @@ module Cask
core_tap.formula_names core_tap.formula_names
end end
sig { returns(String) }
def core_formula_url def core_formula_url
"#{core_tap.default_remote}/blob/HEAD/Formula/#{cask.token}.rb" "#{core_tap.default_remote}/blob/HEAD/Formula/#{cask.token}.rb"
end end

View File

@ -6,9 +6,10 @@ module Cask
# #
# @api private # @api private
module Cache module Cache
module_function extend T::Sig
def path sig { returns(Pathname) }
def self.path
@path ||= HOMEBREW_CACHE/"Cask" @path ||= HOMEBREW_CACHE/"Cask"
end end
end end

View File

@ -12,6 +12,8 @@ module Cask
# #
# @api private # @api private
class Cask class Cask
extend T::Sig
extend Enumerable extend Enumerable
extend Forwardable extend Forwardable
extend Searchable extend Searchable
@ -20,7 +22,7 @@ module Cask
attr_reader :token, :sourcefile_path, :config, :default_config attr_reader :token, :sourcefile_path, :config, :default_config
def self.each(&block) def self.each(&block)
return to_enum unless block_given? return to_enum unless block
Tap.flat_map(&:cask_files).each do |f| Tap.flat_map(&:cask_files).each do |f|
block.call CaskLoader::FromTapPathLoader.new(f).load(config: nil) block.call CaskLoader::FromTapPathLoader.new(f).load(config: nil)
@ -64,6 +66,7 @@ module Cask
define_method(method_name) { |&block| @dsl.send(method_name, &block) } define_method(method_name) { |&block| @dsl.send(method_name, &block) }
end end
sig { returns(T::Array[[String, String]]) }
def timestamped_versions def timestamped_versions
Pathname.glob(metadata_timestamped_path(version: "*", timestamp: "*")) Pathname.glob(metadata_timestamped_path(version: "*", timestamp: "*"))
.map { |p| p.relative_path_from(p.parent.parent) } .map { |p| p.relative_path_from(p.parent.parent) }
@ -89,6 +92,7 @@ module Cask
!versions.empty? !versions.empty?
end end
sig { returns(T.nilable(Time)) }
def install_time def install_time
_, time = timestamped_versions.last _, time = timestamped_versions.last
return unless time return unless time

View File

@ -90,6 +90,8 @@ module Cask
# Loads a cask from a URI. # Loads a cask from a URI.
class FromURILoader < FromPathLoader class FromURILoader < FromPathLoader
extend T::Sig
def self.can_load?(ref) def self.can_load?(ref)
uri_regex = ::URI::DEFAULT_PARSER.make_regexp uri_regex = ::URI::DEFAULT_PARSER.make_regexp
return false unless ref.to_s.match?(Regexp.new("\\A#{uri_regex.source}\\Z", uri_regex.options)) return false unless ref.to_s.match?(Regexp.new("\\A#{uri_regex.source}\\Z", uri_regex.options))
@ -103,6 +105,7 @@ module Cask
attr_reader :url attr_reader :url
sig { params(url: T.any(URI::Generic, String)).void }
def initialize(url) def initialize(url)
@url = URI(url) @url = URI(url)
super Cache.path/File.basename(@url.path) super Cache.path/File.basename(@url.path)
@ -177,10 +180,13 @@ module Cask
# Pseudo-loader which raises an error when trying to load the corresponding cask. # Pseudo-loader which raises an error when trying to load the corresponding cask.
class NullLoader < FromPathLoader class NullLoader < FromPathLoader
extend T::Sig
def self.can_load?(*) def self.can_load?(*)
true true
end end
sig { params(ref: T.any(String, Pathname)).void }
def initialize(ref) def initialize(ref)
token = File.basename(ref, ".rb") token = File.basename(ref, ".rb")
super CaskLoader.default_path(token) super CaskLoader.default_path(token)

View File

@ -1,4 +1,4 @@
# typed: false # typed: true
# frozen_string_literal: true # frozen_string_literal: true
require "utils/user" require "utils/user"
@ -8,13 +8,15 @@ module Cask
# #
# @api private # @api private
module Caskroom module Caskroom
module_function extend T::Sig
def path sig { returns(Pathname) }
def self.path
@path ||= HOMEBREW_PREFIX.join("Caskroom") @path ||= HOMEBREW_PREFIX.join("Caskroom")
end end
def ensure_caskroom_exists sig { void }
def self.ensure_caskroom_exists
return if path.exist? return if path.exist?
sudo = !path.parent.writable? sudo = !path.parent.writable?
@ -30,7 +32,8 @@ module Cask
SystemCommand.run("/usr/bin/chgrp", args: ["admin", path], sudo: sudo) SystemCommand.run("/usr/bin/chgrp", args: ["admin", path], sudo: sudo)
end end
def casks(config: nil) sig { params(config: T.nilable(Config)).returns(T::Array[Cask]) }
def self.casks(config: nil)
return [] unless path.exist? return [] unless path.exist?
Pathname.glob(path.join("*")).sort.select(&:directory?).map do |path| Pathname.glob(path.join("*")).sort.select(&:directory?).map do |path|

View File

@ -38,6 +38,8 @@ module Cask
# #
# @api private # @api private
class Cmd class Cmd
extend T::Sig
include Context include Context
ALIASES = { ALIASES = {
@ -61,11 +63,13 @@ module Cask
Cmd::Upgrade => "brew upgrade --cask", Cmd::Upgrade => "brew upgrade --cask",
}.freeze }.freeze
sig { returns(String) }
def self.description def self.description
max_command_length = Cmd.commands.map(&:length).max max_command_length = Cmd.commands.map(&:length).max
command_lines = Cmd.command_classes command_lines = Cmd.command_classes
.select(&:visible?) .select(&:visible?)
.reject { |command| DEPRECATED_COMMANDS.key?(command) }
.map do |klass| .map do |klass|
" - #{"`#{klass.command_name}`".ljust(max_command_length + 2)} #{klass.short_description}\n" " - #{"`#{klass.command_name}`".ljust(max_command_length + 2)} #{klass.short_description}\n"
end end
@ -75,14 +79,13 @@ module Cask
Commands: Commands:
#{command_lines.join} #{command_lines.join}
See also: `man brew` See also: `man brew`
EOS EOS
end end
def self.parser(&block) def self.parser(&block)
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
if block_given? if block
instance_eval(&block) instance_eval(&block)
else else
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -7,18 +7,24 @@ module Cask
# #
# @api private # @api private
class Cache < AbstractCommand class Cache < AbstractCommand
extend T::Sig
sig { override.returns(T.nilable(T.any(Integer, Symbol))) }
def self.min_named def self.min_named
:cask :cask
end end
sig { returns(String) }
def self.description def self.description
"Display the file used to cache a <cask>." "Display the file used to cache a <cask>."
end end
sig { returns(String) }
def self.command_name def self.command_name
"--cache" "--cache"
end end
sig { void }
def run def run
casks.each do |cask| casks.each do |cask|
puts self.class.cached_location(cask) puts self.class.cached_location(cask)

View File

@ -9,16 +9,22 @@ module Cask
# #
# @api private # @api private
class AbstractCommand class AbstractCommand
extend T::Sig
extend T::Helpers
include Homebrew::Search include Homebrew::Search
sig { returns(T.nilable(T.any(Integer, Symbol))) }
def self.min_named def self.min_named
nil nil
end end
sig { returns(T.nilable(Integer)) }
def self.max_named def self.max_named
nil nil
end end
sig { returns(String) }
def self.banner_args def self.banner_args
if min_named == :cask && max_named != 1 if min_named == :cask && max_named != 1
" <cask>" " <cask>"
@ -29,13 +35,14 @@ module Cask
end end
end end
sig { returns(String) }
def self.banner_headline def self.banner_headline
"`#{command_name}` [<options>]#{banner_args}" "`#{command_name}` [<options>]#{banner_args}"
end end
OPTIONS = [ OPTIONS = [
[:switch, "--[no-]binaries", { [:switch, "--[no-]binaries", {
description: "Disable/enable linking of helper executables. Default: enabled", description: "Disable/enable linking of helper executables (default: enabled).",
env: :cask_opts_binaries, env: :cask_opts_binaries,
}], }],
[:switch, "--require-sha", { [:switch, "--require-sha", {
@ -43,7 +50,7 @@ module Cask
env: :cask_opts_require_sha, env: :cask_opts_require_sha,
}], }],
[:switch, "--[no-]quarantine", { [:switch, "--[no-]quarantine", {
description: "Disable/enable quarantining of downloads. Default: enabled", description: "Disable/enable quarantining of downloads (default: enabled).",
env: :cask_opts_quarantine, env: :cask_opts_quarantine,
}], }],
].freeze ].freeze
@ -61,7 +68,7 @@ module Cask
Cmd.parser do Cmd.parser do
usage_banner banner usage_banner banner
instance_eval(&block) if block_given? instance_eval(&block) if block
OPTIONS.each do |option| OPTIONS.each do |option|
send(*option) send(*option)
@ -72,24 +79,29 @@ module Cask
end end
end end
sig { returns(String) }
def self.command_name def self.command_name
@command_name ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1_\2').downcase @command_name ||= name.sub(/^.*:/, "").gsub(/(.)([A-Z])/, '\1_\2').downcase
end end
sig { returns(T::Boolean) }
def self.abstract? def self.abstract?
name.split("::").last.match?(/^Abstract[^a-z]/) name.split("::").last.match?(/^Abstract[^a-z]/)
end end
sig { returns(T::Boolean) }
def self.visible? def self.visible?
true true
end end
sig { returns(String) }
def self.help def self.help
parser.generate_help_text parser.generate_help_text
end end
sig { returns(String) }
def self.short_description def self.short_description
description.split(".").first description[/\A[^.]*\./]
end end
def self.run(*args) def self.run(*args)

View File

@ -7,10 +7,14 @@ module Cask
# #
# @api private # @api private
class AbstractInternalCommand < AbstractCommand class AbstractInternalCommand < AbstractCommand
extend T::Sig
sig { returns(String) }
def self.command_name def self.command_name
super.sub(/^internal_/i, "_") super.sub(/^internal_/i, "_")
end end
sig { returns(T::Boolean) }
def self.visible? def self.visible?
false false
end end

View File

@ -9,6 +9,9 @@ module Cask
# #
# @api private # @api private
class Audit < AbstractCommand class Audit < AbstractCommand
extend T::Sig
sig { returns(String) }
def self.description def self.description
<<~EOS <<~EOS
Check <cask> for Homebrew coding style violations. This should be run before Check <cask> for Homebrew coding style violations. This should be run before
@ -37,57 +40,84 @@ module Cask
end end
end end
sig { void }
def run def run
require "cask/auditor"
Homebrew.auditing = true
options = {
audit_download: args.download?,
audit_appcast: args.appcast?,
audit_online: args.online?,
audit_strict: args.strict?,
audit_new_cask: args.new_cask?,
audit_token_conflicts: args.token_conflicts?,
quarantine: args.quarantine?,
language: args.language,
}.compact
options[:quarantine] = true if options[:quarantine].nil?
casks = args.named.flat_map do |name| casks = args.named.flat_map do |name|
if File.exist?(name) next name if File.exist?(name)
name next Tap.fetch(name).cask_files if name.count("/") == 1
elsif name.count("/") == 1
Tap.fetch(name).cask_files name
else
name
end
end end
casks = casks.map { |c| CaskLoader.load(c, config: Config.from_args(args)) } casks = casks.map { |c| CaskLoader.load(c, config: Config.from_args(args)) }
casks = Cask.to_a if casks.empty? casks = Cask.to_a if casks.empty?
failed_casks = casks.reject do |cask| results = self.class.audit_casks(
odebug "Auditing Cask #{cask}" *casks,
result = Auditor.audit(cask, **options) download: args.download?,
appcast: args.appcast?,
online: args.online?,
strict: args.strict?,
new_cask: args.new_cask?,
token_conflicts: args.token_conflicts?,
quarantine: args.quarantine?,
language: args.language,
)
if ENV["GITHUB_ACTIONS"] self.class.print_annotations(results)
cask_path = cask.sourcefile_path
annotations = (result[:warnings].map { |w| [:warning, w] } + result[:errors].map { |e| [:error, e] })
.map { |type, message| GitHub::Actions::Annotation.new(type, message, file: cask_path) }
annotations.each do |annotation|
puts annotation if annotation.relevant?
end
end
result[:errors].empty?
end
failed_casks = results.reject { |_, result| result[:errors].empty? }.map(&:first)
return if failed_casks.empty? return if failed_casks.empty?
raise CaskError, "audit failed for casks: #{failed_casks.join(" ")}" raise CaskError, "audit failed for casks: #{failed_casks.join(" ")}"
end end
def self.audit_casks(
*casks,
download: nil,
appcast: nil,
online: nil,
strict: nil,
new_cask: nil,
token_conflicts: nil,
quarantine: nil,
language: nil
)
options = {
audit_download: download,
audit_appcast: appcast,
audit_online: online,
audit_strict: strict,
audit_new_cask: new_cask,
audit_token_conflicts: token_conflicts,
quarantine: quarantine,
language: language,
}.compact
options[:quarantine] = true if options[:quarantine].nil?
Homebrew.auditing = true
require "cask/auditor"
casks.map do |cask|
odebug "Auditing Cask #{cask}"
[cask, Auditor.audit(cask, **options)]
end.to_h
end
def self.print_annotations(results)
return unless ENV["GITHUB_ACTIONS"]
results.each do |cask, result|
cask_path = cask.sourcefile_path
annotations = (result[:warnings].map { |w| [:warning, w] } + result[:errors].map { |e| [:error, e] })
.map { |type, message| GitHub::Actions::Annotation.new(type, message, file: cask_path) }
annotations.each do |annotation|
puts annotation if annotation.relevant?
end
end
end
end end
end end
end end

View File

@ -7,14 +7,19 @@ module Cask
# #
# @api private # @api private
class Cat < AbstractCommand class Cat < AbstractCommand
extend T::Sig
sig { override.returns(T.nilable(T.any(Integer, Symbol))) }
def self.min_named def self.min_named
:cask :cask
end end
sig { returns(String) }
def self.description def self.description
"Dump raw source of a <cask> to the standard output." "Dump raw source of a <cask> to the standard output."
end end
sig { void }
def run def run
casks.each do |cask| casks.each do |cask|
if Homebrew::EnvConfig.bat? if Homebrew::EnvConfig.bat?

View File

@ -7,14 +7,19 @@ module Cask
# #
# @api private # @api private
class Create < AbstractCommand class Create < AbstractCommand
extend T::Sig
sig { override.returns(T.nilable(T.any(Integer, Symbol))) }
def self.min_named def self.min_named
:cask :cask
end end
sig { override.returns(T.nilable(Integer)) }
def self.max_named def self.max_named
1 1
end end
sig { returns(String) }
def self.description def self.description
"Creates the given <cask> and opens it in an editor." "Creates the given <cask> and opens it in an editor."
end end
@ -25,6 +30,7 @@ module Cask
raise UsageError, "Only one cask can be created at a time." raise UsageError, "Only one cask can be created at a time."
end end
sig { void }
def run def run
cask_token = args.named.first cask_token = args.named.first
cask_path = CaskLoader.path(cask_token) cask_path = CaskLoader.path(cask_token)

View File

@ -7,14 +7,19 @@ module Cask
# #
# @api private # @api private
class Doctor < AbstractCommand class Doctor < AbstractCommand
extend T::Sig
sig { override.returns(T.nilable(Integer)) }
def self.max_named def self.max_named
0 0
end end
sig { returns(String) }
def self.description def self.description
"Checks for configuration issues." "Checks for configuration issues."
end end
sig { void }
def run def run
require "diagnostic" require "diagnostic"

View File

@ -7,14 +7,19 @@ module Cask
# #
# @api private # @api private
class Edit < AbstractCommand class Edit < AbstractCommand
extend T::Sig
sig { override.returns(T.nilable(T.any(Integer, Symbol))) }
def self.min_named def self.min_named
:cask :cask
end end
sig { override.returns(T.nilable(Integer)) }
def self.max_named def self.max_named
1 1
end end
sig { returns(String) }
def self.description def self.description
"Open the given <cask> for editing." "Open the given <cask> for editing."
end end
@ -25,6 +30,7 @@ module Cask
raise UsageError, "Only one cask can be edited at a time." raise UsageError, "Only one cask can be edited at a time."
end end
sig { void }
def run def run
exec_editor cask_path exec_editor cask_path
rescue CaskUnavailableError => e rescue CaskUnavailableError => e

View File

@ -7,6 +7,9 @@ module Cask
# #
# @api private # @api private
class Fetch < AbstractCommand class Fetch < AbstractCommand
extend T::Sig
sig { override.returns(T.nilable(T.any(Integer, Symbol))) }
def self.min_named def self.min_named
:cask :cask
end end
@ -18,10 +21,12 @@ module Cask
end end
end end
sig { returns(String) }
def self.description def self.description
"Downloads remote application files to local cache." "Downloads remote application files to local cache."
end end
sig { void }
def run def run
require "cask/download" require "cask/download"
require "cask/installer" require "cask/installer"

View File

@ -7,14 +7,19 @@ module Cask
# #
# @api private # @api private
class Help < AbstractCommand class Help < AbstractCommand
extend T::Sig
sig { override.returns(T.nilable(Integer)) }
def self.max_named def self.max_named
1 1
end end
sig { returns(String) }
def self.description def self.description
"Print help for `cask` commands." "Print help for `cask` commands."
end end
sig { void }
def run def run
if args.named.empty? if args.named.empty?
puts Cmd.parser.generate_help_text puts Cmd.parser.generate_help_text

View File

@ -7,10 +7,14 @@ module Cask
# #
# @api private # @api private
class Home < AbstractCommand class Home < AbstractCommand
extend T::Sig
sig { returns(String) }
def self.description def self.description
"Opens the homepage of the given <cask>. If no cask is given, opens the Homebrew homepage." "Opens the homepage of the given <cask>. If no cask is given, opens the Homebrew homepage."
end end
sig { void }
def run def run
if casks.none? if casks.none?
odebug "Opening project homepage" odebug "Opening project homepage"

View File

@ -9,10 +9,14 @@ module Cask
# #
# @api private # @api private
class Info < AbstractCommand class Info < AbstractCommand
extend T::Sig
sig { override.returns(T.nilable(T.any(Integer, Symbol))) }
def self.min_named def self.min_named
:cask :cask
end end
sig { returns(String) }
def self.description def self.description
"Displays information about the given <cask>." "Displays information about the given <cask>."
end end
@ -42,6 +46,7 @@ module Cask
end end
end end
sig { void }
def run def run
if args.json == "v1" if args.json == "v1"
puts JSON.generate(args.named.to_casks.map(&:to_h)) puts JSON.generate(args.named.to_casks.map(&:to_h))

View File

@ -7,10 +7,14 @@ module Cask
# #
# @api private # @api private
class Install < AbstractCommand class Install < AbstractCommand
extend T::Sig
sig { override.returns(T.nilable(T.any(Integer, Symbol))) }
def self.min_named def self.min_named
:cask :cask
end end
sig { returns(String) }
def self.description def self.description
"Installs the given <cask>." "Installs the given <cask>."
end end
@ -30,10 +34,11 @@ module Cask
send(*option) send(*option)
end end
instance_eval(&block) if block_given? instance_eval(&block) if block
end end
end end
sig { void }
def run def run
self.class.install_casks( self.class.install_casks(
*casks, *casks,

View File

@ -7,14 +7,19 @@ module Cask
# #
# @api private # @api private
class InternalHelp < AbstractInternalCommand class InternalHelp < AbstractInternalCommand
extend T::Sig
sig { override.returns(T.nilable(Integer)) }
def self.max_named def self.max_named
0 0
end end
sig { returns(String) }
def self.description def self.description
"Print help for unstable internal-use commands." "Print help for unstable internal-use commands."
end end
sig { void }
def run def run
max_command_len = Cmd.commands.map(&:length).max max_command_len = Cmd.commands.map(&:length).max
puts "Unstable Internal-use Commands:\n\n" puts "Unstable Internal-use Commands:\n\n"

View File

@ -9,6 +9,8 @@ module Cask
# #
# @api private # @api private
class InternalStanza < AbstractInternalCommand class InternalStanza < AbstractInternalCommand
extend T::Sig
# Syntax # Syntax
# #
# brew cask _stanza <stanza_name> [ --quiet ] [ --table | --yaml ] [ <cask_token> ... ] # brew cask _stanza <stanza_name> [ --quiet ] [ --table | --yaml ] [ <cask_token> ... ]
@ -24,14 +26,17 @@ module Cask
(DSL::ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key) + (DSL::ORDINARY_ARTIFACT_CLASSES.map(&:dsl_key) +
DSL::ARTIFACT_BLOCK_CLASSES.map(&:dsl_key)).freeze DSL::ARTIFACT_BLOCK_CLASSES.map(&:dsl_key)).freeze
sig { override.returns(T.nilable(T.any(Integer, Symbol))) }
def self.min_named def self.min_named
1 1
end end
sig { returns(String) }
def self.banner_args def self.banner_args
" <stanza_name> [<cask>]" " <stanza_name> [<cask>]"
end end
sig { returns(String) }
def self.description def self.description
<<~EOS <<~EOS
Extract and render a specific stanza for the given <cask>. Extract and render a specific stanza for the given <cask>.
@ -80,6 +85,7 @@ module Cask
EOS EOS
end end
sig { void }
def run def run
if ARTIFACTS.include?(stanza) if ARTIFACTS.include?(stanza)
artifact_name = stanza artifact_name = stanza

View File

@ -9,6 +9,9 @@ module Cask
# #
# @api private # @api private
class List < AbstractCommand class List < AbstractCommand
extend T::Sig
sig { returns(String) }
def self.description def self.description
"Lists installed casks or the casks provided in the arguments." "Lists installed casks or the casks provided in the arguments."
end end
@ -26,6 +29,7 @@ module Cask
end end
end end
sig { void }
def run def run
self.class.list_casks( self.class.list_casks(
*casks, *casks,

View File

@ -7,6 +7,9 @@ module Cask
# #
# @api private # @api private
class Outdated < AbstractCommand class Outdated < AbstractCommand
extend T::Sig
sig { returns(String) }
def self.description def self.description
"List the outdated installed casks." "List the outdated installed casks."
end end
@ -20,6 +23,7 @@ module Cask
end end
end end
sig { void }
def run def run
outdated_casks = casks(alternative: -> { Caskroom.casks(config: Config.from_args(args)) }).select do |cask| outdated_casks = casks(alternative: -> { Caskroom.casks(config: Config.from_args(args)) }).select do |cask|
odebug "Checking update info of Cask #{cask}" odebug "Checking update info of Cask #{cask}"

View File

@ -7,10 +7,14 @@ module Cask
# #
# @api private # @api private
class Reinstall < Install class Reinstall < Install
extend T::Sig
sig { returns(String) }
def self.description def self.description
"Reinstalls the given <cask>." "Reinstalls the given <cask>."
end end
sig { void }
def run def run
self.class.reinstall_casks( self.class.reinstall_casks(
*casks, *casks,

View File

@ -10,6 +10,9 @@ module Cask
# #
# @api private # @api private
class Style < AbstractCommand class Style < AbstractCommand
extend T::Sig
sig { returns(String) }
def self.description def self.description
"Checks style of the given <cask> using RuboCop." "Checks style of the given <cask> using RuboCop."
end end
@ -21,6 +24,7 @@ module Cask
end end
end end
sig { void }
def run def run
success = Homebrew::Style.check_style_and_print( success = Homebrew::Style.check_style_and_print(
cask_paths, cask_paths,

View File

@ -7,10 +7,14 @@ module Cask
# #
# @api private # @api private
class Uninstall < AbstractCommand class Uninstall < AbstractCommand
extend T::Sig
sig { override.returns(T.nilable(T.any(Integer, Symbol))) }
def self.min_named def self.min_named
:cask :cask
end end
sig { returns(String) }
def self.description def self.description
"Uninstalls the given <cask>." "Uninstalls the given <cask>."
end end
@ -23,6 +27,7 @@ module Cask
end end
end end
sig { void }
def run def run
self.class.uninstall_casks( self.class.uninstall_casks(
*casks, *casks,

View File

@ -10,6 +10,9 @@ module Cask
# #
# @api private # @api private
class Upgrade < AbstractCommand class Upgrade < AbstractCommand
extend T::Sig
sig { returns(String) }
def self.description def self.description
"Upgrades all outdated casks or the specified casks." "Upgrades all outdated casks or the specified casks."
end end
@ -23,6 +26,7 @@ module Cask
}], }],
].freeze ].freeze
sig { returns(Homebrew::CLI::Parser) }
def self.parser def self.parser
super do super do
switch "--force", switch "--force",
@ -36,6 +40,7 @@ module Cask
end end
end end
sig { void }
def run def run
verbose = ($stdout.tty? || args.verbose?) && !args.quiet? verbose = ($stdout.tty? || args.verbose?) && !args.quiet?
self.class.upgrade_casks( self.class.upgrade_casks(
@ -52,6 +57,20 @@ module Cask
) )
end end
sig do
params(
casks: Cask,
args: Homebrew::CLI::Args,
force: T.nilable(T::Boolean),
greedy: T.nilable(T::Boolean),
dry_run: T.nilable(T::Boolean),
skip_cask_deps: T.nilable(T::Boolean),
verbose: T.nilable(T::Boolean),
binaries: T.nilable(T::Boolean),
quarantine: T.nilable(T::Boolean),
require_sha: T.nilable(T::Boolean),
).void
end
def self.upgrade_casks( def self.upgrade_casks(
*casks, *casks,
args:, args:,
@ -81,7 +100,9 @@ module Cask
return if outdated_casks.empty? return if outdated_casks.empty?
ohai "Casks with `auto_updates` or `version :latest` will not be upgraded" if casks.empty? && !greedy if casks.empty? && !greedy
ohai "Casks with `auto_updates` or `version :latest` will not be upgraded; pass `--greedy` to upgrade them."
end
verb = dry_run ? "Would upgrade" : "Upgrading" verb = dry_run ? "Would upgrade" : "Upgrading"
oh1 "#{verb} #{outdated_casks.count} #{"outdated package".pluralize(outdated_casks.count)}:" oh1 "#{verb} #{outdated_casks.count} #{"outdated package".pluralize(outdated_casks.count)}:"

View File

@ -7,10 +7,14 @@ module Cask
# #
# @api private # @api private
class Zap < AbstractCommand class Zap < AbstractCommand
extend T::Sig
sig { override.returns(T.nilable(T.any(Integer, Symbol))) }
def self.min_named def self.min_named
:cask :cask
end end
sig { returns(String) }
def self.description def self.description
<<~EOS <<~EOS
Zaps all files associated with the given <cask>. Implicitly also performs all actions associated with `uninstall`. Zaps all files associated with the given <cask>. Implicitly also performs all actions associated with `uninstall`.
@ -26,6 +30,7 @@ module Cask
end end
end end
sig { void }
def run def run
require "cask/installer" require "cask/installer"

View File

@ -1,4 +1,4 @@
# typed: true # typed: strict
# frozen_string_literal: true # frozen_string_literal: true
module Cask module Cask
@ -6,6 +6,9 @@ module Cask
# #
# @api private # @api private
module Denylist module Denylist
extend T::Sig
sig { params(name: String).returns(T.nilable(String)) }
def self.reason(name) def self.reason(name)
case name case name
when /^adobe-(after|illustrator|indesign|photoshop|premiere)/ when /^adobe-(after|illustrator|indesign|photoshop|premiere)/

View File

@ -125,7 +125,7 @@ module Cask
def language(*args, default: false, &block) def language(*args, default: false, &block)
if args.empty? if args.empty?
language_eval language_eval
elsif block_given? elsif block
@language_blocks ||= {} @language_blocks ||= {}
@language_blocks[args] = block @language_blocks[args] = block
@ -248,7 +248,7 @@ module Cask
def caveats(*strings, &block) def caveats(*strings, &block)
@caveats ||= DSL::Caveats.new(cask) @caveats ||= DSL::Caveats.new(cask)
if block_given? if block
@caveats.eval_caveats(&block) @caveats.eval_caveats(&block)
elsif strings.any? elsif strings.any?
strings.each do |string| strings.each do |string|

View File

@ -64,7 +64,7 @@ module Cask
MacOSRequirement.new([version.to_sym], comparator: comparator) MacOSRequirement.new([version.to_sym], comparator: comparator)
elsif /^\s*(?<comparator><|>|[=<>]=)\s*(?<version>\S+)\s*$/ =~ args.first elsif /^\s*(?<comparator><|>|[=<>]=)\s*(?<version>\S+)\s*$/ =~ args.first
MacOSRequirement.new([version], comparator: comparator) MacOSRequirement.new([version], comparator: comparator)
else else # rubocop:disable Lint/DuplicateBranch
MacOSRequirement.new([args.first], comparator: "==") MacOSRequirement.new([args.first], comparator: "==")
end end
rescue MacOSVersionError => e rescue MacOSVersionError => e

View File

@ -7,6 +7,8 @@ module Cask
# #
# @api private # @api private
class Version < ::String class Version < ::String
extend T::Sig
DIVIDERS = { DIVIDERS = {
"." => :dots, "." => :dots,
"-" => :hyphens, "-" => :hyphens,
@ -62,6 +64,7 @@ module Cask
attr_reader :raw_version attr_reader :raw_version
sig { params(raw_version: T.nilable(T.any(String, Symbol))).void }
def initialize(raw_version) def initialize(raw_version)
@raw_version = raw_version @raw_version = raw_version
super(raw_version.to_s) super(raw_version.to_s)
@ -73,6 +76,7 @@ module Cask
raw_version.scan(INVALID_CHARACTERS) raw_version.scan(INVALID_CHARACTERS)
end end
sig { returns(T::Boolean) }
def unstable? def unstable?
return false if latest? return false if latest?
@ -84,6 +88,7 @@ module Cask
false false
end end
sig { returns(T::Boolean) }
def latest? def latest?
to_s == "latest" to_s == "latest"
end end
@ -134,6 +139,7 @@ module Cask
private private
sig { returns(T.self_type) }
def version def version
return self if empty? || latest? return self if empty? || latest?

View File

@ -11,12 +11,15 @@ module Cask
# #
# @api private # @api private
class MultipleCaskErrors < CaskError class MultipleCaskErrors < CaskError
extend T::Sig
def initialize(errors) def initialize(errors)
super() super()
@errors = errors @errors = errors
end end
sig { returns(String) }
def to_s def to_s
<<~EOS <<~EOS
Problems with multiple casks: Problems with multiple casks:
@ -29,12 +32,18 @@ module Cask
# #
# @api private # @api private
class AbstractCaskErrorWithToken < CaskError class AbstractCaskErrorWithToken < CaskError
attr_reader :token, :reason extend T::Sig
sig { returns(String) }
attr_reader :token
sig { returns(String) }
attr_reader :reason
def initialize(token, reason = nil) def initialize(token, reason = nil)
super() super()
@token = token @token = token.to_s
@reason = reason.to_s @reason = reason.to_s
end end
end end
@ -43,6 +52,9 @@ module Cask
# #
# @api private # @api private
class CaskNotInstalledError < AbstractCaskErrorWithToken class CaskNotInstalledError < AbstractCaskErrorWithToken
extend T::Sig
sig { returns(String) }
def to_s def to_s
"Cask '#{token}' is not installed." "Cask '#{token}' is not installed."
end end
@ -52,6 +64,8 @@ module Cask
# #
# @api private # @api private
class CaskConflictError < AbstractCaskErrorWithToken class CaskConflictError < AbstractCaskErrorWithToken
extend T::Sig
attr_reader :conflicting_cask attr_reader :conflicting_cask
def initialize(token, conflicting_cask) def initialize(token, conflicting_cask)
@ -59,6 +73,7 @@ module Cask
@conflicting_cask = conflicting_cask @conflicting_cask = conflicting_cask
end end
sig { returns(String) }
def to_s def to_s
"Cask '#{token}' conflicts with '#{conflicting_cask}'." "Cask '#{token}' conflicts with '#{conflicting_cask}'."
end end
@ -68,6 +83,9 @@ module Cask
# #
# @api private # @api private
class CaskUnavailableError < AbstractCaskErrorWithToken class CaskUnavailableError < AbstractCaskErrorWithToken
extend T::Sig
sig { returns(String) }
def to_s def to_s
"Cask '#{token}' is unavailable#{reason.empty? ? "." : ": #{reason}"}" "Cask '#{token}' is unavailable#{reason.empty? ? "." : ": #{reason}"}"
end end
@ -77,6 +95,9 @@ module Cask
# #
# @api private # @api private
class CaskUnreadableError < CaskUnavailableError class CaskUnreadableError < CaskUnavailableError
extend T::Sig
sig { returns(String) }
def to_s def to_s
"Cask '#{token}' is unreadable#{reason.empty? ? "." : ": #{reason}"}" "Cask '#{token}' is unreadable#{reason.empty? ? "." : ": #{reason}"}"
end end
@ -86,6 +107,9 @@ module Cask
# #
# @api private # @api private
class CaskAlreadyCreatedError < AbstractCaskErrorWithToken class CaskAlreadyCreatedError < AbstractCaskErrorWithToken
extend T::Sig
sig { returns(String) }
def to_s def to_s
%Q(Cask '#{token}' already exists. Run #{Formatter.identifier("brew cask edit #{token}")} to edit it.) %Q(Cask '#{token}' already exists. Run #{Formatter.identifier("brew cask edit #{token}")} to edit it.)
end end
@ -95,6 +119,9 @@ module Cask
# #
# @api private # @api private
class CaskAlreadyInstalledError < AbstractCaskErrorWithToken class CaskAlreadyInstalledError < AbstractCaskErrorWithToken
extend T::Sig
sig { returns(String) }
def to_s def to_s
<<~EOS <<~EOS
Cask '#{token}' is already installed. Cask '#{token}' is already installed.
@ -109,6 +136,9 @@ module Cask
# #
# @api private # @api private
class CaskX11DependencyError < AbstractCaskErrorWithToken class CaskX11DependencyError < AbstractCaskErrorWithToken
extend T::Sig
sig { returns(String) }
def to_s def to_s
<<~EOS <<~EOS
Cask '#{token}' requires XQuartz/X11, which can be installed using Homebrew Cask by running: Cask '#{token}' requires XQuartz/X11, which can be installed using Homebrew Cask by running:
@ -124,6 +154,9 @@ module Cask
# #
# @api private # @api private
class CaskCyclicDependencyError < AbstractCaskErrorWithToken class CaskCyclicDependencyError < AbstractCaskErrorWithToken
extend T::Sig
sig { returns(String) }
def to_s def to_s
"Cask '#{token}' includes cyclic dependencies on other Casks#{reason.empty? ? "." : ": #{reason}"}" "Cask '#{token}' includes cyclic dependencies on other Casks#{reason.empty? ? "." : ": #{reason}"}"
end end
@ -133,6 +166,9 @@ module Cask
# #
# @api private # @api private
class CaskSelfReferencingDependencyError < CaskCyclicDependencyError class CaskSelfReferencingDependencyError < CaskCyclicDependencyError
extend T::Sig
sig { returns(String) }
def to_s def to_s
"Cask '#{token}' depends on itself." "Cask '#{token}' depends on itself."
end end
@ -142,6 +178,9 @@ module Cask
# #
# @api private # @api private
class CaskUnspecifiedError < CaskError class CaskUnspecifiedError < CaskError
extend T::Sig
sig { returns(String) }
def to_s def to_s
"This command requires a Cask token." "This command requires a Cask token."
end end
@ -151,6 +190,9 @@ module Cask
# #
# @api private # @api private
class CaskInvalidError < AbstractCaskErrorWithToken class CaskInvalidError < AbstractCaskErrorWithToken
extend T::Sig
sig { returns(String) }
def to_s def to_s
"Cask '#{token}' definition is invalid#{reason.empty? ? "." : ": #{reason}"}" "Cask '#{token}' definition is invalid#{reason.empty? ? "." : ": #{reason}"}"
end end
@ -182,6 +224,9 @@ module Cask
# #
# @api private # @api private
class CaskSha256MissingError < CaskSha256Error class CaskSha256MissingError < CaskSha256Error
extend T::Sig
sig { returns(String) }
def to_s def to_s
<<~EOS <<~EOS
Cask '#{token}' requires a checksum: Cask '#{token}' requires a checksum:
@ -194,6 +239,8 @@ module Cask
# #
# @api private # @api private
class CaskSha256MismatchError < CaskSha256Error class CaskSha256MismatchError < CaskSha256Error
extend T::Sig
attr_reader :path attr_reader :path
def initialize(token, expected, actual, path) def initialize(token, expected, actual, path)
@ -201,6 +248,7 @@ module Cask
@path = path @path = path
end end
sig { returns(String) }
def to_s def to_s
<<~EOS <<~EOS
Checksum for Cask '#{token}' does not match. Checksum for Cask '#{token}' does not match.
@ -218,6 +266,9 @@ module Cask
# #
# @api private # @api private
class CaskNoShasumError < CaskSha256Error class CaskNoShasumError < CaskSha256Error
extend T::Sig
sig { returns(String) }
def to_s def to_s
<<~EOS <<~EOS
Cask '#{token}' does not have a sha256 checksum defined and was not installed. Cask '#{token}' does not have a sha256 checksum defined and was not installed.
@ -230,6 +281,8 @@ module Cask
# #
# @api private # @api private
class CaskQuarantineError < CaskError class CaskQuarantineError < CaskError
extend T::Sig
attr_reader :path, :reason attr_reader :path, :reason
def initialize(path, reason) def initialize(path, reason)
@ -239,6 +292,7 @@ module Cask
@reason = reason @reason = reason
end end
sig { returns(String) }
def to_s def to_s
s = +"Failed to quarantine #{path}." s = +"Failed to quarantine #{path}."
@ -256,6 +310,9 @@ module Cask
# #
# @api private # @api private
class CaskQuarantinePropagationError < CaskQuarantineError class CaskQuarantinePropagationError < CaskQuarantineError
extend T::Sig
sig { returns(String) }
def to_s def to_s
s = +"Failed to quarantine one or more files within #{path}." s = +"Failed to quarantine one or more files within #{path}."
@ -273,6 +330,9 @@ module Cask
# #
# @api private # @api private
class CaskQuarantineReleaseError < CaskQuarantineError class CaskQuarantineReleaseError < CaskQuarantineError
extend T::Sig
sig { returns(String) }
def to_s def to_s
s = +"Failed to release #{path} from quarantine." s = +"Failed to release #{path} from quarantine."

View File

@ -18,6 +18,8 @@ module Cask
# #
# @api private # @api private
class Installer class Installer
extend T::Sig
extend Predicable extend Predicable
# TODO: it is unwise for Cask::Staged to be a module, when we are # TODO: it is unwise for Cask::Staged to be a module, when we are
# dealing with both staged and unstaged casks here. This should # dealing with both staged and unstaged casks here. This should
@ -142,6 +144,7 @@ module Cask
Installer.new(installed_cask, binaries: binaries?, verbose: verbose?, force: true, upgrade: upgrade?).uninstall Installer.new(installed_cask, binaries: binaries?, verbose: verbose?, force: true, upgrade: upgrade?).uninstall
end end
sig { returns(String) }
def summary def summary
s = +"" s = +""
s << "#{Homebrew::EnvConfig.install_badge} " unless Homebrew::EnvConfig.no_emoji? s << "#{Homebrew::EnvConfig.install_badge} " unless Homebrew::EnvConfig.no_emoji?
@ -368,15 +371,19 @@ module Cask
force: false, force: false,
).install ).install
else else
FormulaInstaller.new(cask_or_formula, verbose: verbose?).yield_self do |fi| fi = FormulaInstaller.new(
fi.installed_as_dependency = true cask_or_formula,
fi.installed_on_request = false **{
fi.show_header = true show_header: true,
fi.prelude installed_as_dependency: true,
fi.fetch installed_on_request: false,
fi.install verbose: verbose?,
fi.finish }.compact,
end )
fi.prelude
fi.fetch
fi.install
fi.finish
end end
end end
end end

View File

@ -8,19 +8,25 @@ module Cask
# #
# @api private # @api private
class Pkg class Pkg
extend T::Sig
sig { params(regexp: String, command: T.class_of(SystemCommand)).returns(T::Array[Pkg]) }
def self.all_matching(regexp, command) def self.all_matching(regexp, command)
command.run("/usr/sbin/pkgutil", args: ["--pkgs=#{regexp}"]).stdout.split("\n").map do |package_id| command.run("/usr/sbin/pkgutil", args: ["--pkgs=#{regexp}"]).stdout.split("\n").map do |package_id|
new(package_id.chomp, command) new(package_id.chomp, command)
end end
end end
sig { returns(String) }
attr_reader :package_id attr_reader :package_id
sig { params(package_id: String, command: T.class_of(SystemCommand)).void }
def initialize(package_id, command = SystemCommand) def initialize(package_id, command = SystemCommand)
@package_id = package_id @package_id = package_id
@command = command @command = command
end end
sig { void }
def uninstall def uninstall
unless pkgutil_bom_files.empty? unless pkgutil_bom_files.empty?
odebug "Deleting pkg files" odebug "Deleting pkg files"
@ -65,23 +71,28 @@ module Cask
forget forget
end end
sig { void }
def forget def forget
odebug "Unregistering pkg receipt (aka forgetting)" odebug "Unregistering pkg receipt (aka forgetting)"
@command.run!("/usr/sbin/pkgutil", args: ["--forget", package_id], sudo: true) @command.run!("/usr/sbin/pkgutil", args: ["--forget", package_id], sudo: true)
end end
sig { returns(T::Array[Pathname]) }
def pkgutil_bom_files def pkgutil_bom_files
@pkgutil_bom_files ||= pkgutil_bom_all.select(&:file?) - pkgutil_bom_specials @pkgutil_bom_files ||= pkgutil_bom_all.select(&:file?) - pkgutil_bom_specials
end end
sig { returns(T::Array[Pathname]) }
def pkgutil_bom_specials def pkgutil_bom_specials
@pkgutil_bom_specials ||= pkgutil_bom_all.select(&method(:special?)) @pkgutil_bom_specials ||= pkgutil_bom_all.select(&method(:special?))
end end
sig { returns(T::Array[Pathname]) }
def pkgutil_bom_dirs def pkgutil_bom_dirs
@pkgutil_bom_dirs ||= pkgutil_bom_all.select(&:directory?) - pkgutil_bom_specials @pkgutil_bom_dirs ||= pkgutil_bom_all.select(&:directory?) - pkgutil_bom_specials
end end
sig { returns(T::Array[Pathname]) }
def pkgutil_bom_all def pkgutil_bom_all
@pkgutil_bom_all ||= @command.run!("/usr/sbin/pkgutil", args: ["--files", package_id]) @pkgutil_bom_all ||= @command.run!("/usr/sbin/pkgutil", args: ["--files", package_id])
.stdout .stdout
@ -90,6 +101,7 @@ module Cask
.reject(&MacOS.public_method(:undeletable?)) .reject(&MacOS.public_method(:undeletable?))
end end
sig { returns(Pathname) }
def root def root
@root ||= Pathname.new(info.fetch("volume")).join(info.fetch("install-location")) @root ||= Pathname.new(info.fetch("volume")).join(info.fetch("install-location"))
end end
@ -101,10 +113,12 @@ module Cask
private private
sig { params(path: Pathname).returns(T::Boolean) }
def special?(path) def special?(path)
path.symlink? || path.chardev? || path.blockdev? path.symlink? || path.chardev? || path.blockdev?
end end
sig { params(path: Pathname).void }
def rmdir(path) def rmdir(path)
return unless path.children.empty? return unless path.children.empty?
@ -115,7 +129,8 @@ module Cask
end end
end end
def with_full_permissions(path) sig { params(path: Pathname, _block: T.proc.void).void }
def with_full_permissions(path, &_block)
original_mode = (path.stat.mode % 01000).to_s(8) original_mode = (path.stat.mode % 01000).to_s(8)
original_flags = @command.run!("/usr/bin/stat", args: ["-f", "%Of", "--", path]).stdout.chomp original_flags = @command.run!("/usr/bin/stat", args: ["-f", "%Of", "--", path]).stdout.chomp
@ -128,10 +143,12 @@ module Cask
end end
end end
sig { params(paths: T::Array[Pathname]).returns(T::Array[Pathname]) }
def deepest_path_first(paths) def deepest_path_first(paths)
paths.sort_by { |path| -path.to_s.split(File::SEPARATOR).count } paths.sort_by { |path| -path.to_s.split(File::SEPARATOR).count }
end end
sig { params(dir: Pathname).void }
def clean_ds_store(dir) def clean_ds_store(dir)
return unless (ds_store = dir.join(".DS_Store")).exist? return unless (ds_store = dir.join(".DS_Store")).exist?
@ -140,12 +157,14 @@ module Cask
# Some packages leave broken symlinks around; we clean them out before # Some packages leave broken symlinks around; we clean them out before
# attempting to `rmdir` to prevent extra cruft from accumulating. # attempting to `rmdir` to prevent extra cruft from accumulating.
sig { params(dir: Pathname).void }
def clean_broken_symlinks(dir) def clean_broken_symlinks(dir)
dir.children.select(&method(:broken_symlink?)).each do |path| dir.children.select(&method(:broken_symlink?)).each do |path|
@command.run!("/bin/rm", args: ["--", path], sudo: true) @command.run!("/bin/rm", args: ["--", path], sudo: true)
end end
end end
sig { params(path: Pathname).returns(T::Boolean) }
def broken_symlink?(path) def broken_symlink?(path)
path.symlink? && !path.exist? path.symlink? && !path.exist?
end end

View File

@ -9,6 +9,8 @@ module Cask
# #
# @api private # @api private
module Quarantine module Quarantine
extend T::Sig
module_function module_function
QUARANTINE_ATTRIBUTE = "com.apple.quarantine" QUARANTINE_ATTRIBUTE = "com.apple.quarantine"
@ -25,6 +27,7 @@ module Cask
end end
private :xattr private :xattr
sig { returns(Symbol) }
def check_quarantine_support def check_quarantine_support
odebug "Checking quarantine support" odebug "Checking quarantine support"

View File

@ -1,4 +1,4 @@
# typed: false # typed: true
# frozen_string_literal: true # frozen_string_literal: true
require "utils/user" require "utils/user"
@ -8,25 +8,35 @@ module Cask
# #
# @api private # @api private
module Staged module Staged
extend T::Sig
# FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed.
# rubocop:disable Style/MutableConstant
Paths = T.type_alias { T.any(String, Pathname, T::Array[T.any(String, Pathname)]) }
# rubocop:enable Style/MutableConstant
sig { params(paths: Paths, permissions_str: String).void }
def set_permissions(paths, permissions_str) def set_permissions(paths, permissions_str)
full_paths = remove_nonexistent(paths) full_paths = remove_nonexistent(paths)
return if full_paths.empty? return if full_paths.empty?
@command.run!("/bin/chmod", args: ["-R", "--", permissions_str] + full_paths, @command.run!("/bin/chmod", args: ["-R", "--", permissions_str, *full_paths],
sudo: false) sudo: false)
end end
def set_ownership(paths, user: User.current, group: "staff") sig { params(paths: Paths, user: T.any(String, User), group: String).void }
def set_ownership(paths, user: T.must(User.current), group: "staff")
full_paths = remove_nonexistent(paths) full_paths = remove_nonexistent(paths)
return if full_paths.empty? return if full_paths.empty?
ohai "Changing ownership of paths required by #{@cask}; your password may be necessary" ohai "Changing ownership of paths required by #{@cask}; your password may be necessary"
@command.run!("/usr/sbin/chown", args: ["-R", "--", "#{user}:#{group}"] + full_paths, @command.run!("/usr/sbin/chown", args: ["-R", "--", "#{user}:#{group}", *full_paths],
sudo: true) sudo: true)
end end
private private
sig { params(paths: Paths).returns(T::Array[Pathname]) }
def remove_nonexistent(paths) def remove_nonexistent(paths)
Array(paths).map { |p| Pathname(p).expand_path }.select(&:exist?) Array(paths).map { |p| Pathname(p).expand_path }.select(&:exist?)
end end

View File

@ -0,0 +1,7 @@
# typed: strict
module Cask
module Staged
include Kernel
end
end

View File

@ -1,4 +1,4 @@
# typed: false # typed: true
# frozen_string_literal: true # frozen_string_literal: true
require "tsort" require "tsort"
@ -8,7 +8,11 @@ module Cask
class TopologicalHash < Hash class TopologicalHash < Hash
include TSort include TSort
alias tsort_each_node each_key private
def tsort_each_node(&block)
each_key(&block)
end
def tsort_each_child(node, &block) def tsort_each_child(node, &block)
fetch(node).each(&block) fetch(node).each(&block)

View File

@ -13,6 +13,8 @@ module Cask
# #
# @api private # @api private
module Utils module Utils
extend T::Sig
def self.gain_permissions_remove(path, command: SystemCommand) def self.gain_permissions_remove(path, command: SystemCommand)
if path.respond_to?(:rmtree) && path.exist? if path.respond_to?(:rmtree) && path.exist?
gain_permissions(path, ["-R"], command) do |p| gain_permissions(path, ["-R"], command) do |p|
@ -72,10 +74,12 @@ module Cask
end end
end end
sig { params(path: Pathname).returns(T::Boolean) }
def self.path_occupied?(path) def self.path_occupied?(path)
File.exist?(path) || File.symlink?(path) path.exist? || path.symlink?
end end
sig { returns(String) }
def self.error_message_with_suggestions def self.error_message_with_suggestions
<<~EOS <<~EOS
Follow the instructions here: Follow the instructions here:

View File

@ -76,6 +76,12 @@ class Cleaner
path.text_executable? || path.executable? path.text_executable? || path.executable?
end end
# Both these files are completely unnecessary to package and cause
# pointless conflicts with other formulae. They are removed by Debian,
# Arch & MacPorts amongst other packagers as well. The files are
# created as part of installing any Perl module.
PERL_BASENAMES = Set.new(%w[perllocal.pod .packlist]).freeze
# Clean a top-level (bin, sbin, lib) directory, recursively, by fixing file # Clean a top-level (bin, sbin, lib) directory, recursively, by fixing file
# permissions and removing .la files, unless the files (or parent # permissions and removing .la files, unless the files (or parent
# directories) are protected by skip_clean. # directories) are protected by skip_clean.
@ -93,18 +99,10 @@ class Cleaner
next if path.directory? next if path.directory?
if path.extname == ".la" if path.extname == ".la" || PERL_BASENAMES.include?(path.basename.to_s)
path.unlink path.unlink
elsif path.symlink? elsif path.symlink?
# Skip it. # Skip it.
elsif path.basename.to_s == "perllocal.pod"
# Both this file & the .packlist one below are completely unnecessary
# to package & causes pointless conflict with other formulae. They are
# removed by Debian, Arch & MacPorts amongst other packagers as well.
# The files are created as part of installing any Perl module.
path.unlink
elsif path.basename.to_s == ".packlist" # Hidden file, not file extension!
path.unlink
else else
# Set permissions for executables and non-executables # Set permissions for executables and non-executables
perms = if executable_path?(path) perms = if executable_path?(path)

View File

@ -168,6 +168,7 @@ module Homebrew
return false if Homebrew::EnvConfig.no_install_cleanup? return false if Homebrew::EnvConfig.no_install_cleanup?
unless PERIODIC_CLEAN_FILE.exist? unless PERIODIC_CLEAN_FILE.exist?
HOMEBREW_CACHE.mkpath
FileUtils.touch PERIODIC_CLEAN_FILE FileUtils.touch PERIODIC_CLEAN_FILE
return false return false
end end

View File

@ -7,11 +7,14 @@ require "ostruct"
module Homebrew module Homebrew
module CLI module CLI
class Args < OpenStruct class Args < OpenStruct
extend T::Sig
attr_reader :options_only, :flags_only attr_reader :options_only, :flags_only
# undefine tap to allow --tap argument # undefine tap to allow --tap argument
undef tap undef tap
sig { void }
def initialize def initialize
super() super()
@ -21,7 +24,7 @@ module Homebrew
# 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] = NamedArgs.new(parent: self) self[:named] = NamedArgs.new(parent: self)
self[:remaining] = [] self[:remaining] = []
end end
@ -30,7 +33,7 @@ module Homebrew
end end
def freeze_named_args!(named_args) def freeze_named_args!(named_args)
self[:named_args] = NamedArgs.new( self[:named] = NamedArgs.new(
*named_args.freeze, *named_args.freeze,
override_spec: spec(nil), override_spec: spec(nil),
force_bottle: force_bottle?, force_bottle: force_bottle?,
@ -50,8 +53,9 @@ module Homebrew
@flags_only = cli_args.select { |a| a.start_with?("--") }.freeze @flags_only = cli_args.select { |a| a.start_with?("--") }.freeze
end end
sig { returns(NamedArgs) }
def named def named
named_args self[:named]
end end
def no_named? def no_named?
@ -131,6 +135,7 @@ module Homebrew
flag_with_value.delete_prefix(arg_prefix) flag_with_value.delete_prefix(arg_prefix)
end end
sig { returns(Context::ContextStruct) }
def context def context
Context::ContextStruct.new(debug: debug?, quiet: quiet?, verbose: verbose?) Context::ContextStruct.new(debug: debug?, quiet: quiet?, verbose: verbose?)
end end

View File

@ -3,27 +3,62 @@
module Homebrew module Homebrew
module CLI module CLI
class Args < OpenStruct class Args < OpenStruct
sig { returns(T.nilable(T::Boolean)) }
def devel?; end def devel?; end
sig { returns(T.nilable(T::Boolean)) }
def HEAD?; end def HEAD?; end
sig { returns(T.nilable(T::Boolean)) }
def include_test?; end def include_test?; end
sig { returns(T.nilable(T::Boolean)) }
def build_bottle?; end def build_bottle?; end
sig { returns(T.nilable(T::Boolean)) }
def build_universal?; end def build_universal?; end
sig { returns(T.nilable(T::Boolean)) }
def build_from_source?; end def build_from_source?; end
def named_args; end sig { returns(T.nilable(T::Boolean)) }
def force_bottle?; end def force_bottle?; end
sig { returns(T.nilable(T::Boolean)) }
def debug?; end def debug?; end
sig { returns(T.nilable(T::Boolean)) }
def quiet?; end def quiet?; end
sig { returns(T.nilable(T::Boolean)) }
def verbose?; end def verbose?; end
sig { returns(T.nilable(T::Boolean)) }
def fetch_HEAD?; end
sig { returns(T.nilable(T::Boolean)) }
def cask?; end
sig { returns(T.nilable(T::Boolean)) }
def dry_run?; end
sig { returns(T.nilable(T::Boolean)) }
def skip_cask_deps?; end
sig { returns(T.nilable(T::Boolean)) }
def greedy?; end
sig { returns(T.nilable(T::Boolean)) }
def force?; end
sig { returns(T.nilable(T::Boolean)) }
def ignore_pinned?; end
sig { returns(T.nilable(T::Boolean)) }
def display_times?; end
sig { returns(T.nilable(T::Boolean)) }
def formula?; end
end end
end end
end end

View File

@ -6,6 +6,7 @@ require "delegate"
require "cask/cask_loader" require "cask/cask_loader"
require "cli/args" require "cli/args"
require "formulary" require "formulary"
require "keg"
require "missing_formula" require "missing_formula"
module Homebrew module Homebrew
@ -13,7 +14,9 @@ module Homebrew
# Helper class for loading formulae/casks from named arguments. # Helper class for loading formulae/casks from named arguments.
# #
# @api private # @api private
class NamedArgs < SimpleDelegator class NamedArgs < Array
extend T::Sig
def initialize(*args, parent: Args.new, override_spec: nil, force_bottle: false, flags: []) def initialize(*args, parent: Args.new, override_spec: nil, force_bottle: false, flags: [])
@args = args @args = args
@override_spec = override_spec @override_spec = override_spec
@ -39,9 +42,9 @@ module Homebrew
end end
end end
def to_formulae_to_casks(method: nil, only: nil) def to_formulae_to_casks(only: nil, method: nil)
@to_formulae_to_casks ||= {} @to_formulae_to_casks ||= {}
@to_formulae_to_casks[[method, only]] = to_formulae_and_casks(method: method, only: only) @to_formulae_to_casks[[method, only]] = to_formulae_and_casks(only: only, method: method)
.partition { |o| o.is_a?(Formula) } .partition { |o| o.is_a?(Formula) }
.map(&:freeze).freeze .map(&:freeze).freeze
end end
@ -62,14 +65,16 @@ module Homebrew
when nil, :factory when nil, :factory
Formulary.factory(name, *spec, force_bottle: @force_bottle, flags: @flags) Formulary.factory(name, *spec, force_bottle: @force_bottle, flags: @flags)
when :resolve when :resolve
Formulary.resolve(name, spec: spec, force_bottle: @force_bottle, flags: @flags) resolve_formula(name)
when :keg
resolve_keg(name)
else else
raise raise
end end
warn_if_cask_conflicts(name, "formula") unless only == :formula warn_if_cask_conflicts(name, "formula") unless only == :formula
return formula return formula
rescue FormulaUnavailableError => e rescue NoSuchKegError, FormulaUnavailableError => e
raise e if only == :formula raise e if only == :formula
end end
end end
@ -97,24 +102,22 @@ module Homebrew
end end
def to_resolved_formulae_to_casks(only: nil) def to_resolved_formulae_to_casks(only: nil)
to_formulae_to_casks(method: :resolve, only: only) to_formulae_to_casks(only: only, method: :resolve)
end end
# Convert named arguments to {Tap}, {Formula} or {Cask} objects. # Convert named arguments to {Formula} or {Cask} objects.
# If both a formula and cask exist with the same name, returns the # If both a formula and cask exist with the same name, returns the
# formula and prints a warning unless `only` is specified. # formula and prints a warning unless `only` is specified.
def to_objects(only: nil, method: nil) def to_objects(only: nil, method: nil)
@to_objects ||= {} @to_objects ||= {}
@to_objects[only] ||= downcased_unique_named.flat_map do |name| @to_objects[only] ||= downcased_unique_named.map do |name|
next Tap.fetch(name) if only == :tap || (only.nil? && name.count("/") == 1 && !name.start_with?("./", "/"))
load_formula_or_cask(name, only: only, method: method) load_formula_or_cask(name, only: only, method: method)
end.uniq.freeze end.uniq.freeze
end end
private :to_objects private :to_objects
def to_formulae_paths def to_formulae_paths
to_paths(only: :formulae) to_paths(only: :formula)
end end
# Keep existing paths and try to convert others to tap, formula or cask paths. # Keep existing paths and try to convert others to tap, formula or cask paths.
@ -125,11 +128,11 @@ module Homebrew
@to_paths[only] ||= downcased_unique_named.flat_map do |name| @to_paths[only] ||= downcased_unique_named.flat_map do |name|
if File.exist?(name) if File.exist?(name)
Pathname(name) Pathname(name)
elsif name.count("/") == 1 elsif name.count("/") == 1 && !name.start_with?("./", "/")
Tap.fetch(name).path Tap.fetch(name).path
else else
next Formulary.path(name) if only == :formulae next Formulary.path(name) if only == :formula
next Cask::CaskLoader.path(name) if only == :casks next Cask::CaskLoader.path(name) if only == :cask
formula_path = Formulary.path(name) formula_path = Formulary.path(name)
cask_path = Cask::CaskLoader.path(name) cask_path = Cask::CaskLoader.path(name)
@ -144,44 +147,33 @@ module Homebrew
end.uniq.freeze end.uniq.freeze
end end
sig { returns(T::Array[Keg]) }
def to_kegs def to_kegs
@to_kegs ||= downcased_unique_named.map do |name| @to_kegs ||= begin
resolve_keg name to_formulae_and_casks(only: :formula, method: :keg).freeze
rescue NoSuchKegError => e rescue NoSuchKegError => e
if (reason = Homebrew::MissingFormula.suggest_command(name, "uninstall")) if (reason = Homebrew::MissingFormula.suggest_command(e.name, "uninstall"))
$stderr.puts reason $stderr.puts reason
end end
raise e raise e
end.freeze
end
def to_kegs_to_casks
@to_kegs_to_casks ||= begin
kegs = []
casks = []
downcased_unique_named.each do |name|
kegs << resolve_keg(name)
warn_if_cask_conflicts(name, "keg")
rescue NoSuchKegError, FormulaUnavailableError
begin
casks << Cask::CaskLoader.load(name, config: Cask::Config.from_args(@parent))
rescue Cask::CaskUnavailableError
raise "No installed keg or cask with the name \"#{name}\""
end
end
[kegs.freeze, casks.freeze].freeze
end end
end end
sig { params(only: T.nilable(Symbol)).returns([T::Array[Keg], T::Array[Cask::Cask]]) }
def to_kegs_to_casks(only: nil)
@to_kegs_to_casks ||= to_formulae_and_casks(only: only, method: :keg)
.partition { |o| o.is_a?(Keg) }
.map(&:freeze).freeze
end
sig { returns(T::Array[String]) }
def homebrew_tap_cask_names def homebrew_tap_cask_names
downcased_unique_named.grep(HOMEBREW_CASK_TAP_CASK_REGEX) downcased_unique_named.grep(HOMEBREW_CASK_TAP_CASK_REGEX)
end end
private private
sig { returns(T::Array[String]) }
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
map do |arg| map do |arg|

View File

@ -14,6 +14,8 @@ OPTION_DESC_WIDTH = 43
module Homebrew module Homebrew
module CLI module CLI
class Parser class Parser
extend T::Sig
attr_reader :processed_options, :hide_from_man_page attr_reader :processed_options, :hide_from_man_page
def self.from_cmd_path(cmd_path) def self.from_cmd_path(cmd_path)
@ -31,78 +33,82 @@ module Homebrew
def self.global_cask_options def self.global_cask_options
[ [
[:flag, "--appdir=", { [:flag, "--appdir=", {
description: "Target location for Applications. " \ description: "Target location for Applications " \
"Default: `#{Cask::Config::DEFAULT_DIRS[:appdir]}`", "(default: `#{Cask::Config::DEFAULT_DIRS[:appdir]}`).",
}], }],
[:flag, "--colorpickerdir=", { [:flag, "--colorpickerdir=", {
description: "Target location for Color Pickers. " \ description: "Target location for Color Pickers " \
"Default: `#{Cask::Config::DEFAULT_DIRS[:colorpickerdir]}`", "(default: `#{Cask::Config::DEFAULT_DIRS[:colorpickerdir]}`).",
}], }],
[:flag, "--prefpanedir=", { [:flag, "--prefpanedir=", {
description: "Target location for Preference Panes. " \ description: "Target location for Preference Panes " \
"Default: `#{Cask::Config::DEFAULT_DIRS[:prefpanedir]}`", "(default: `#{Cask::Config::DEFAULT_DIRS[:prefpanedir]}`).",
}], }],
[:flag, "--qlplugindir=", { [:flag, "--qlplugindir=", {
description: "Target location for QuickLook Plugins. " \ description: "Target location for QuickLook Plugins " \
"Default: `#{Cask::Config::DEFAULT_DIRS[:qlplugindir]}`", "(default: `#{Cask::Config::DEFAULT_DIRS[:qlplugindir]}`).",
}], }],
[:flag, "--mdimporterdir=", { [:flag, "--mdimporterdir=", {
description: "Target location for Spotlight Plugins. " \ description: "Target location for Spotlight Plugins " \
"Default: `#{Cask::Config::DEFAULT_DIRS[:mdimporterdir]}`", "(default: `#{Cask::Config::DEFAULT_DIRS[:mdimporterdir]}`).",
}], }],
[:flag, "--dictionarydir=", { [:flag, "--dictionarydir=", {
description: "Target location for Dictionaries. " \ description: "Target location for Dictionaries " \
"Default: `#{Cask::Config::DEFAULT_DIRS[:dictionarydir]}`", "(default: `#{Cask::Config::DEFAULT_DIRS[:dictionarydir]}`).",
}], }],
[:flag, "--fontdir=", { [:flag, "--fontdir=", {
description: "Target location for Fonts. " \ description: "Target location for Fonts " \
"Default: `#{Cask::Config::DEFAULT_DIRS[:fontdir]}`", "(default: `#{Cask::Config::DEFAULT_DIRS[:fontdir]}`).",
}], }],
[:flag, "--servicedir=", { [:flag, "--servicedir=", {
description: "Target location for Services. " \ description: "Target location for Services " \
"Default: `#{Cask::Config::DEFAULT_DIRS[:servicedir]}`", "(default: `#{Cask::Config::DEFAULT_DIRS[:servicedir]}`).",
}], }],
[:flag, "--input_methoddir=", { [:flag, "--input_methoddir=", {
description: "Target location for Input Methods. " \ description: "Target location for Input Methods " \
"Default: `#{Cask::Config::DEFAULT_DIRS[:input_methoddir]}`", "(default: `#{Cask::Config::DEFAULT_DIRS[:input_methoddir]}`).",
}], }],
[:flag, "--internet_plugindir=", { [:flag, "--internet_plugindir=", {
description: "Target location for Internet Plugins. " \ description: "Target location for Internet Plugins " \
"Default: `#{Cask::Config::DEFAULT_DIRS[:internet_plugindir]}`", "(default: `#{Cask::Config::DEFAULT_DIRS[:internet_plugindir]}`).",
}], }],
[:flag, "--audio_unit_plugindir=", { [:flag, "--audio_unit_plugindir=", {
description: "Target location for Audio Unit Plugins. " \ description: "Target location for Audio Unit Plugins " \
"Default: `#{Cask::Config::DEFAULT_DIRS[:audio_unit_plugindir]}`", "(default: `#{Cask::Config::DEFAULT_DIRS[:audio_unit_plugindir]}`).",
}], }],
[:flag, "--vst_plugindir=", { [:flag, "--vst_plugindir=", {
description: "Target location for VST Plugins. " \ description: "Target location for VST Plugins " \
"Default: `#{Cask::Config::DEFAULT_DIRS[:vst_plugindir]}`", "(default: `#{Cask::Config::DEFAULT_DIRS[:vst_plugindir]}`).",
}], }],
[:flag, "--vst3_plugindir=", { [:flag, "--vst3_plugindir=", {
description: "Target location for VST3 Plugins. " \ description: "Target location for VST3 Plugins " \
"Default: `#{Cask::Config::DEFAULT_DIRS[:vst3_plugindir]}`", "(default: `#{Cask::Config::DEFAULT_DIRS[:vst3_plugindir]}`).",
}], }],
[:flag, "--screen_saverdir=", { [:flag, "--screen_saverdir=", {
description: "Target location for Screen Savers. " \ description: "Target location for Screen Savers " \
"Default: `#{Cask::Config::DEFAULT_DIRS[:screen_saverdir]}`", "(default: `#{Cask::Config::DEFAULT_DIRS[:screen_saverdir]}`).",
}], }],
[:comma_array, "--language", { [:comma_array, "--language", {
description: "Set language of the Cask to install. The first matching " \ description: "Comma-separated list of language codes to prefer for cask installation. " \
"language is used, otherwise the default language on the Cask. " \ "The first matching language is used, otherwise it reverts to the cask's " \
"The default value is the `language of your system`", "default language. The default value is the language of your system.",
}], }],
] ]
end end
sig { returns(T::Array[[String, String, String]]) }
def self.global_options def self.global_options
[ [
["-d", "--debug", "Display any debugging information."], ["-d", "--debug", "Display any debugging information."],
["-q", "--quiet", "Suppress any warnings."], ["-q", "--quiet", "Make some output more quiet."],
["-v", "--verbose", "Make some output more verbose."], ["-v", "--verbose", "Make some output more verbose."],
["-h", "--help", "Show this message."], ["-h", "--help", "Show this message."],
] ]
end end
# FIXME: Block should be `T.nilable(T.proc.bind(Parser).void)`.
# See https://github.com/sorbet/sorbet/issues/498.
sig { params(block: T.proc.bind(Parser).void).void.checked(:never) }
def initialize(&block) def initialize(&block)
@parser = OptionParser.new @parser = OptionParser.new
@ -130,7 +136,7 @@ module Homebrew
switch short, long, description: desc, env: option_to_name(long), method: :on_tail switch short, long, description: desc, env: option_to_name(long), method: :on_tail
end end
instance_eval(&block) if block_given? instance_eval(&block) if block
end end
def switch(*names, description: nil, env: nil, required_for: nil, depends_on: nil, method: :on) def switch(*names, description: nil, env: nil, required_for: nil, depends_on: nil, method: :on)
@ -170,7 +176,7 @@ module Homebrew
def usage_banner_text def usage_banner_text
@parser.banner @parser.banner
.gsub(/^ - (`[^`]+`)\s+/, "\n- \\1 \n ") # Format `cask` subcommands as MarkDown list. .gsub(/^ - (`[^`]+`)\s+/, "\n- \\1:\n <br>") # Format `cask` subcommands as Markdown list.
end end
def comma_array(name, description: nil) def comma_array(name, description: nil)
@ -331,6 +337,7 @@ module Homebrew
end end
end end
sig { void }
def formula_options def formula_options
@formula_options = true @formula_options = true
end end
@ -367,6 +374,7 @@ module Homebrew
end end
end end
sig { void }
def hide_from_man_page! def hide_from_man_page!
@hide_from_man_page = true @hide_from_man_page = true
end end
@ -454,20 +462,24 @@ module Homebrew
end end
def check_named_args(args) def check_named_args(args)
min_exception = case @min_named_type exception = if @min_named_args && args.size < @min_named_args
when :cask case @min_named_type
Cask::CaskUnspecifiedError when :cask
when :formula Cask::CaskUnspecifiedError
FormulaUnspecifiedError when :formula
when :formula_or_cask FormulaUnspecifiedError
FormulaOrCaskUnspecifiedError when :formula_or_cask
when :keg FormulaOrCaskUnspecifiedError
KegUnspecifiedError when :keg
else KegUnspecifiedError
MinNamedArgumentsError.new(@min_named_args) else
MinNamedArgumentsError.new(@min_named_args)
end
elsif @max_named_args && args.size > @max_named_args
MaxNamedArgumentsError.new(@max_named_args)
end end
raise min_exception if @min_named_args && args.size < @min_named_args
raise MaxNamedArgumentsError, @max_named_args if @max_named_args && args.size > @max_named_args raise exception if exception
end end
def process_option(*args) def process_option(*args)
@ -535,6 +547,9 @@ module Homebrew
end end
class MaxNamedArgumentsError < UsageError class MaxNamedArgumentsError < UsageError
extend T::Sig
sig { params(maximum: Integer).void }
def initialize(maximum) def initialize(maximum)
super case maximum super case maximum
when 0 when 0
@ -546,6 +561,9 @@ module Homebrew
end end
class MinNamedArgumentsError < UsageError class MinNamedArgumentsError < UsageError
extend T::Sig
sig { params(minimum: Integer).void }
def initialize(minimum) def initialize(minimum)
super "This command requires at least #{minimum} named #{"argument".pluralize(minimum)}." super "This command requires at least #{minimum} named #{"argument".pluralize(minimum)}."
end end

View File

@ -6,14 +6,17 @@ require "cli/parser"
require "cask/download" require "cask/download"
module Homebrew module Homebrew
extend T::Sig
extend Fetch extend Fetch
module_function module_function
sig { returns(CLI::Parser) }
def __cache_args def __cache_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
`--cache` [<options>] [<formula|cask>] `--cache` [<options>] [<formula>|<cask>]
Display Homebrew's download cache. See also `HOMEBREW_CACHE`. Display Homebrew's download cache. See also `HOMEBREW_CACHE`.

View File

@ -1,9 +1,12 @@
# typed: false # typed: strict
# frozen_string_literal: true # frozen_string_literal: true
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def __caskroom_args def __caskroom_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
@ -17,6 +20,7 @@ module Homebrew
end end
end end
sig { void }
def __caskroom def __caskroom
args = __caskroom_args.parse args = __caskroom_args.parse

View File

@ -7,8 +7,11 @@ require "utils/shell"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def __env_args def __env_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
@ -44,11 +47,10 @@ module Homebrew
Utils::Shell.from_path(args.shell) Utils::Shell.from_path(args.shell)
end end
env_keys = BuildEnvironment.keys(ENV)
if shell.nil? if shell.nil?
BuildEnvironment.dump ENV BuildEnvironment.dump ENV
else else
env_keys.each do |key| BuildEnvironment.keys(ENV).each do |key|
puts Utils::Shell.export_value(key, ENV[key], shell) puts Utils::Shell.export_value(key, ENV[key], shell)
end end
end end

View File

@ -4,8 +4,11 @@
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def __prefix_args def __prefix_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -4,8 +4,11 @@
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def __repository_args def __repository_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -4,8 +4,11 @@
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def __version_args def __version_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
@ -14,6 +17,7 @@ module Homebrew
Print the version numbers of Homebrew, Homebrew/homebrew-core and Homebrew/homebrew-cask Print the version numbers of Homebrew, Homebrew/homebrew-core and Homebrew/homebrew-cask
(if tapped) to standard output. (if tapped) to standard output.
EOS EOS
max_named 0 max_named 0
end end
end end

View File

@ -4,8 +4,11 @@
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def analytics_args def analytics_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
@ -17,12 +20,13 @@ module Homebrew
`brew analytics` [`state`]: `brew analytics` [`state`]:
Display the current state of Homebrew's analytics. Display the current state of Homebrew's analytics.
`brew analytics` [`on`|`off`]: `brew analytics` (`on`|`off`):
Turn Homebrew's analytics on or off respectively. Turn Homebrew's analytics on or off respectively.
`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
max_named 1 max_named 1
end end
end end

View File

@ -17,7 +17,8 @@ module Homebrew
EOS EOS
switch "-n", "--dry-run", switch "-n", "--dry-run",
description: "List what would be uninstalled, but do not actually uninstall anything." description: "List what would be uninstalled, but do not actually uninstall anything."
named 0
max_named 0
end end
end end

View File

@ -5,8 +5,11 @@ require "cleanup"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def cleanup_args def cleanup_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
days = Homebrew::EnvConfig::ENVS[:HOMEBREW_CLEANUP_MAX_AGE_DAYS][:default] days = Homebrew::EnvConfig::ENVS[:HOMEBREW_CLEANUP_MAX_AGE_DAYS][:default]

View File

@ -4,8 +4,11 @@
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def commands_args def commands_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -5,8 +5,11 @@ require "system_config"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def config_args def config_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -8,10 +8,13 @@ require "cask/caskroom"
require "dependencies_helpers" require "dependencies_helpers"
module Homebrew module Homebrew
extend T::Sig
extend DependenciesHelpers extend DependenciesHelpers
module_function module_function
sig { returns(CLI::Parser) }
def deps_args def deps_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -7,10 +7,13 @@ require "description_cache_store"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
extend Search extend Search
sig { returns(CLI::Parser) }
def desc_args def desc_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -6,8 +6,11 @@ require "cli/parser"
require "cask/caskroom" require "cask/caskroom"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def doctor_args def doctor_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -6,10 +6,13 @@ require "fetch"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
extend Fetch extend Fetch
module_function module_function
sig { returns(CLI::Parser) }
def fetch_args def fetch_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -9,10 +9,13 @@ require "socket"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
extend Install extend Install
module_function module_function
sig { returns(CLI::Parser) }
def gist_logs_args def gist_logs_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -4,8 +4,11 @@
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def home_args def home_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -13,12 +13,15 @@ require "utils/spdx"
require "deprecate_disable" require "deprecate_disable"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
VALID_DAYS = %w[30 90 365].freeze VALID_DAYS = %w[30 90 365].freeze
VALID_FORMULA_CATEGORIES = %w[install install-on-request build-error].freeze VALID_FORMULA_CATEGORIES = %w[install install-on-request build-error].freeze
VALID_CATEGORIES = (VALID_FORMULA_CATEGORIES + %w[cask-install os-version]).freeze VALID_CATEGORIES = (VALID_FORMULA_CATEGORIES + %w[cask-install os-version]).freeze
sig { returns(CLI::Parser) }
def info_args def info_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
@ -87,20 +90,23 @@ module Homebrew
raise FormulaOrCaskUnspecifiedError if args.no_named? raise FormulaOrCaskUnspecifiedError if args.no_named?
exec_browser(*args.named.to_formulae_and_casks.map { |f| github_info(f) }) exec_browser(*args.named.to_formulae_and_casks.map { |f| github_info(f) })
elsif args.no_named?
print_statistics
else else
print_info(args: args) print_info(args: args)
end end
end end
def print_statistics
return unless HOMEBREW_CELLAR.exist?
count = Formula.racks.length
puts "#{count} #{"keg".pluralize(count)}, #{HOMEBREW_CELLAR.dup.abv}"
end
def print_analytics(args:) def print_analytics(args:)
if args.no_named? if args.no_named?
if args.analytics? Utils::Analytics.output(args: args)
Utils::Analytics.output(args: args)
elsif HOMEBREW_CELLAR.exist?
count = Formula.racks.length
puts "#{count} #{"keg".pluralize(count)}, #{HOMEBREW_CELLAR.dup.abv}"
end
return return
end end

View File

@ -14,10 +14,13 @@ require "cli/parser"
require "upgrade" require "upgrade"
module Homebrew module Homebrew
extend T::Sig
extend Search extend Search
module_function module_function
sig { returns(CLI::Parser) }
def install_args def install_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
@ -82,7 +85,6 @@ module Homebrew
}], }],
[:switch, "--keep-tmp", { [:switch, "--keep-tmp", {
description: "Retain the temporary files created during installation.", description: "Retain the temporary files created during installation.",
}], }],
[:switch, "--build-bottle", { [:switch, "--build-bottle", {
description: "Prepare the formula for eventual bottling during installation, skipping any " \ description: "Prepare the formula for eventual bottling during installation, skipping any " \
@ -122,7 +124,6 @@ module Homebrew
conflicts "--ignore-dependencies", "--only-dependencies" conflicts "--ignore-dependencies", "--only-dependencies"
conflicts "--build-from-source", "--build-bottle", "--force-bottle" conflicts "--build-from-source", "--build-bottle", "--force-bottle"
min_named :formula_or_cask min_named :formula_or_cask
end end
end end
@ -203,7 +204,7 @@ module Homebrew
EOS EOS
elsif args.only_dependencies? elsif args.only_dependencies?
installed_formulae << f installed_formulae << f
else elsif !args.quiet?
opoo <<~EOS opoo <<~EOS
#{f.full_name} #{f.pkg_version} is already installed and up-to-date #{f.full_name} #{f.pkg_version} is already installed and up-to-date
To reinstall #{f.pkg_version}, run `brew reinstall #{f.name}` To reinstall #{f.pkg_version}, run `brew reinstall #{f.name}`
@ -223,11 +224,14 @@ module Homebrew
msg = "#{f.full_name} #{installed_version} is already installed" msg = "#{f.full_name} #{installed_version} is already installed"
linked_not_equals_installed = f.linked_version != installed_version linked_not_equals_installed = f.linked_version != installed_version
if f.linked? && linked_not_equals_installed if f.linked? && linked_not_equals_installed
msg = <<~EOS msg = if args.quiet?
#{msg} nil
The currently linked version is #{f.linked_version} else
You can use `brew switch #{f} #{installed_version}` to link this version. <<~EOS
EOS #{msg}
The currently linked version is #{f.linked_version}
EOS
end
elsif !f.linked? || f.keg_only? elsif !f.linked? || f.keg_only?
msg = <<~EOS msg = <<~EOS
#{msg}, it's just not linked #{msg}, it's just not linked
@ -237,10 +241,14 @@ module Homebrew
msg = nil msg = nil
installed_formulae << f installed_formulae << f
else else
msg = <<~EOS msg = if args.quiet?
#{msg} and up-to-date nil
To reinstall #{f.pkg_version}, run `brew reinstall #{f.name}` else
EOS <<~EOS
#{msg} and up-to-date
To reinstall #{f.pkg_version}, run `brew reinstall #{f.name}`
EOS
end
end end
opoo msg if msg opoo msg if msg
elsif !f.any_version_installed? && old_formula = f.old_installed_formulae.first elsif !f.any_version_installed? && old_formula = f.old_installed_formulae.first
@ -250,8 +258,10 @@ module Homebrew
#{msg}, it's just not linked. #{msg}, it's just not linked.
You can use `brew link #{old_formula.full_name}` to link this version. You can use `brew link #{old_formula.full_name}` to link this version.
EOS EOS
elsif args.quiet?
msg = nil
end end
opoo msg opoo msg if msg
elsif f.migration_needed? && !args.force? elsif f.migration_needed? && !args.force?
# Check if the formula we try to install is the same as installed # Check if the formula we try to install is the same as installed
# but not migrated one. If --force is passed then install anyway. # but not migrated one. If --force is passed then install anyway.
@ -288,7 +298,7 @@ module Homebrew
Cleanup.install_formula_clean!(f) Cleanup.install_formula_clean!(f)
end end
Upgrade.check_installed_dependents(args: args) Upgrade.check_installed_dependents(installed_formulae, args: args)
Homebrew.messages.display_messages(display_times: args.display_times?) Homebrew.messages.display_messages(display_times: args.display_times?)
rescue FormulaUnreadableError, FormulaClassUnavailableError, rescue FormulaUnreadableError, FormulaClassUnavailableError,
@ -347,21 +357,28 @@ module Homebrew
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?, fi = FormulaInstaller.new(
include_test_formulae: args.include_test_formulae, f,
build_from_source_formulae: args.build_from_source_formulae, **{
debug: args.debug?, quiet: args.quiet?, verbose: args.verbose?) options: build_options.used_options,
fi.options = build_options.used_options build_bottle: args.build_bottle?,
fi.env = args.env force_bottle: args.force_bottle?,
fi.force = args.force? bottle_arch: args.bottle_arch,
fi.keep_tmp = args.keep_tmp? ignore_deps: args.ignore_dependencies?,
fi.ignore_deps = args.ignore_dependencies? only_deps: args.only_dependencies?,
fi.only_deps = args.only_dependencies? include_test_formulae: args.include_test_formulae,
fi.build_bottle = args.build_bottle? build_from_source_formulae: args.build_from_source_formulae,
fi.bottle_arch = args.bottle_arch env: args.env,
fi.interactive = args.interactive? cc: args.cc,
fi.git = args.git? git: args.git?,
fi.cc = args.cc interactive: args.interactive?,
keep_tmp: args.keep_tmp?,
force: args.force?,
debug: args.debug?,
quiet: args.quiet?,
verbose: args.verbose?,
}.compact,
)
fi.prelude fi.prelude
fi.fetch fi.fetch
fi.install fi.install

View File

@ -5,8 +5,11 @@ require "formula"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def leaves_args def leaves_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -7,8 +7,11 @@ require "cli/parser"
require "unlink" require "unlink"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def link_args def link_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -7,19 +7,22 @@ require "cli/parser"
require "cask/cmd" require "cask/cmd"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def list_args def list_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
`list`, `ls` [<options>] [<formula|cask>] `list`, `ls` [<options>] [<formula>|<cask>]
List all installed formulae or casks List all installed formulae and casks.
If <formula> is provided, summarise the paths within its current keg. If <formula> is provided, summarise the paths within its current keg.
EOS EOS
switch "--formula", "--formulae", switch "--formula", "--formulae",
description: "List only formulae. `This is the default action on non TTY.`" description: "List only formulae. This is the default when output is not to a terminal."
switch "--cask", "--casks", switch "--cask", "--casks",
description: "List only casks, or <cask> if provided." description: "List only casks, or <cask> if provided."
switch "--unbrewed", switch "--unbrewed",

View File

@ -5,8 +5,11 @@ require "formula"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def log_args def log_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
@ -25,8 +28,9 @@ module Homebrew
description: "Print only one commit." description: "Print only one commit."
flag "-n", "--max-count=", flag "-n", "--max-count=",
description: "Print only a specified number of commits." description: "Print only a specified number of commits."
max_named 1
conflicts "-1", "--max-count" conflicts "-1", "--max-count"
max_named 1
end end
end end

View File

@ -5,8 +5,11 @@ require "migrator"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def migrate_args def migrate_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -7,8 +7,11 @@ require "diagnostic"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def missing_args def missing_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -7,8 +7,11 @@ require "cli/parser"
require "commands" require "commands"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def options_args def options_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -8,8 +8,11 @@ require "cask/cmd"
require "cask/caskroom" require "cask/caskroom"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def outdated_args def outdated_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
@ -23,9 +26,9 @@ module Homebrew
switch "-v", "--verbose", switch "-v", "--verbose",
description: "Include detailed version information." description: "Include detailed version information."
switch "--formula", switch "--formula",
description: "Only output outdated formulae." description: "List only outdated formulae."
switch "--cask", switch "--cask",
description: "Only output outdated casks." description: "List only outdated casks."
flag "--json", flag "--json",
description: "Print output in JSON format. There are two versions: v1 and v2. " \ description: "Print output in JSON format. There are two versions: v1 and v2. " \
"v1 is deprecated and is currently the default if no version is specified. " \ "v1 is deprecated and is currently the default if no version is specified. " \

View File

@ -5,8 +5,11 @@ require "formula"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def pin_args def pin_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -6,8 +6,11 @@ require "formula_installer"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def postinstall_args def postinstall_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
@ -25,7 +28,7 @@ module Homebrew
args.named.to_resolved_formulae.each do |f| args.named.to_resolved_formulae.each do |f|
ohai "Postinstalling #{f}" ohai "Postinstalling #{f}"
fi = FormulaInstaller.new(f, debug: args.debug?, quiet: args.quiet?, verbose: args.verbose?) fi = FormulaInstaller.new(f, **{ debug: args.debug?, quiet: args.quiet?, verbose: args.verbose? }.compact)
fi.post_install fi.post_install
end end
end end

View File

@ -5,8 +5,11 @@ require "readall"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def readall_args def readall_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

View File

@ -14,8 +14,11 @@ require "cask/macos"
require "upgrade" require "upgrade"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def reinstall_args def reinstall_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
@ -42,8 +45,8 @@ module Homebrew
}], }],
[:switch, "-i", "--interactive", { [:switch, "-i", "--interactive", {
description: "Download and patch <formula>, then open a shell. This allows the user to " \ description: "Download and patch <formula>, then open a shell. This allows the user to " \
"run `./configure --help` and otherwise determine how to turn the software " \ "run `./configure --help` and otherwise determine how to turn the software " \
"package into a Homebrew package.", "package into a Homebrew package.",
}], }],
[:switch, "--force-bottle", { [:switch, "--force-bottle", {
description: "Install from a bottle if it exists for the current or newest version of " \ description: "Install from a bottle if it exists for the current or newest version of " \
@ -72,7 +75,6 @@ module Homebrew
cask_options cask_options
conflicts "--build-from-source", "--force-bottle" conflicts "--build-from-source", "--force-bottle"
min_named :formula_or_cask min_named :formula_or_cask
end end
end end
@ -100,7 +102,7 @@ module Homebrew
Cleanup.install_formula_clean!(f) Cleanup.install_formula_clean!(f)
end end
Upgrade.check_installed_dependents(args: args) Upgrade.check_installed_dependents(formulae, args: args)
if casks.any? if casks.any?
Cask::Cmd::Reinstall.reinstall_casks( Cask::Cmd::Reinstall.reinstall_casks(

View File

@ -8,6 +8,8 @@ require "cli/parser"
require "search" require "search"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
extend Search extend Search
@ -25,6 +27,7 @@ module Homebrew
}, },
}.freeze }.freeze
sig { returns(CLI::Parser) }
def search_args def search_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
@ -47,7 +50,7 @@ module Homebrew
description: "Search for formulae with a description matching <text> and casks with "\ description: "Search for formulae with a description matching <text> and casks with "\
"a name matching <text>." "a name matching <text>."
switch "--pull-request", switch "--pull-request",
description: "Search for GitHub pull requests for <text>." description: "Search for GitHub pull requests containing <text>."
package_manager_switches = PACKAGE_MANAGERS.keys.map { |name| "--#{name}" } package_manager_switches = PACKAGE_MANAGERS.keys.map { |name| "--#{name}" }
package_manager_switches.each do |s| package_manager_switches.each do |s|

View File

@ -6,8 +6,11 @@ require "keg"
require "cli/parser" require "cli/parser"
module Homebrew module Homebrew
extend T::Sig
module_function module_function
sig { returns(CLI::Parser) }
def switch_args def switch_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS

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